corsair 0.1.106 → 0.1.107

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.
@@ -1,4 +1,4 @@
1
- import { B as BrowserDeliveryPayload } from './index-CXNdPXR3.js';
1
+ import { B as BrowserDeliveryPayload } from './index-CdzrawUJ.js';
2
2
 
3
3
  /**
4
4
  * Browser (client) delivery — hub redirects the user's browser to the app with `?d=<token>`.
@@ -0,0 +1,38 @@
1
+ import{a as Nr,b as pe,c as $r,d as w,e as F,f as jr,g as N,h as H,i as S,j as hn,k as Wr,l as Kr,m as bt,n as qr,o as Zr}from"./chunk-BPFUYXOD.js";import{a as Lr}from"./chunk-IGGCNGU2.js";var bn=["agentql","algolia","ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","confluence","cursor","datadog","deepseek","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","gemini","github","gitlab","gmail","googlecalendar","googledocs","googledrive","googlemeet","googlesheets","grafana","hackernews","hubspot","insightoai","instagram","intercom","jira","linear","linkedin","mailchimp","monday","neon","notion","onedrive","openai","openweathermap","oura","outlook","pagerduty","perplexityai","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","supabase","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],Gr={agentql:"AgentQL",algolia:"Algolia",ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",confluence:"Confluence",cursor:"Cursor",datadog:"Datadog",deepseek:"DeepSeek",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",gemini:"Gemini",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledocs:"Google Docs",googledrive:"Google Drive",googlemeet:"Google Meet",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",insightoai:"Insighto.ai",instagram:"Instagram",intercom:"Intercom",jira:"Jira",linear:"Linear",linkedin:"LinkedIn",mailchimp:"Mailchimp",monday:"Monday",neon:"Neon",notion:"Notion",onedrive:"OneDrive",openai:"OpenAI",openweathermap:"OpenWeatherMap",oura:"Oura",outlook:"Outlook",pagerduty:"PagerDuty",posthog:"PostHog",razorpay:"Razorpay",reddit:"Reddit",resend:"Resend",sentry:"Sentry",sharepoint:"SharePoint",slack:"Slack",spotify:"Spotify",strava:"Strava",stripe:"Stripe",supabase:"Supabase",tally:"Tally",tavily:"Tavily",teams:"Teams",telegram:"Telegram",todoist:"Todoist",trello:"Trello",twilio:"Twilio",twitter:"Twitter",twitterapiio:"Twitter API IO",typeform:"Typeform",vapi:"Vapi",xquik:"XQuik",youtube:"YouTube",zendesk:"Zendesk",zohomail:"Zoho Mail",zoom:"Zoom",perplexityai:"Perplexity AI"};function ge(e){let n=Gr[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}import{randomUUID as Wi}from"crypto";var Ui="corsair:client-bridge";function kt(e){return new URL(e).origin}function Oe(e){let n=JSON.stringify({type:Ui,requestId:e.requestId,ok:e.ok,body:e.body??null,error:e.error??null}),t=JSON.stringify(kt(e.hubOrigin));return`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><script>
2
+ (function () {
3
+ var message = ${n};
4
+ var targetOrigin = ${t};
5
+ if (window.parent && window.parent !== window) {
6
+ window.parent.postMessage(message, targetOrigin);
7
+ }
8
+ })();
9
+ </script></body></html>`}var Bi=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Ct(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Bi.has(n)}catch{return!1}}function ze(e){return e==="development"?"browser":"server"}function Jr(e){return ze(e)==="browser"}function zr(e){return Ct(e)?"Production delivery URL must be a public URL, not localhost":null}import{randomBytes as ji}from"crypto";var Vr=new Set(["oauth.callback","oauth.tokens","webhook","permission.approve","permission.deny","auth.credentials","integration.credentials","connect.create_link","connections.sync"]),fe=60*1e3,Pe=300*1e3;import{createHmac as Li,randomBytes as Ni,timingSafeEqual as $i}from"crypto";function oe(){return Ni(16).toString("base64url")}function Ve(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Li("sha256",t).update(e).digest("base64url")}function Y(e,n){let t=n.trim();if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[o,i]=r;if(!o||!i)return null;let s=Ve(o,t);try{if(!$i(Buffer.from(i,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function kn(e,n,t){let r=Math.floor(Date.now()/1e3),o={...e,iat:r,exp:t},i=Buffer.from(JSON.stringify(o)).toString("base64url"),s=Ve(i,n);return`${i}.${s}`}function Ye(e,n,t){let r=Math.floor(Date.now()/1e3);return kn(e,n,r+Math.floor(t/1e3))}function Ae(e){return decodeURIComponent(e)}function wt(e){return encodeURIComponent(e)}function Yr(e){let n=e.trim();return n.length>0?n:null}function Me(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function He(e,n){if(!Yr(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??ji(16).toString("base64url"),iat:t,exp:t+Math.floor(fe/1e3)},o=Buffer.from(JSON.stringify(r)).toString("base64url"),i=Ve(o,n);return`${o}.${i}`}function ye(e,n){return Yr(n)?Y(e,n):null}function Ki(e){let n=kt(e.hubOrigin),t={connectJti:e.requestId,projectId:e.projectId,hubSuccessUrl:e.hubOrigin,deliveryMode:e.deliveryMode,hubOrigin:n,requestId:e.requestId};switch(e.deliveryMode){case"connections.sync":return{...t,plugin:"connections.sync",tenantId:"*"};case"connect.create_link":return{...t,plugin:"connect.create_link",tenantId:e.tenantId,connectLinkPlugins:e.plugins}}}function vt(e){let n=He(Ki(e),e.signingSecret);return Me(e.deliveryUrl,n)}function Qr(e){if(ze(e.environmentSlug)==="server")return{transport:"server"};if(!e.hubOrigin)throw new Error(`hubOrigin is required for development ${e.deliveryMode} delivery`);let t=Wi(),r={...e,hubOrigin:e.hubOrigin,requestId:t};return{transport:"browser",requestId:t,deliveryUrl:vt(r)}}var Qe="https://auth.corsair.dev";var ie=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret } to createCorsair()."),this.name="HubNotConfiguredError"}};function Cn(e){let n=(e.apiUrl?.trim()||Qe).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim();if(!t||!r)throw new Error("Hub config requires non-empty projectApiKey and signingSecret");return{apiUrl:n,projectApiKey:t,signingSecret:r,oauthCallbackUrl:e.oauthCallbackUrl?.trim().replace(/\/$/,"")}}function qi(e){return e.apiUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function M(e){let n=w(e).hub;if(!n||!qi(n))throw new ie;return n}function Xr(e){return e.replace(/\/$/,"")}function wn(e){return e.oauthCallbackUrl?Xr(e.oauthCallbackUrl.trim()):`${Xr(e.apiUrl)}/oauth/callback`}function Fe(e){if(e.startsWith("ck_dev_"))return"development";if(e.startsWith("ck_prod_"))return"production";throw new Error("Hub API key must start with ck_dev_ (development) or ck_prod_ (production)")}function I(e){return typeof e=="string"&&e.length>0}function Zi(e){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"}function Gi(e){return e==="oauth_2"||e==="api_key"||e==="bot_token"||e==="managed"}function vn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!I(n.connectUrl)||!I(n.token)||!I(n.projectId))throw new Error("Hub API returned an incomplete connect session (expected connectUrl, token, and projectId)");let t={connectUrl:n.connectUrl,token:n.token,projectId:n.projectId,environmentId:I(n.environmentId)?n.environmentId:n.projectId};return I(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function Tn(e){if(!Array.isArray(e))throw new Error("Hub API returned an invalid connections response (expected array)");let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;if(!I(r.tenantId)||!I(r.plugin)||!Zi(r.status)||!Gi(r.authType)||typeof r.connected!="boolean"||typeof r.verified!="boolean")continue;let o=Array.isArray(r.missingFields)?r.missingFields.filter(i=>typeof i=="string"):[];n.push({tenantId:r.tenantId,plugin:r.plugin,status:r.status,authType:r.authType,connected:r.connected,verified:r.verified,missingFields:o,reportedAt:I(r.reportedAt)?r.reportedAt:new Date().toISOString()})}return n}function Pn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!I(n.approvalUrl)||!I(n.token)||!I(n.projectId)||!I(n.expiresAt))throw new Error("Hub API returned an incomplete permission session (expected approvalUrl, token, projectId, and expiresAt)");return{approvalUrl:n.approvalUrl,token:n.token,projectId:n.projectId,expiresAt:n.expiresAt}}function An(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(I(n.access_token))return{access_token:n.access_token,refresh_token:I(n.refresh_token)?n.refresh_token:void 0,expires_in:(()=>{if(typeof n.expires_in=="number")return n.expires_in;if(typeof n.expires_in=="string"&&n.expires_in.trim().length>0){let t=Number(n.expires_in);return Number.isFinite(t)?t:void 0}})(),scope:I(n.scope)?n.scope:void 0};throw new Error(I(n.error)?I(n.error_description)?n.error_description:n.error:"Hub token refresh returned no access_token")}function Ji(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function zi(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;I(r.name)&&n.push({name:r.name,level:r.level==="integration"||r.level==="account"?r.level:"account",required:r.required===!0,configured:r.configured===!0})}return n}function Vi(e,n,t,r){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"?e:n?"ready":t.some(i=>i.level==="integration"&&i.required&&!i.configured)?"missing_integration":t.some(i=>i.level==="account"&&i.required&&i.configured)?"partial":(r.length>0,"not_started")}function eo(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!I(n.tenantId)||!Array.isArray(n.plugins))throw new Error("Connect status response was incomplete (expected tenantId and plugins)");let t=[];for(let r of n.plugins){if(!r||typeof r!="object")continue;let o=r;if(!I(o.plugin)||typeof o.connected!="boolean")continue;let i=o.authKind==="oauth"||o.authKind==="api_key"||o.authKind==="bot_token"?o.authKind:"api_key",s=zi(o.fields),a=Ji(o.missingRequiredFields),c=Vi(o.status,o.connected,s,a);t.push({plugin:o.plugin,providerName:I(o.providerName)?o.providerName:o.plugin,authKind:i,status:c,connected:o.connected,fields:s,missingRequiredFields:a})}return{tenantId:n.tenantId,plugins:t}}function xn(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}var Yi="3000",Qi="/api/corsair";function Xi(e){return e.replace(/\/$/,"")}function me(e){let n=e?.deliveryUrl?.trim()||process.env.CORSAIR_DELIVERY_URL?.trim();if(n){let r=/^https?:\/\//i.test(n)?n:`https://${n}`;return Xi(r)}return`http://localhost:${process.env.PORT?.trim()||Yi}${Qi}`}function no(e){return e.replace(/\/$/,"")}function Tt(e){if(!e.projectApiKey.startsWith("ck_dev_"))return null;try{return me()}catch{return null}}function to(e){let n=Tt(e);return n?{"x-corsair-delivery-url":n}:{}}async function ro(e){let n=e.headers.get("content-type")??"",t=await e.text();if(!t)return null;if(!n.includes("application/json")&&t.trimStart().startsWith("<"))throw new Error(`Hub API returned HTML instead of JSON (HTTP ${e.status}). Check HUB_API_URL and deploy the latest hub API.`);try{return JSON.parse(t)}catch{throw new Error(`Hub API returned invalid JSON (HTTP ${e.status})`)}}function oo(e,n,t){if(n===404&&t)return t;let r=xn(e);return r||`Hub API returned HTTP ${n}`}async function $(e){let n=no(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.hub.projectApiKey}`,...to(e.hub)},body:JSON.stringify(e.body)}),r=await ro(t);if(!t.ok)throw new Error(oo(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function In(e){let n=no(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`,...to(e.hub)}}),r=await ro(t);if(!t.ok)throw new Error(oo(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as io,createDecipheriv as so,randomBytes as Sn,scrypt as es}from"crypto";import{promisify as ns}from"util";var ao=ns(es),Rn="aes-256-gcm",co=12,_n=16,ts=16,Xe=32;function se(){return Sn(Xe).toString("base64")}async function ae(e,n){let t=Sn(ts),r=await ao(n,t,Xe),o=Sn(co),i=io(Rn,r,o,{authTagLength:_n}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[t.toString("base64"),o.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function K(e,n){let[t,r,o,i]=e.split(":");if(!t||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),l=Buffer.from(i,"base64"),u=await ao(n,s,Xe),p=so(Rn,u,a,{authTagLength:_n});return p.setAuthTag(c),Buffer.concat([p.update(l),p.final()]).toString("utf8")}function Pt(e,n){let t=Buffer.from(n,"base64"),r=Sn(co),o=io(Rn,t,r,{authTagLength:_n}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function en(e,n){let[t,r,o]=e.split(":");if(!t||!r||!o)throw new Error("Invalid encrypted data format");let i=Buffer.from(n,"base64"),s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),l=so(Rn,i,s,{authTagLength:_n});return l.setAuthTag(a),Buffer.concat([l.update(c),l.final()]).toString("utf8")}function he(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Pt(o,n);return t}function ce(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=en(o,n);return t}function nn(e,n,t){let r=ce(e,n);return he(r,t)}function uo(e,n,t){let r={};for(let o of t)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await n({[o]:s})};return r}var At=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function E(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,s=[...H[n].integration,...i],a=null,c={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let m=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!m)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:m.id,config:At(m.config),dek:m.dek??null},a},updateIntegration:async m=>{let h=await c.getIntegration();await o.db.updateTable("corsair_integrations").set({...m.config!==void 0?{config:m.config}:{},...m.dek!==void 0?{dek:m.dek}:{},updated_at:new Date}).where("id","=",h.id).execute(),a=null}},l=null,u=async()=>{if(l)return l;let m=await c.getIntegration();if(!m.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return l=await K(m.dek,r),l},p=async()=>{let m=await c.getIntegration(),h=await u(),b=m.config;return!b||Object.keys(b).length===0?{}:ce(b,h)},g=Promise.resolve(),d=m=>{let h=g.then(()=>y(m));return g=h.catch(()=>{}),h},y=async m=>{let h=await u(),b;try{b=await p()}catch(T){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,T),b={}}let v={...b};for(let[T,A]of Object.entries(m))A===null?delete v[T]:v[T]=A;let O=he(v,h);await c.updateIntegration({config:O})};return{get_dek:u,issue_new_dek:async()=>{let m=await c.getIntegration(),h=se(),b={};if(m.dek){let O=await K(m.dek,r),T=m.config;T&&Object.keys(T).length>0&&(b=nn(T,O,h))}let v=await ae(h,r);return await c.updateIntegration({config:b,dek:v}),l=h,h},...uo(p,d,s)}}function _(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:s=[],ensureProvisioned:a}=e,c=[...H[n].account,...s],l=null,u=null,p=async()=>{if(u)return u;let k=!1;for(;;){let C=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!C){if(!k&&a){k=!0,await a();continue}throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`)}return u={id:C.id,config:At(C.config),dek:C.dek??null},u}},g={kek:o,integrationName:t,tenantId:r,getIntegration:p,getAccount:async()=>{if(l)return l;let k=!1;for(;;){let C=await p(),P=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",C.id).executeTakeFirst();if(!P){if(!k&&a){k=!0,await a();continue}throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`)}return l={id:P.id,config:At(P.config),dek:P.dek??null},l}},updateAccount:async k=>{let C=await g.getAccount();await i.db.updateTable("corsair_accounts").set({...k.config!==void 0?{config:k.config}:{},...k.dek!==void 0?{dek:k.dek}:{},updated_at:new Date}).where("id","=",C.id).execute(),l=null}},d=null,y=null,f=async()=>{if(d)return d;let k=await g.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return d=await K(k.dek,o),d},m=async()=>{if(y)return y;let k=await g.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return y=await K(k.dek,o),y},h=async()=>{let k=await g.getAccount(),C=await f(),P=k.config;return!P||Object.keys(P).length===0?{}:ce(P,C)},b=async()=>{let k=await g.getIntegration(),C=await m(),P=k.config;return!P||Object.keys(P).length===0?{}:ce(P,C)},v=Promise.resolve(),O=k=>{let C=v.then(()=>T(k));return v=C.catch(()=>{}),C},T=async k=>{let C=await f(),P;try{P=await h()}catch(x){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,x),P={}}let L={...P};for(let[x,te]of Object.entries(k))te===null?delete L[x]:L[x]=te;let ne=he(L,C);await g.updateAccount({config:ne})},A={get_dek:f,issue_new_dek:async()=>{let k=await g.getAccount(),C=se(),P={};if(k.dek){let ne=await K(k.dek,o),x=k.config;x&&Object.keys(x).length>0&&(P=nn(x,ne,C))}let L=await ae(C,o);return await g.updateAccount({config:P,dek:L}),d=C,C},...uo(h,O,c)};return n==="oauth_2"&&(A.get_integration_credentials=async()=>{let k=await b();return{...k,client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),A}async function lo(e,n,t){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!r)throw new Error(`Integration "${n}" not found.`);let o=se(),i=await ae(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function po(e,n,t,r){let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!o)throw new Error(`Integration "${n}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",o.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let s=se(),a=await ae(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var rs=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function be(e){return rs.has(e)}function os(e,n){return be(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function is(e){return!be(e)}function ss(e){switch(e){case"oauth_2":case"managed":return["access_token","refresh_token"];case"api_key":return["api_key"];case"bot_token":return["bot_token"]}}function as(e,n){return ss(e).every(r=>n.find(i=>i.level==="account"&&i.name===r)?.configured??!1)}async function go(e,n){if(!e)return!1;let t=N(e,`get_${n}`);if(!t)return!1;try{let r=await t();return typeof r=="string"&&r.length>0}catch{return!1}}function cs(e,n){let r=e.authConfig?.[n]?.integration??[];return[...H[n].integration,...r]}function us(e,n){let r=e.authConfig?.[n]?.account??[];return[...H[n].account,...r]}function ls(e,n,t){let r=t.filter(a=>a.required&&!a.configured).map(a=>a.name),o=t.filter(a=>a.level==="integration"&&a.required&&!a.configured).map(a=>a.name),i=t.filter(a=>a.level==="account"&&a.required&&a.configured),s;return o.length>0?s="missing_integration":r.length===0?s="ready":i.length>0?s="partial":s="not_started",{plugin:e,authType:n,status:s,connected:as(n,t),fields:t,missingRequiredFields:r}}async function xe(e,n,t){let r=S(n);if(!r||!e.database||!e.kek)return null;let o=t.trim()||"default",i=n.authConfig,s=i?.[r]?.integration??[],a=i?.[r]?.account??[],c=E({authType:r,integrationName:n.id,kek:e.kek,database:e.database,extraIntegrationFields:s}),l=_({authType:r,integrationName:n.id,tenantId:o,kek:e.kek,database:e.database,extraAccountFields:a}),u=cs(n,r),p=us(n,r),g=[];for(let d of u)g.push({name:d,level:"integration",required:os(r,d),configured:await go(c,d)});for(let d of p)g.push({name:d,level:"account",required:is(d),configured:await go(l,d)});return ls(n.id,r,g)}async function tn(e,n,t={}){let r=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,i=[];for(let s of e.plugins){if(o&&!o.has(s.id))continue;let a=await xe(e,s,r);a&&i.push(a)}return i}function En(e){return e.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}var fo=Symbol.for("corsair:internal"),yo=new WeakMap;function ds(e){let n=yo.get(e);return n||(n=new Map,yo.set(e,n)),n}function ps(e){return e.multiTenancy?{withTenant:()=>({}),[fo]:e}:{[fo]:e}}async function Dn(e,n){if(!e.database)return;let t=n.trim()||"default",r=ds(e),o=t,i=r.get(o);if(i){await i;return}let s=(async()=>{let{setupCorsair:a}=await import("./setup-W2M2D2FG.js");await a(ps(e),{tenantId:e.multiTenancy?t:void 0,silent:!0})})().finally(()=>{r.delete(o)});r.set(o,s),await s}import{ZodBoolean as fs,ZodDate as ys,ZodEnum as ms,ZodNullable as hs,ZodNumber as bs,ZodObject as ks,ZodOptional as Cs,ZodRecord as ws,ZodString as vs,ZodType as Ts}from"zod";var gs={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},repositories:{list:{}}},discord:{guilds:{list:{}},channels:{list:{}}},hubspot:{contacts:{getMany:{}},companies:{getMany:{}},deals:{getMany:{}}},gmail:{messages:{list:{}},labels:{list:{}},drafts:{list:{}},threads:{list:{}}},googlecalendar:{events:{getMany:{}}},googlemeet:{conferenceRecords:{list:{}}},googledrive:{files:{list:{}},folders:{list:{}},sharedDrives:{list:{}}},notion:{databases:{getManyDatabases:{}},databasePages:{getManyDatabasePages:{}},users:{getManyUsers:{}}},airtable:{bases:{getMany:{}}},todoist:{projects:{getMany:{}},tasks:{getMany:{}}},cal:{bookings:{list:{}}},zohomail:{folders:{list:{}},messages:{list:{}}}},xt=gs;async function Mn(e,n){let t=[],r=n?.silent??!1,o=d=>{t.push(d),r||console.log(d)},i=d=>{t.push(d),r||console.warn(d)},s=n?.caller??"script",a=$r(e);if(!a)throw new Error("setupCorsair: invalid corsair instance");if(!a.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let c=As(e,a.plugins,n),l={...a,database:a.database},u=l.database.db;await Ss(u,i);let p=await Rs(u,l,c.tenantId,c.provisionAccounts,o);n?.credentials&&Object.keys(n.credentials).length>0&&await Ds(e,c,n.credentials,l,o,i);let g=await Ms(p,c,o,s);if(n?.backfill){o("[corsair:setup] Starting backfill...");let d=bo({plugins:a.plugins,database:u,kek:a.kek,multiTenancy:!0}).withTenant(c.tenantId);await Hs(d,a.plugins,g,o,i),o("[corsair:setup] Backfill complete.")}return t.join(`
10
+ `)}function It(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...H[n][t],...r])}function Ps(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let o=n.find(a=>a.id===t);if(!o)continue;let i=S(o);if(!i)continue;let s=It(o,i,"account");for(let a of Object.keys(r))if(s.has(a))return!0}return!1}function As(e,n,t){let r=jr(e),o=t?.tenantId?.trim(),i=o!==void 0&&o.length>0;if(r&&t?.backfill&&!i)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(r&&Ps(t?.credentials,n)&&!i)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(i&&!o)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:r,tenantIdProvided:i,tenantId:i?o:"default",provisionAccounts:!r||i}}function ho(e,n){return pe(e)?n===0?!0:Object.values(e).every(t=>ho(t,n-1)):!1}function xs(e){return ho(e,4)}var Is={...qr};function On(e){if(e instanceof ks){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Ts?On(r):"unknown";return n}return e instanceof hs?`${On(e.unwrap())} | null`:e instanceof Cs?`${On(e.unwrap())} | undefined`:e instanceof ms?e.options.join(" | "):e instanceof vs?"string":e instanceof bs?"number":e instanceof fs?"boolean":e instanceof ys?"date":e instanceof ws?"jsonb":"unknown"}async function Ss(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(o=>o.name));for(let[o,i]of Object.entries(Is))r.has(o)||n(`[corsair:setup] Table "${o}" does not exist. Run your database migrations before calling setupCorsair.
11
+ Schema: ${JSON.stringify(On(i),null,2)}`)}async function Rs(e,n,t,r,o){let i=new Date,s=new Map;for(let a of n.plugins){let c=a.id,l=S(a),u=await e.selectFrom("corsair_integrations").selectAll().where("name","=",c).executeTakeFirst();if(!u){let f=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:f,name:c,config:{},created_at:i,updated_at:i}).execute(),u=await e.selectFrom("corsair_integrations").selectAll().where("id","=",f).executeTakeFirst(),o(`[corsair:setup] Created integration: ${c}`)}let p=l?a.authConfig?.[l]?.integration??[]:[],g=l?a.authConfig?.[l]?.account??[]:[],d=l&&u?E({authType:l,integrationName:c,kek:n.kek,database:n.database,extraIntegrationFields:p}):void 0;if(u&&!u.dek&&d&&(await d.issue_new_dek(),o(`[corsair:setup] Issued integration DEK: ${c}`)),!u||!l||!d)continue;let y;if(r){let f=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",u.id).executeTakeFirst();if(!f){let m=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:m,tenant_id:t,integration_id:u.id,config:{},created_at:i,updated_at:i}).execute(),f=await e.selectFrom("corsair_accounts").selectAll().where("id","=",m).executeTakeFirst(),o(`[corsair:setup] Created account: ${c}`)}y=f&&_({authType:l,integrationName:c,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),f&&y&&!f.dek&&(await y.issue_new_dek(),o(`[corsair:setup] Issued account DEK: ${c}`))}s.set(c,{pluginId:c,authType:l,integration:d,account:y,integrationFields:[...H[l].integration,...p],accountFields:r?[...H[l].account,...g]:[]})}return s}function _s(e){if(!pe(e))return;let n=e.keys;return pe(n)?n:void 0}function Es(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function Ds(e,n,t,r,o,i){let s=_s(e),a=n.provisionAccounts?Es(e,n.tenantId):void 0;for(let[c,l]of Object.entries(t)){let u=r.plugins.find(h=>h.id===c);if(!u){i(`[corsair:setup] Unknown plugin '${c}' \u2014 skipping credentials.`);continue}let p=S(u);if(!p){i(`[corsair:setup] Plugin '${c}' has no auth type \u2014 skipping credentials.`);continue}let g=It(u,p,"integration"),d=It(u,p,"account"),y=s?.[c],f=a?.[c],m=pe(f)?f.keys:void 0;for(let[h,b]of Object.entries(l))if(b){if(g.has(h)){if(n.multiTenant&&n.tenantIdProvided)throw new Error(`[corsair:setup] '${c}.${h}' is an integration-level credential shared across all tenants. You passed tenantId="${n.tenantId}", which only scopes account-level credentials. Run setup without --tenant if you intend to change this credential globally.`);let v=N(y,`set_${h}`);if(!v){i(`[corsair:setup] Cannot set integration field '${h}' for '${c}'.`);continue}await v(b),o(`[corsair:setup] Set ${c} integration.${h}`);continue}if(d.has(h)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${c}.${h}' on a multi-tenant instance`);let v=N(m,`set_${h}`);if(!v){i(`[corsair:setup] Cannot set account field '${h}' for '${c}'.`);continue}await v(b),o(`[corsair:setup] Set ${c} account.${h} (tenant=${n.tenantId})`);continue}i(`[corsair:setup] Unknown credential field '${h}' for plugin '${c}'.`)}}}var mo=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function Os(e,n,t,r,o,i,s,a,c){let l=[],u=[];for(let g of o){if(mo.has(g))continue;let d=N(t,`get_${g}`);if(!d)continue;let y=null;try{let f=await d();y=typeof f=="string"?f:null}catch{}y||l.push(g)}if(r&&i.length>0)for(let g of i){if(mo.has(g))continue;let d=N(r,`get_${g}`);if(!d)continue;let y=null;try{let f=await d();y=typeof f=="string"?f:null}catch{}y||u.push(g)}let p=l.length===0&&u.length===0;if(p)a(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else if(n==="managed")a(`[corsair:setup] '${e}' (managed) is not connected yet. Use Connect in your app \u2014 Corsair Hub delivers OAuth tokens after authorization.`);else{let g=[...l,...u];if(c==="cli"){let d=g.map(y=>`${y}=VALUE`).join(" ");a(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
12
+ corsair setup --${e} ${d}`)}else{let d=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let y of l)d.push(` await corsair.keys.${e}.set_${y}(value)`);for(let y of u){let f=s.provisionAccounts?s.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(s.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;d.push(` await ${f}.keys.set_${y}(value)`)}a(d.join(`
13
+ `))}}return p}async function Ms(e,n,t,r){let o=new Set;for(let i of e.values())await Os(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function Hs(e,n,t,r,o){if(!xs(xt)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=xt,s=new Set(n.map(a=>a.id));for(let[a,c]of Object.entries(i)){if(!s.has(a))continue;if(!t.has(a)){r(`[corsair:setup] Skipping backfill for '${a}' \u2014 auth not configured.`);continue}let l=pe(e)?e[a]:void 0,u=pe(l)?l.api:void 0;if(u)for(let[p,g]of Object.entries(c))for(let[d,y]of Object.entries(g)){r(`[corsair:setup] Backfilling ${a} \u203A ${p}.${d}...`);try{let f=pe(u)?u[p]:void 0;await N(f,d)?.(y)}catch(f){o(`[corsair:setup] ${a} \u203A ${p}.${d} failed: `+(f instanceof Error?f.message:String(f)))}}}}async function ko(e){if(!w(e).database)throw new Error("A database must be configured to provision Corsair integrations");await Mn(e,{silent:!0})}async function Ie(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to provision Corsair for connect");await Dn(t,n)}var Fs=Symbol.for("corsair:internal"),Us=new Set(["access_token","refresh_token","expires_at","scope"]);function Bs(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Ls(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!be(t)&&!Us.has(t)):n.filter(t=>!be(t))}function Co(e){return{plugins:e.plugins,database:e.database,kek:e.kek,multiTenancy:!1}}function wo(e){return{[Fs]:Co(e)}}async function Hn(e,n,t={}){let r=wn(e.hub),o=[],i=t.pluginIds?new Set(t.pluginIds):null,s=Co(e),a=wo(e);for(let c of e.plugins){if(i&&!i.has(c.id))continue;let l=S(c);if(!l)continue;let u=Bs(l),p=t.providerNameOverrides?.[c.id]??ge(c.id),g=await xe(s,c,n),d=hn(c,l),y=Ls(l,d),f={plugin:c.id,providerName:p,authKind:u,alreadyConfigured:g?.connected??!1};if(y.length>0&&(f.credentialFields=y),u==="oauth"){let h=t.oauthModeOverrides?.[c.id]??(l==="managed"?"managed":"byo");if(f.oauthMode=h,!t.skipOAuthUrlGeneration&&h!=="managed")try{let b=await St(a,c.id,{tenantId:n,redirectUri:r,hubConnect:!0});f.oauthUrl=b.url}catch(b){f.setupError=b instanceof Error?b.message:`Could not prepare OAuth for ${c.id}`}}o.push(f)}return o}async function Su(e,n,t={}){let r=w(e),o=r.hub;if(!o)throw new Error("Hub is not configured");return Hn({plugins:r.plugins,database:r.database,kek:r.kek,hub:o},n,t)}async function Rt(e,n){if(!e.database)throw new Error("A database must be configured to provision Corsair for connect");await Ie(wo(e),n)}async function Ru(e,n){await Ie(e,n)}async function vo(e,n){let t=Fe(e.projectApiKey),r={tenantId:n.tenantId,plugins:n.plugins};return t==="development"&&(r.deliveryUrl=me({deliveryUrl:n.deliveryUrl})),$({hub:e,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:vn})}async function _t(e,n){let t={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await Rt(t,n.tenantId);let r=await Hn(t,n.tenantId,{pluginIds:[n.plugin.id]});if(r.length===0)throw new Error(`Plugin '${n.plugin.id}' is not configured on this Corsair instance`);return vo(e,{tenantId:n.tenantId,plugins:r,deliveryUrl:n.deliveryUrl})}async function Fn(e,n){let t=w(e),r=M(e),o={plugins:t.plugins,database:t.database,kek:t.kek,hub:r};await Rt(o,n.tenantId);let i=n.plugin?[n.plugin]:void 0,s=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,a=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,c=await Hn(o,n.tenantId,{pluginIds:i,oauthModeOverrides:s,providerNameOverrides:a});if(c.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is not configured on this Corsair instance`:"No plugins are configured on this Corsair instance");return vo(r,{tenantId:n.tenantId,plugins:c,deliveryUrl:n.deliveryUrl})}function To(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Ns(e,n){return n&&!n.has(e.id)?!1:S(e)!==null}async function Po(e,n,t={}){let r=w(e),o=n.trim()||"default",i=t.pluginIds?.length?new Set(t.pluginIds):null,s=await tn(r,o,{pluginIds:t.pluginIds}),a=new Map(s.map(l=>[l.plugin,l])),c=r.plugins.filter(l=>Ns(l,i)).map(l=>{let u=S(l),p=a.get(l.id);return p?{plugin:l.id,providerName:ge(l.id),authKind:To(u),status:p.status,connected:p.connected,fields:p.fields.map(g=>({name:g.name,level:g.level,required:g.required,configured:g.configured})),missingRequiredFields:p.missingRequiredFields}:{plugin:l.id,providerName:ge(l.id),authKind:To(u),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:o,plugins:c}}async function Ao(e,n){let t=M(e);return In({hub:t,path:`/projects/${encodeURIComponent(n.projectId)}/connections`,notFoundMessage:"Hub REST API not found at /projects/:id/connections. Check HUB_API_URL and ensure the Hub API is deployed.",parseResponse:Tn})}import*as rn from"crypto";function ke(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function Et(e,{maxAgeMs:n}={}){try{let t=e.includes(".")?e.split(".")[0]:e,r=JSON.parse(Buffer.from(t,"base64url").toString("utf-8"));if(r!==null&&typeof r=="object"&&"plugin"in r&&"tenantId"in r&&typeof r.plugin=="string"&&typeof r.tenantId=="string"){let o=r;return n!==void 0&&typeof o.iat=="number"&&Date.now()-o.iat>n?null:o}return null}catch{return null}}function Ue(e,n){let t=rn.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var Dt=600*1e3;function Un(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),o=e.slice(t+1),i=rn.createHmac("sha256",n).update(r).digest("base64url"),s=Buffer.from(o,"base64url"),a=Buffer.from(i,"base64url");return s.length!==a.length||!rn.timingSafeEqual(s,a)?null:Et(r,{maxAgeMs:Dt})}function Be(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}import*as xo from"querystring";function Se(e){let{oauthConfig:n,clientId:t,redirectUri:r,state:o}=e,i={...n.authParams,client_id:t,redirect_uri:r,response_type:"code",scope:n.scopes.join(" "),state:o};return`${n.authUrl}?${xo.stringify(i)}`}var q=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function $s(e){let n=e.oauthConfig;if(!n)throw new q("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Ot(e,n){let t=w(e,()=>new q("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new q("no_database","No database configured on corsair instance");let r=t.manual?.redirectUri;if(!r)throw new q("no_redirect_uri","No redirectUri configured. Set manual.redirectUri in createCorsair().");let o=Un(n,t.kek);if(!o)throw new q("invalid_state","Invalid or tampered state parameter");let{plugin:i,tenantId:s}=o,a=F(t,i,g=>new q("plugin_not_found",g)),c=$s(a),u=await E({authType:"oauth_2",integrationName:i,kek:t.kek,database:t.database}).get_client_id();if(!u)throw new q("client_id_not_configured",`client_id not configured for '${i}'`);let p=Se({oauthConfig:c,clientId:u,redirectUri:r,state:n});return{plugin:i,tenantId:s,providerName:c.providerName,oauthUrl:p,state:n}}import{AsyncLocalStorage as Ws}from"async_hooks";import{randomBytes as Ks}from"crypto";import{v4 as qs}from"uuid";async function Bn(e,n){let t=Fe(e.projectApiKey),r={permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,expiresAt:n.expiresAt};return t==="development"&&(r.deliveryUrl=me({deliveryUrl:n.deliveryUrl})),$({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:Pn})}function Ln(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var Mt="Permission approval required. Set manual.approvalBaseUrl (or use hub for hosted approval) so an approval URL can be generated. Optionally set manual.onApprovalRequired to customize the agent message.";function Ft(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function Io(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Ht(e){return Ln(e)}async function Ut(e,n){if(Ft(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?Io(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await Bn(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:js(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function js(e){try{return JSON.parse(e)}catch{return e}}async function Nn(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await Ut(e,n);return{...n,approvalUrl:r}}async function Bt(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:o,permissionToken:i,plugin:s,endpoint:a,args:c,tenantId:l,expiresAt:u,operationPath:p}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:i,id:o,plugin:s,endpoint:a,args:c});let d=await Ut({manual:t,hub:r},{id:o,token:i,plugin:s,endpoint:a,args:JSON.stringify(c),tenant_id:l,expires_at:u});return Ft(t)?d?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:d}):Ht(d):Mt:r?d?Ht(d):`Action '${p}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Mt}var Ro=new Ws,$n=class extends Error{endpointPath;riskLevel;constructor(n,t){super(`Action '${n}' is a '${t}' operation and is forbidden in readonly mode. Only read operations are permitted \u2014 rewrite the script to avoid write/destructive actions.`),this.name="ReadonlyForbiddenError",this.endpointPath=n,this.riskLevel=t}};function Zs(e){return Ro.run(!0,e)}function _o(){return Ro.getStore()===!0}function Lt(e,n){if(_o()&&n!=="read")throw new $n(e,n)}var Gs={open:{read:"allow",write:"allow",destructive:"allow"},cautious:{read:"allow",write:"allow",destructive:"require_approval"},strict:{read:"allow",write:"require_approval",destructive:"deny"},readonly:{read:"allow",write:"deny",destructive:"deny"}};function Js(e,n,t){return t!==void 0?t:Gs[n][e]}function Nt(e){let n=/(\d+)(d|h|m|s)/g,t=0,r;for(;(r=n.exec(e))!==null;){let o=parseInt(r[1],10);switch(r[2]){case"d":t+=o*864e5;break;case"h":t+=o*36e5;break;case"m":t+=o*6e4;break;case"s":t+=o*1e3;break}}return t>0?t:600*1e3}function Eo(e){return{async find_by_permission_id(n){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst()},async find_by_token(n){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst()},async set_executing(n){e&&await e.db.updateTable("corsair_permissions").set({status:"executing",updated_at:new Date}).where("id","=",n).execute()},async set_completed(n){e&&await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}}}async function So(e,n,t){let r=Date.now()+t;for(;Date.now()<r;){let o=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!o)return{result:"blocked",reason:"pending"};if(o.status==="approved")return{result:"allow",onComplete:async()=>{await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}};if(o.status==="denied")return{result:"blocked",reason:"denied"};if(o.status==="expired"||o.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(i=>setTimeout(i,500))}return{result:"blocked",reason:"timeout"}}async function Do(e){let n=Js(e.riskLevel,e.mode,e.override);if(n==="allow")return{result:"allow"};let t=e.meta?.irreversible?" (irreversible)":"",r=e.meta?.description?`${e.meta.description}${t}`:`${e.pluginId}.${e.endpointPath}${t}`;if(n==="deny"||!e.db)return console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 denied by permission mode '${e.mode}'.`,`
14
+ Action: ${r}`,`
15
+ To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let o=JSON.stringify(e.args),i=new Date().toISOString(),s=e.tenantId??"default",a=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",o).where("tenant_id","=",s).where("expires_at",">",i).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(a){if(a.status==="approved"){let y=e.db,f=a.id;return{result:"allow",onComplete:async()=>{await y.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",f).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
16
+ Action: ${r}`,`
17
+ Permission ID: ${a.id}`,`
18
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?So(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:a.id,token:a.token,expiresAt:a.expires_at})}let c=qs(),l=Ks(32).toString("hex"),u=e.timeoutMs??600*1e3,p=new Date(Date.now()+u).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:c,created_at:new Date,updated_at:new Date,token:l,plugin:e.pluginId,endpoint:e.endpointPath,args:o,tenant_id:s,status:"pending",expires_at:p}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
19
+ Action: ${r}`,`
20
+ Permission ID: ${c}`,`
21
+ Permission token: ${l}`,`
22
+ Expires at: ${p}`,`
23
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?So(e.db,c,u):{result:"blocked",reason:"pending",id:c,token:l,expiresAt:p}}var R=class extends Error{status;code;extra;constructor(n,t,r,o={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=o}};function D(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function Oo(e){let n={error:e.code,message:e.message,...e.extra};return D(e.status,n)}function Ce(e){return new R(404,"not_found",e)}function ue(e,n={}){return new R(400,"bad_request",e,n)}function Mo(e,n){return F(e,n,t=>Ce(t))}async function Ho(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=E({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),o=H[t].integration,i=r,s;try{s=await Promise.all(o.map(l=>i[`get_${l}`]()))}catch{s=o.map(()=>null)}let a=o.filter((l,u)=>s[u]==null),c;return t==="oauth_2"?c=!a.includes("client_id")&&!a.includes("client_secret"):c=a.length===0,{configured:c,missingFields:a}}async function Fo(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:o,missingFields:i}=await Ho(e,n);return{id:e.id,authType:t,configured:o,missingFields:i,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function jn(){return{ok:!0}}async function Le(e){return Promise.all(e.plugins.map(n=>Fo(n,e)))}async function Wn(e,n){let t=Mo(e,n);return Fo(t,e)}async function zs(e,n){return e.database?(await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.id as accountId","a.dek as dek","i.name as integrationName"]).where("a.tenant_id","=",n).execute()).map(r=>({integrationName:r.integrationName,hasCredentials:!!r.dek})):[]}async function Uo(e,n){let t=await zs(e,n),r=t.filter(o=>o.hasCredentials).map(o=>o.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function Ne(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let o=r.tenant_id;if(!o)continue;let i=n.get(o);i||(i={id:o,accounts:[],connectedPlugins:[]},n.set(o,i));let s=!!r.dek;i.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&i.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function Kn(e,n){if(!n)throw ue("Tenant id must be a non-empty string");return Uo(e,n)}async function qn(e,n){let t=n?.id?.trim();if(!t)throw ue("Tenant id is required",{missingFields:["id"]});return Uo(e,t)}async function Zn(e,n){let t=n?.trim()||"default",r={},o=await tn(e,t);for(let i of o)r[i.plugin]=En(i);for(let i of e.plugins)i.id in r||(!i.options?.authType||!e.database||!e.kek?r[i.id]="missing_credentials":r[i.id]="not_connected");return r}async function $t(e,n){if(!e.database)throw Ce(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw Ce(`Permission '${n}' not found`);return Nn(e,t)}function Vs(e){if(!e.oauthConfig)throw ue(`Plugin '${e.id}' has no oauthConfig`)}function Ys(e){if(!e.manual)throw new R(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function jt(e){let n=Ys(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new R(500,"connect_not_configured","Manual connect requires manual.baseUrl and manual.redirectUri. Use hub for hosted connect, or set both URLs for manual OAuth.");return n}function Qs(e){let n=!!e.hub,t=Be(e.manual);if(!n&&!t)throw new R(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function Bo(e){if(!e.database||!e.kek)throw new R(500,"database_not_configured","A database and kek are required to issue connect links.")}async function Xs(e,n){let t=n?.plugin?.trim();if(!t)throw ue("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",o=Mo(e,t);Vs(o);let i=jt(e);Bo(e);let s=await Ho(o,e);if(!s.configured)throw new R(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:s.missingFields});let a=Ue(ke(t,r),e.kek),c;try{c=new URL(i.baseUrl)}catch{throw new R(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return c.searchParams.set("state",a),{connectUrl:c.toString(),expiresAt:new Date(Date.now()+Dt).toISOString()}}async function ea(e,n,t){Bo(n);let o={tenantId:t.tenantId?.trim()||"default",oauthMode:t.oauthMode},i=t.plugin?.trim();i&&(o.plugin=i);let s=t.providerName?.trim();s&&(o.providerName=s);let a=await Fn(e,o);return{connectUrl:a.connectUrl,expiresAt:a.expiresAt}}async function Gn(e,n,t){return Qs(n),n.hub?ea(e,n,t):Xs(n,t)}async function Jn(e,n,t){if(n.hub&&!Be(n.manual))throw new R(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw ue("state is required",{missingFields:["state"]});jt(n);try{return await Ot(e,r)}catch(o){if(o instanceof q)switch(o.code){case"invalid_state":throw ue("Invalid or expired state");case"client_id_not_configured":throw new R(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new R(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function zn(e,n,t){if(n.hub&&!Be(n.manual))throw new R(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),o=t?.state?.trim(),i=[];if(r||i.push("code"),o||i.push("state"),i.length)throw ue("Missing required fields",{missingFields:i});let s=jt(n),{processOAuthCallback:a}=await import("./oauth.js");try{return await a(e,{code:r,state:o,redirectUri:s.redirectUri})}catch(c){if(c instanceof Error&&c.name==="OAuthCallbackError")switch(c.code){case"invalid_state":throw ue("Invalid or expired state");case"credentials_not_configured":throw new R(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new R(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function Wt(e,n){if(!e.database)throw Ce("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw Ce("Permission not found");return Nn(e,t)}async function Lo(e,n){return"id"in n?$t(e,n.id):Wt(e,n.token)}import{createCipheriv as aa,createDecipheriv as Rl,randomBytes as Wo,scryptSync as ca}from"crypto";import{createHmac as Kt,randomUUID as na,timingSafeEqual as $o}from"crypto";function jo(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Vn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=Kt("sha256",e.signingSecret.trim()).update(n).digest("hex");return{body:n,headers:{"content-type":"application/json","x-corsair-signature":`sha256=${r}`,"x-corsair-timestamp":t,"x-corsair-project":e.projectId,"x-corsair-nonce":na()}}}function qt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=jo(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>Pe)return!1;let i=Kt("sha256",n).update(e.body).digest("hex");try{return $o(Buffer.from(i,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function $e(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=jo(e.signatureHeader);if(!t)return{ok:!1,error:"Invalid tunnel signature"};let r=Number(e.timestampHeader);if(!Number.isFinite(r))return{ok:!1,error:"Invalid or missing tunnel timestamp"};if(Math.abs(Date.now()-r*1e3)>Pe)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let i=Kt("sha256",n).update(e.body).digest("hex");try{if(!$o(Buffer.from(i,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function je(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function Yn(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function Qn(e){let n=e.sync?.encrypted;return typeof n!="string"||!n.trim()?null:{encrypted:n.trim()}}function on(e){let n=e.connectUrl?.trim();return n?{connectUrl:n,expiresAt:e.expiresAt}:null}function Zt(e){return on(je(e))}async function Gt(e){let n=await nt({deliveryUrl:e.deliveryUrl,projectId:e.projectId,signingSecret:e.signingSecret,type:"connect.create_link",payload:{tenantId:e.tenantId,plugins:e.plugins}}),t=je(n.body),r=Yn({httpOk:n.ok,status:n.status,body:t}),o=on(t);if(!r||!o)throw new Error(et({deliveryUrl:e.deliveryUrl,status:n.status,body:n.body,ack:t}));return o}function Xn(e){return Qn(je(e))}function ta(e){let n=e;for(;n;){if(n instanceof Error){let t=n.code;if(typeof t=="string")return t;n=n.cause;continue}if(typeof n=="object"&&n!==null&&"code"in n){let t=n.code;if(typeof t=="string")return t}break}}function No(e,n=200){let t=e.trim();return t.length<=n?t:`${t.slice(0,n)}\u2026`}var ra="Verify hub.signingSecret in your app matches the signing secret shown in Hub project settings.",oa="Check the delivery URL configured for this environment.";function ia(e){return`${e.ack.error?`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`:`App rejected the signed delivery (HTTP ${e.status} from ${e.deliveryUrl})`}. ${ra}`}function sa(e){return`${e.ack.error?`${e.ack.error} (HTTP 404 from ${e.deliveryUrl})`:`Delivery endpoint not found at ${e.deliveryUrl} (HTTP 404)`}. ${oa}`}function sn(e,n){let t=ta(n),r=n instanceof Error?n.message:"Delivery request failed",o;switch(t){case"ECONNREFUSED":o="connection refused \u2014 nothing accepted a TCP connection on that host and port";break;case"ENOTFOUND":o="host not found \u2014 DNS could not resolve the hostname";break;case"ETIMEDOUT":case"UND_ERR_CONNECT_TIMEOUT":o="connection timed out before the app responded";break;case"ECONNRESET":o="connection reset while talking to the app";break;case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":o=`TLS certificate error (${t})`;break;default:o=r==="fetch failed"&&t?`${r} (${t})`:r}return[`Could not reach ${e}`,o].join(". ")}function et(e){if(e.status===0)return e.ack.error?e.ack.error:e.body.startsWith("Could not reach")?e.body:sn(e.deliveryUrl,new Error(e.body||"Delivery request failed"));if(e.status===401||e.status===403)return ia(e);if(e.status===404)return sa(e);if(e.ack.error)return`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`;if(e.status>=500){let t=e.body.trim();return t?`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl}): ${No(t)}`:`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl})`}let n=e.body.trim();return n?`${No(n)} (HTTP ${e.status} from ${e.deliveryUrl})`:`Delivery failed with HTTP ${e.status} from ${e.deliveryUrl}`}async function nt(e){let{body:n,headers:t}=Vn(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),o=await r.text();return{ok:r.ok,status:r.status,body:o}}catch(r){return{ok:!1,status:0,body:sn(e.deliveryUrl,r)}}}var ua="aes-256-gcm",la=12,da=16,pa=16,ga=32;function fa(e,n){return ca(e.trim(),n,ga)}function Jt(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required to encrypt sync manifest");let r=Wo(pa),o=fa(t,r),i=Wo(la),s=aa(ua,o,i,{authTagLength:da}),a=JSON.stringify(e),c=Buffer.concat([s.update(a,"utf8"),s.final()]),l=s.getAuthTag();return[r.toString("base64"),i.toString("base64"),l.toString("base64"),c.toString("base64")].join(":")}var ya=["invalid corsair instance","a database must be configured to sync connections from the app","a database must be configured on the corsair instance","signing secret is required to encrypt sync manifest"];function zt(e){if(e instanceof Nr)return!1;if(!(e instanceof Error))return!0;let n=e.message.toLowerCase();return!ya.some(t=>n.includes(t))}function ma(e){if(!e)return[];let n=S(e);return n?(e.authConfig?.[n]?.integration??[]).filter(r=>!be(r)):[]}async function an(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to sync connections from the app");await Mn(e,{silent:!0});let[r,o]=await Promise.all([Ne(t),Le(t)]),i={tenants:r.map(s=>({id:s.id})),plugins:o.map(s=>{let a=ma(t.plugins.find(c=>c.id===s.id));return{id:s.id,authType:s.authType,configured:s.configured,missingFields:s.missingFields,...a.length>0?{integrationCredentialFields:a}:{}}}),syncedAt:new Date().toISOString()};return Jt(i,n)}async function tt(e,n){let t=n.tenantId.trim();if(!t)throw new Error("tenantId is required");let r=n.plugins.map(s=>s.trim()).filter(Boolean);if(r.length===0)throw new Error("At least one plugin is required");let o=w(e);if(!o.hub)throw new Error("Hub is not configured on this Corsair instance");if(!o.database)throw new Error("Database not configured");let i=await ha(o.hub,{plugins:o.plugins,database:o.database,kek:o.kek},{tenantId:t,pluginIds:r});return{connectUrl:i.connectUrl,expiresAt:i.expiresAt}}async function ha(e,n,t){let{buildConnectPluginManifestFromContext:r,ensureConnectAccountRowsFromContext:o}=await import("./setup-introspect-YZWWCD2B.js"),{postHubConnectSession:i}=await import("./connect-A2OXYDLE.js"),s={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await o(s,t.tenantId);let a=await r(s,t.tenantId,{pluginIds:t.pluginIds});if(a.length===0)throw new Error("No connectable plugins found for this tenant");let c=a.find(l=>l.setupError);if(c)throw new Error(c.setupError??`Could not prepare connect link for ${c.plugin}`);return i(e,{tenantId:t.tenantId,plugins:a})}var Q=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function rt(e,n){let t=w(e,()=>new Q("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Q("no_database","Database not configured");let r=F(t,n.plugin,u=>new Q("plugin_not_found",u)),o=S(r);if(!o)throw new Q("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(o==="oauth_2"||o==="managed")throw new Q("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Ie(e,n.tenantId);let i=new Set(hn(r,o)),a=r.authConfig?.[o]?.account??[],c=_({authType:o,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a}),l=0;for(let[u,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(u))throw new Q("invalid_credentials",`Unknown credential field '${u}' for plugin '${n.plugin}'`);let g=N(c,`set_${u}`);if(!g)throw new Q("invalid_credentials",`Cannot set credential field '${u}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new Q("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var X=class extends Error{code;constructor(n,t){super(t),this.name="IntegrationCredentialsDeliveryError",this.code=n}};async function Vt(e,n){let t=w(e,()=>new X("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new X("no_database","Database not configured");let r=F(t,n.plugin,u=>new X("plugin_not_found",u)),o=S(r);if(!o)throw new X("invalid_credentials",`Plugin '${r.id}' has no authType configured`);await ko(e);let i=new Set(Wr(r,o)),a=r.authConfig?.[o]?.integration??[],c=E({authType:o,integrationName:n.plugin,kek:t.kek,database:t.database,extraIntegrationFields:a}),l=0;for(let[u,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(u))throw new X("invalid_credentials",`Unknown integration credential field '${u}' for plugin '${n.plugin}'`);let g=N(c,`set_${u}`);if(!g)throw new X("invalid_credentials",`Cannot set integration field '${u}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new X("invalid_credentials","Provide at least one integration credential field to save");return{plugin:n.plugin}}var ot=new Map;function ba(e){for(let[n,t]of ot)t<=e&&ot.delete(n)}function it(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return ba(r),ot.has(t)?{ok:!1,error:"Delivery request already consumed"}:(ot.set(t,r+n),{ok:!0})}async function st(e,n,t){for(let r of e){if(r.id!==n)continue;let o=r.oauthWebhookTenantLinkResolver;return o?o(t):null}return null}var Ko=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function ka(e){let n=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.pluginId).executeTakeFirst();if(!n)throw new Error(`Integration '${e.pluginId}' not found. Run setupCorsair before registering webhook tenant links.`);let t=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",n.id).executeTakeFirst();if(!t)throw new Error(`Account not found for tenant '${e.tenantId}' and integration '${e.pluginId}'.`);return{integrationId:n.id,accountId:t.id}}async function Ca(e){let n=await e.database.db.selectFrom("corsair_accounts").selectAll().where("id","=",e.accountId).executeTakeFirst();if(!n?.dek)throw new Error(`Account '${e.accountId}' has no DEK.`);let t=await K(n.dek,e.kek),r=Ko(n.config),o={};Object.keys(r).length>0&&(o=ce(r,t)),o[e.link.linkType]=e.link.externalId;let i=he(o,t);await e.database.db.updateTable("corsair_accounts").set({config:i,updated_at:new Date}).where("id","=",n.id).execute()}async function We(e){let{database:n,kek:t,pluginId:r,tenantId:o,link:i,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await ka({database:n,pluginId:r,tenantId:o}),l=!1;if(s){let u=_({authType:s,integrationName:r,tenantId:o,kek:t,database:n,extraAccountFields:a}),p=`set_${i.linkType}`,g=u[p];typeof g=="function"&&(await g(i.externalId),l=!0)}l||await Ca({database:n,kek:t,accountId:c,link:i})}async function Yt(e){let{database:n,kek:t,pluginId:r,linkType:o,externalId:i}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let c=await K(a.dek,t),u=Ko(a.config)[o];if(!u)continue;if(en(u,c)===i)return a}catch{continue}return null}async function at(e){return(await Yt(e))?.tenant_id??null}async function qo(e){return at({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}function Zo(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType??"oauth_2",status:"ready",connected:!0,verified:!0,webhookLink:e.link}}function Go(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType,status:e.status,connected:e.connected,verified:e.verified,missingFields:e.missingFields,webhookLink:e.webhookLink,webhookSecret:e.webhookSecret}}async function Ke(e,n){await $({hub:e,path:"/connections/report",body:Zo(n),parseResponse:()=>({ok:!0})}).catch(()=>{})}function wa(e,n){try{let t=M(e);$({hub:t,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}catch(t){if(t instanceof ie)return}}async function va(e){if(!e.hub||!e.database||!e.kek)return;let n={database:e.database,kek:e.kek,plugins:e.plugins};if(!S(e.plugin))return;let r=e.tenantId?.trim()||"default",o=await xe(n,e.plugin,r);o&&zo(e.hub,Go({tenantId:r,plugin:e.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:e.verified??o.connected,missingFields:o.missingRequiredFields}))}function Jo(e,n){wa(e,n)}function zo(e,n){$({hub:e,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}function cn(e){va(e).catch(()=>{})}async function Qt(e,n){let t=w(e);if(!S(n.plugin))return;let o=await xe(t,n.plugin,n.tenantId);o&&Jo(e,Go({tenantId:n.tenantId.trim()||"default",plugin:n.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:n.verified??o.connected,missingFields:o.missingRequiredFields,webhookLink:n.webhookLink,webhookSecret:n.webhookSecret}))}var we=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function qe(e,n){let{plugin:t,tenantId:r,accessToken:o,refreshToken:i,expiresIn:s,scope:a}=n;if(!o.trim())throw new we("no_access_token","Managed OAuth delivery missing access_token");let c=w(e,()=>new we("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new we("no_database","No database configured on corsair instance");let l=F(c,t,p=>new we("plugin_not_found",p));await Ie(e,r);let u=_({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await u.set_access_token(o),i&&await u.set_refresh_token(i),s&&await u.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await u.set_scope(a);try{let p=await st(c.plugins,t,{access_token:o,refresh_token:i,scope:a});if(p){try{let g=l.authConfig?.managed?.account??[];await We({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:p,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}c.hub&&Ke(c.hub,{plugin:t,tenantId:r,link:p,authType:"managed"})}}catch(p){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,p)}return{plugin:t,tenantId:r}}function Ta(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Vo(e,n,t=[]){for(let[r,o]of Object.entries(e))if(Ta(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=Vo(o,n,[...t,r]);if(i)return i}return null}function Pa(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Aa(e){let n=e["x-goog-resource-uri"],t=e["x-goog-channel-id"];if(!n||!t)return null;let r={resourceId:e["x-goog-resource-id"]||"",resourceState:e["x-goog-resource-state"]||"",resourceUri:n,channelId:t,channelExpiration:e["x-goog-channel-expiration"]||""};return n.includes("/drive/")&&(r.kind="drive#change"),{message:{data:Buffer.from(JSON.stringify(r)).toString("base64"),messageId:e["x-goog-message-number"]||""}}}async function Yo(e,n,t,r,o){let i=Pa(n),s=typeof t=="string"?JSON.parse(t):t;(!s||typeof s=="object"&&Object.keys(s).length===0)&&i["x-goog-resource-uri"]&&(s=Aa(i)||s);let c={headers:i,body:s,...r?{query:r}:{}},l=r?.tenantId||"default",u=e.withTenant?e.withTenant(l):e,p=o?.plugin,g=p?[p]:bn;for(let d of g){let y=u[d];if(!y||!y.webhooks||!p&&y.pluginWebhookMatcher&&!y.pluginWebhookMatcher(c))continue;let f=Vo(y.webhooks,c);if(!f)continue;let m=f.path.join("."),h={payload:s,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let b=await f.webhook.handler(h),v=!!Object.keys(b.returnToSender||{})?.length;return{plugin:d,action:m,body:s,response:v?{...b?.returnToSender,success:!0}:{success:!0},...b.responseHeaders&&{responseHeaders:b.responseHeaders}}}catch(b){return console.error(`Error executing webhook handler for ${d}.${m}:`,b),{plugin:d,action:m,body:s,response:{success:!1,error:b instanceof Error?b.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}function Re(e){return e.deliveryMode==="auth.credentials"}function un(e){return e.deliveryMode==="connections.sync"}function ct(e){return e.deliveryMode==="connect.create_link"}function ln(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function dn(e){return e.deliveryMode==="oauth.tokens"}function ut(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!Re(e)&&!un(e)&&!ct(e)&&!ln(e)&&!dn(e)}async function xa(e,n){try{return{status:"ok",webhookResponse:{status:200,body:{status:"ok",sync:{encrypted:await an(e,n)}}}}}catch(t){return{status:"failed",retryable:zt(t),error:t instanceof Error?t.message:"Connections sync delivery failed"}}}async function Ia(e,n){try{let t=await tt(e,n);return{status:"ok",webhookResponse:{status:200,body:{status:"ok",connectUrl:t.connectUrl,expiresAt:t.expiresAt}}}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Connect link delivery failed"}}}function Xt(e,n){if(e instanceof Headers)return e.get(n)??void 0;let t=e[n]??e[n.toLowerCase()];return Array.isArray(t)?t[0]:typeof t=="string"?t:void 0}async function Sa(e,n,t){let r=typeof t.tenantId=="string"?t.tenantId:typeof t.query?.tenantId=="string"?t.query.tenantId:void 0;return r||(!n.database||!t.plugin||!t.linkType||!t.externalId?void 0:await at({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function Ra(e,n,t){let r=await Sa(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await Yo(e,t.headers,t.body,o,t.plugin?{plugin:t.plugin}:void 0);if(!i.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(i.response&&i.response.success===!1)return{status:"failed",retryable:!1,error:typeof i.response.error=="string"?i.response.error:"Webhook handler failed"};let s=i.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(i.response?.data??i.response);return{status:"ok",webhookResponse:{status:i.response?.statusCode??200,body:a,headers:i.responseHeaders}}}async function _a(e,n){return await pn(e,{code:n.code,state:n.state,redirectUri:n.redirectUri,...n.plugin&&n.tenantId?{trusted:!0,plugin:n.plugin,tenantId:n.tenantId}:{}}),{status:"ok"}}async function Ea(e,n){return await qe(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function nr(e,n,t){let r=await er(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function er(e,n,t){let r=w(e),o=n.token?.trim();if(!o)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let i=new Date().toISOString(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",o).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<i?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Da(e,n){try{return await rt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function Oa(e,n){try{return await Vt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Integration credential delivery failed"}}}async function tr(e,n,t={}){let r=w(e),o=Xt(n.headers,"x-corsair-signature"),i=Xt(n.headers,"x-corsair-timestamp"),s=Xt(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let c=$e({body:n.body,signatureHeader:o,timestampHeader:i,signingSecret:t.signingSecret});if(!c.ok)return{status:"failed",retryable:!1,error:c.error};if(!s?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let l=it(`nonce:${s.trim()}`,Pe);if(!l.ok)return{status:"failed",retryable:!1,error:l.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let a;try{a=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}if(a.type==="connect.status")return{status:"failed",retryable:!1,error:"connect.status is deprecated; use connections.sync signed delivery instead"};switch(a.type){case"webhook":return Ra(e,r,a.payload);case"oauth.callback":return _a(e,a.payload);case"oauth.tokens":return Ea(e,a.payload);case"permission.approve":return er(e,a.payload,"approved");case"permission.deny":return er(e,a.payload,"denied");case"auth.credentials":return Da(e,a.payload);case"integration.credentials":return Oa(e,a.payload);case"connect.create_link":return Ia(e,a.payload);case"connections.sync":{let c=t.signingSecret?.trim();return c?xa(e,c):{status:"failed",retryable:!1,error:"Tunnel signing secret is required for connections.sync"}}default:return Ma(String(a.type))}}function Ma(e){return Vr.has(e)?{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}:{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}}var rr=new Map;function Qo(e){let n;try{n=M(e)}catch{return}let t=Tt(n);t&&rr.get(n.projectApiKey)!==t&&(rr.set(n.projectApiKey,t),$({hub:n,path:"/apps/announce",body:{deliveryUrl:t},parseResponse:()=>({ok:!0})}).catch(()=>{rr.delete(n.projectApiKey)}))}var Ha=[".corsair.dev"];function Fa(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function Ua(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Fa(n)?!0:Ha.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Xo(e){return!e||!Ua(e)?null:{"Access-Control-Allow-Origin":e,"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"content-type, x-corsair-signature, x-corsair-timestamp, x-corsair-project, x-corsair-nonce, access-control-request-private-network","Access-Control-Allow-Private-Network":"true","Access-Control-Max-Age":"0",Vary:"Origin"}}function ei(e,n){if(!n)return e;let t=new Headers(e.headers);for(let[r,o]of Object.entries(n))t.set(r,o);return new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function or(e,n){let t=new URL(e);return n.error?(t.searchParams.set("error",n.error),t.toString()):n.connectedPlugin?(t.searchParams.set("connected",n.connectedPlugin),t.toString()):(n.status!==void 0&&t.searchParams.set("status",Buffer.from(JSON.stringify(n.status)).toString("base64url")),t.toString())}async function ir(e,n){let t=M(e),o=new URL(n).searchParams.get("d");if(!o)return{type:"json",status:200,body:{status:"ok",message:"Corsair tunnel endpoint is active",timestamp:new Date().toISOString()}};let i=ye(o,t.signingSecret);if(!i)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let s=it(`browser:${i.jti}`,fe);if(!s.ok)return{type:"json",status:400,body:{error:s.error}};try{if(un(i)){if(!i.hubOrigin||!i.requestId)return{type:"json",status:400,body:{error:"Connections sync delivery requires hubOrigin and requestId for client bridge"}};let a=await an(e,t.signingSecret);return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:Oe({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",sync:{encrypted:a}}})}}if(ct(i)){if(!i.hubOrigin||!i.requestId)return{type:"json",status:400,body:{error:"Connect link delivery requires hubOrigin and requestId for client bridge"}};let a=i.connectLinkPlugins?.filter(Boolean)??[];if(a.length===0)return{type:"json",status:400,body:{error:"Connect link delivery requires at least one plugin in connectLinkPlugins"}};let c=await tt(e,{tenantId:i.tenantId,plugins:a});return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:Oe({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",connectUrl:c.connectUrl,expiresAt:c.expiresAt}})}}if(Re(i))return i.hubSuccessUrl?i.credentials?(await rt(e,{plugin:i.plugin,tenantId:i.tenantId,credentials:i.credentials}),{type:"redirect",url:or(i.hubSuccessUrl,{connectedPlugin:i.plugin})}):{type:"redirect",url:or(i.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(ln(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await nr(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(dn(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await qe(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!ut(i)||!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await pn(e,{code:i.code,state:i.state,redirectUri:i.redirectUri,trusted:!0,plugin:i.plugin,tenantId:i.tenantId})}}catch(a){let c=a instanceof Error?a.message:"Hub delivery failed";return un(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Oe({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:ct(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Oe({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:Re(i)&&i.hubSuccessUrl?{type:"redirect",url:or(i.hubSuccessUrl,{error:c})}:Re(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Oe({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:{type:"json",status:400,body:{error:c}}}return{type:"redirect",url:i.hubSuccessUrl}}async function sr(e,n){let t=M(e),r=await tr(e,n,{signingSecret:t.signingSecret});if(r.status!=="ok")return{type:"json",status:r.retryable===!1?400:502,body:{error:r.error??"Tunnel processing failed"}};let o=r.webhookResponse;if(!o)return{type:"json",status:200,body:{status:"ok"}};let i=o.status??200,s=o.headers;return o.body&&typeof o.body=="object"&&!(o.body instanceof ArrayBuffer)?{type:"json",status:i,body:o.body,headers:s}:{type:"text",status:i,body:typeof o.body=="string"?o.body:o.body?JSON.stringify(o.body):null,headers:s}}function ar(e){if(e.type==="redirect")return Response.redirect(e.url,302);let n=new Headers;for(let[t,r]of Object.entries(e.headers??{}))typeof r=="string"&&n.set(t,r);return e.type==="json"?Response.json(e.body,{status:e.status,headers:n}):new Response(e.body,{status:e.status,headers:n})}async function cr(e,n){return n.method==="GET"?ir(e,n.url):sr(e,{headers:n.headers,body:n.body??""})}async function ur(e,n){try{let t=await cr(e,n);return ar(t)}catch(t){if(t instanceof ie)return Response.json({error:t.message},{status:503});throw t}}async function _e(e,n){Qo(e);let t=n.method.toUpperCase(),r=Xo(n.headers.get("origin"));if(t==="OPTIONS")return r?new Response(null,{status:204,headers:r}):Response.json({error:"Method not allowed"},{status:405});if(t!=="GET"&&t!=="POST")return Response.json({error:"Method not allowed"},{status:405});let o=await ur(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return ei(o,r)}var ee=class extends Error{pluginId;authType;constructor(n,t,r){super(r??`[auth-missing:${n}:${t}]`),Object.setPrototypeOf(this,new.target.prototype),this.name="AuthMissingError",this.pluginId=n,this.authType=t}};var ni=300;async function lr(e,n){let{keys:t,hub:r,plugin:o,tenantId:i}=e,s=n?.forceRefresh??!1,[a,c,l]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!a&&!l)throw new ee(o,"managed");let u=Math.floor(Date.now()/1e3);if(!s&&a&&c&&Number(c)>u+ni)return{accessToken:a,expiresAt:Number(c),refreshed:!1};if(!l&&a&&!s){let d=c?Number(c):null;if(d===null||d>u+ni)return{accessToken:a,expiresAt:d??u+3600,refreshed:!1}}let p=await La(r,o,i),g=p.expires_in?u+p.expires_in:c?Number(c):u+3600;return await t.set_access_token(p.access_token),await t.set_expires_at(String(g)),p.refresh_token&&await t.set_refresh_token(p.refresh_token),p.scope&&await t.set_scope(p.scope),{accessToken:p.access_token,expiresAt:g,refreshed:!0}}function Ba(e){return e.includes("Managed OAuth connection not found")||e.includes("Managed OAuth connection has no tokens")}async function La(e,n,t){try{return await $({hub:e,path:"/oauth/refresh",body:{plugin:n,tenantId:t},parseResponse:An})}catch(r){let o=r instanceof Error?r.message:"";throw Ba(o)?new ee(n,"managed"):r}}async function ti(e,n){e._refreshAuth=async()=>(await lr(n,{forceRefresh:!0})).accessToken}function ri(e){return{delivery:n=>_e(e,n),deliveryOptions:n=>_e(e,n)}}var oi=1200*1e3;function dr(){return oe()}function pr(){return oi}function gr(e,n){return Ye(e,n,oi)}function fr(e,n){return Y(e,n)}function yr(e){return Ae(e)}var ii=600*1e3;function mr(){return oe()}function hr(){return ii}function br(e,n){return Ye(e,n,ii)}function kr(e,n){return Y(e,n)}function Cr(e){return wt(e)}function wr(e){return Ae(e)}function vr(){return oe()}function Tr(e,n,t){return kn(e,n,Math.floor(t.getTime()/1e3))}function Pr(e,n){return Y(e,n)}function Ar(e){return Ae(e)}function lt(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(o,i){let s=t.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${t.join(" and ")} ${s?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
24
+
25
+ To generate a KEK, run: openssl rand -base64 ${Xe}`)}})}async function Na(e){let n=!1;for(;;){let t=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.integrationName).executeTakeFirst();if(!t){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Integration "${e.integrationName}" not found. Make sure to create the integration first.`)}let r=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",t.id).executeTakeFirst();if(!r){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Account not found for tenant "${e.tenantId}" and integration "${e.integrationName}". Make sure to create the account first.`)}return{integrationId:t.id,accountId:r.id,integration:{id:t.id,config:t.config,dek:t.dek??null},account:{id:r.id,config:r.config,dek:r.dek??null}}}}async function si(e){let{integrationId:n,accountId:t}=await Na(e);return{integrationId:n,accountId:t}}function xr(e,n){return`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${n}`}async function $a(e,n){let t=e.hub;if(!t||!n.database||!n.kek)return null;try{return(await _t(t,{tenantId:n.tenantId,plugin:n.plugin,database:n.database,kek:n.kek,plugins:n.plugins})).connectUrl}catch{return null}}async function ja(e){let n=e.hub;if(n&&e.database&&e.kek)try{let r=await _t(n,{tenantId:e.tenantId,plugin:e.plugin,database:e.database,kek:e.kek,plugins:e.plugins});return e.manual?.onAuthMissing?e.manual.onAuthMissing({plugin:e.pluginId,connectUrl:r.connectUrl,state:r.token}):xr(e.pluginId,r.connectUrl)}catch{return`[auth-missing:${e.pluginId}:${e.authType}] Authentication required. Could not create connect link. Check hub configuration and server logs.`}let t=await $a({manual:e.manual,hub:e.hub},{plugin:e.plugin,tenantId:e.tenantId,database:e.database,kek:e.kek,plugins:e.plugins});return t?xr(e.pluginId,t):`[auth-missing:${e.pluginId}:${e.authType}]`}function Wa(e,n,t){let r=Ue(ke(e,n.tenantId??t??"default"),n.kek),o=new URL(n.baseUrl);o.searchParams.set("state",r);let i=o.toString();return n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:i,state:r}):xr(e,i)}async function ai(e){let n=e.tenantId??"default",t=e.error.pluginId;return e.manual&&Be(e.manual)&&e.manual.oauthConfig&&e.manual.kek&&e.error.authType==="oauth_2"?Wa(t,{...e.manual,baseUrl:e.manual.baseUrl,kek:e.manual.kek},e.tenantId):e.hub&&e.plugin&&e.kek&&e.database&&e.plugins?ja({manual:e.manual,hub:e.hub,plugin:e.plugin,pluginId:t,tenantId:n,authType:e.error.authType,database:e.database,kek:e.kek,plugins:e.plugins}):e.error.message}var Ka=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function ci(e,n,t,r,o){let i={pluginId:n,operation:t,input:r,originalError:e},s=Object.keys(o).find(l=>o[l]?.match(e,i));return await(o[s||"DEFAULT"]?.handler||Ka)(e,i)}function qa(e){return typeof e=="function"}function Ir({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:o,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:c,endpointMeta:l,database:u,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:y,plugin:f,kek:m,allPlugins:h}){for(let[b,v]of Object.entries(e)){let O=n?.[b];if(qa(v)){let T=O,A=[...s,b].join("."),k=async(C={})=>{let P=l?.[A];Lt(A,P?.riskLevel??"write");let L;if(c){let j=P,{result:mn,reason:z,onComplete:Je,token:re,id:Te,expiresAt:W}=await Do({pluginId:o,endpointPath:A,args:C,mode:c.mode,override:c.overrides?.[A],riskLevel:j?.riskLevel??"write",meta:j,db:u,timeoutMs:p?Nt(p.timeout):void 0,tenantId:g,approvalMode:p?.mode});if(mn==="blocked"){let V;throw z==="denied"?V=`Action '${A}' was denied by the user. Await further instructions before proceeding.`:z==="policy"?V=`Action '${A}' is blocked by the permission policy. Update the corsair config to allow it.`:z==="timeout"?V=`Action '${A}' timed out waiting for approval.`:re&&Te?V=await Bt({permissionsOptions:p,manual:d,hub:y,permissionId:Te,permissionToken:re,plugin:o,endpoint:A,args:C,tenantId:g??"default",expiresAt:W??new Date(Date.now()+(p?Nt(p.timeout):600*1e3)).toISOString(),operationPath:A}):V=`Action '${A}' requires user approval before it can run.`,new Error(V)}L=Je}let ne=async(j,mn,z)=>{try{return await v(mn,z)}catch(Je){if(Je instanceof Error){let re=await ci(Je,o,A,typeof z=="object"&&z!==null?z:{args:z},i);if(j<(re.maxRetries||0)){let Te=j+1;console.log(`Retrying (${Te} / ${re.maxRetries})...`);let W;if(re.headersRetryAfterMs)W=re.headersRetryAfterMs;else switch(re.retryStrategy){case"exponential_backoff":W=Math.pow(2,Te-1)*1e3;break;case"exponential_backoff_jitter":let V=Math.pow(2,Te-1)*1e3,Fi=(Math.random()-.5)*1e3;W=Math.max(0,V+Fi);break;case"linear_1s":W=1e3;break;case"linear_2s":W=2e3;break;case"linear_3s":W=3e3;break;case"linear_4s":W=4e3;break;default:W=1e3;break}await new Promise(V=>setTimeout(V,W)),await ne(Te,mn,z),console.log(`[corsair:${o}:${A}] Retry strategy:`,re)}}throw Je}},x;try{x=a?await a(t,"endpoint"):void 0}catch(j){if(j instanceof ee)return f&&y&&cn({hub:y,database:u,kek:m,plugins:h??[],plugin:f,tenantId:g,verified:!1}),ai({error:j,manual:d,hub:y,plugin:f,tenantId:g,database:u,kek:m,plugins:h});throw j}if(!T?.before&&!T?.after){let j=await ne(0,{...t,key:x},C);return await L?.(),f&&y&&cn({hub:y,database:u,kek:m,plugins:h??[],plugin:f,tenantId:g,verified:!0}),j}let te={...t,key:x},de=T.before?await T.before(te,C):{ctx:te,args:C,continue:!0,passToAfter:void 0};if(de.continue===!1)return;let yn=await ne(0,de.ctx,de.args);return await T.after?.(de.ctx,yn,de.passToAfter),await L?.(),f&&y&&cn({hub:y,database:u,kek:m,plugins:h??[],plugin:f,tenantId:g,verified:!0}),yn};r[b]=k}else if(v&&typeof v=="object"){let T={};Ir({endpoints:v,hooks:O,ctx:t,tree:T,pluginId:o,errorHandlers:i,currentPath:[...s,b],keyBuilder:a,permissionsConfig:c,endpointMeta:l,database:u,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:y,plugin:f,kek:m,allPlugins:h}),r[b]=T}}}function Za(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Sr({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:o}){for(let[i,s]of Object.entries(e)){let a=n?.[i];if(Za(s)){let c=a,l=async u=>{let p=(d,y)=>s.handler(d,y),g=o?await o(t,"webhook"):void 0;return!c?.before&&!c?.after?p({...t,key:g},u):(async()=>{let d={...t,key:g},y=c.before?await c.before(d,u):{ctx:d,args:u,continue:!0,passToAfter:void 0};if(y.continue===!1)return;let f=await p(y.ctx,y.args);return f?.success===!0&&await c.after?.(y.ctx,f,y.passToAfter),f})()};r[i]={match:s.match,handler:l}}else if(s&&typeof s=="object"){let c={};Sr({webhooks:s,hooks:a,ctx:t,webhooksTree:c,keyBuilder:o}),r[i]=c}}}function Ga(e,n,t,r){let o=null;return async()=>{if(o)return o;if(!e)throw new Error("Database not configured");let{accountId:i}=await si({database:e,integrationName:n,tenantId:t,ensureProvisioned:r});return o=i,o}}function Ja(e,n,t,r,o){return e?bt(e.db,n,t,r,o):{findByEntityId:async()=>null,existsByEntityId:async()=>!1,findIdByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function Rr(e,n){let{database:t,tenantId:r,kek:o,rootErrorHandlers:i,permissionsOptions:s,manualConfig:a,hubConfig:c,internalConfig:l}=n,u=l&&t?()=>Dn(l,r??"default"):void 0,p={},g={};for(let d of e)p[d.id]={},g[d.id]={};for(let d of e){let y=d.schema,f=r??"default",m=Ga(t,d.id,f,u);if(y?.entities){let x={};for(let[te,de]of Object.entries(y.entities)){let yn=t?bt(t.db,m,te,y.version,de):Ja(void 0,m,te,y.version,de);x[te]=yn}g[d.id].db=x,p[d.id].db=x}let h=d.options,b=d.authConfig,v;if(t&&o&&h?.authType){let x=b?.[h.authType]?.account??[];v=_({authType:h.authType,integrationName:d.id,tenantId:f,kek:o,database:t,extraAccountFields:x,ensureProvisioned:u}),p[d.id].keys=v}let O={database:t,db:g[d.id]?.db??{},$getAccountId:m,...d.options?{options:d.options}:{},...v?{keys:v,authType:h?.authType}:{},tenantId:f,...c?{hub:c}:{}},T=d.endpoints??{},A=d.hooks,k={...i,...d.errorHandlers},C={},P=d.options?.permissions;Ir({endpoints:T,hooks:A,ctx:O,tree:C,pluginId:d.id,errorHandlers:k,currentPath:[],keyBuilder:d.keyBuilder,permissionsConfig:P,endpointMeta:d.endpointMeta,database:t,permissionsOptions:s,tenantId:r,manualConfig:a?{...a,oauthConfig:d.oauthConfig,kek:o,tenantId:f}:void 0,hubConfig:c,plugin:d,kek:o,allPlugins:e}),Object.keys(C).length>0&&(p[d.id].api=C),O.endpoints=C;let L=d.webhooks??{},ne=d.webhookHooks;if(Object.keys(L).length>0){let x={};Sr({webhooks:L,hooks:ne,ctx:O,webhooksTree:x,keyBuilder:d.keyBuilder}),p[d.id].webhooks=x,d.pluginWebhookMatcher&&(p[d.id].pluginWebhookMatcher=d.pluginWebhookMatcher),d.pluginTenantWebhookMatcher&&(p[d.id].pluginTenantWebhookMatcher=d.pluginTenantWebhookMatcher)}}return p}function ui(e,n,t){let r={};for(let o of e){let i=o.options,s=o.authConfig;if(i?.authType){let a=s?.[i.authType]?.integration??[],c=E({authType:i.authType,integrationName:o.id,kek:t,database:n,extraIntegrationFields:a});r[o.id]=c}}return r}var za="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function li(e){let{permissions:n,approval:t}=e;if(n&&t)throw new Error("createCorsair was given both permissions and approval config. Use permissions only \u2014 approval is deprecated.");return t?(console.warn(`[corsair] ${za}`),t):n}var di=[{method:"GET",pattern:"/ok",handler:async()=>D(200,jn())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>D(200,await Ne(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>D(201,await qn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>D(200,await Kn(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>D(200,await Le(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>D(200,await Wn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>D(200,await Zn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>D(200,await $t(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?D(200,await Wt(e,t)):D(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>D(200,await Gn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>D(200,await Jn(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>D(200,await zn(e,n,t))}];(()=>{let e=new Set;for(let n of di){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function Va(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let o={};for(let i=0;i<t.length;i++){let s=t[i],a=r[i];if(s.startsWith(":"))o[s.slice(1)]=decodeURIComponent(a);else if(s!==a)return null}return o}function Ya(e,n){if(!n)return e;let t=n.endsWith("/")?n.slice(0,-1):n;return e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length):e}async function Qa(e){if(!(e.method==="GET"||e.method==="HEAD"||!(e.headers.get("content-type")??"").includes("application/json")))try{let t=await e.text();return t?JSON.parse(t):void 0}catch{throw new R(400,"invalid_json","Request body is not valid JSON")}}var Xa="/api/corsair";function Ee(e,n={}){let t=n.basePath??Xa,r=w(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async o=>{try{let i=new URL(o.url),s=Ya(i.pathname,t),a=o.method.toUpperCase();if(a==="OPTIONS"||s==="/"||s==="")return await _e(e,o);if(a!=="GET"&&a!=="POST")return D(405,{error:"method_not_allowed",message:`Method ${a} not allowed`});let c=Object.fromEntries(i.searchParams);for(let l of di){if(l.method!==a)continue;let u=Va(l.pattern,s);if(!u)continue;let p=await Qa(o);return await l.handler({corsair:e,internal:r,req:o,params:u,query:c,body:p})}throw Ce(`No route for ${a} ${s}`)}catch(i){if(n.onError){let a=await n.onError(i,o);if(a)return a}if(i instanceof R)return Oo(i);let s=i instanceof Error?i.message:"Internal server error";return D(500,{error:"internal_error",message:s})}}}function ec(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,o=`${t}://${n}${r}`,i=new Headers;for(let[c,l]of Object.entries(e.headers))if(l!=null)if(Array.isArray(l))for(let u of l)i.append(c,u);else i.set(c,l);let s=e.method!=="GET"&&e.method!=="HEAD",a={method:e.method,headers:i};return s&&e.body!==void 0&&(a.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),i.has("content-type")||i.set("content-type","application/json")),new Request(o,a)}async function nc(e,n){e.status(n.status),n.headers.forEach((r,o)=>e.setHeader(o,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function pi(e,n){let t=Ee(e,n);return async(r,o,i)=>{try{let s=await t(ec(r));await nc(o,s)}catch(s){i(s)}}}function gi(e,n){let t=Ee(e,n);return r=>t(r.req.raw)}function fi(e,n){let t=Ee(e,n);return{GET:t,POST:t,OPTIONS:t}}function yi(e){let n={[gn]:e};return{ok:jn,tenants:{list:()=>Ne(e),create:t=>qn(e,t),get:t=>Kn(e,t)},plugins:{list:()=>Le(e),get:t=>Wn(e,t)},connectionStatus:{get:t=>Zn(e,t?.tenantId)},permissions:{get:t=>Lo(e,t)},connect:{createLink:t=>Gn(n,e,t),resolve:t=>Jn(n,e,t),oauthCallback:t=>zn(n,e,t)}}}async function mi(e,n,t,r,o="pending"){if(!e)return null;try{let i=Kr(),s=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:s,updated_at:s,account_id:n,event_type:t,payload:r,status:o}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function tc(e,n,t,r="pending"){try{let o=await e.$getAccountId();return mi(e.database,o,n,t,r)}catch(o){return console.warn("Failed to log event:",o),null}}import*as bi from"https";import*as dt from"querystring";var rc=["expires_in","refresh_token_expires_in"];function hi(e){let n={...e};for(let t of rc){let r=e[t];if(typeof r=="string"){let o=Number(r);n[t]=Number.isFinite(o)?o:void 0}}return n}function oc(e){try{return hi(JSON.parse(e))}catch{}if(!e.includes("="))return null;let n=dt.parse(e);return!n.access_token&&!n.error?null:hi({...n})}function pt(e,n,t,r,o){let i=new URL(r.tokenUrl),s=r.tokenAuthMethod==="basic";return new Promise((a,c)=>{let l={code:e.trim(),redirect_uri:o,grant_type:"authorization_code"};s||(l.client_id=n,l.client_secret=t);let u=dt.stringify(l),p={"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json","Content-Length":Buffer.byteLength(u).toString()};s&&(p.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=bi.request({hostname:i.hostname,...i.port?{port:Number(i.port)}:{},path:i.pathname+i.search,method:"POST",headers:p},d=>{let y="";d.on("data",f=>{y+=f}),d.on("end",()=>{if(d.statusCode!==200){c(new Error(`Token exchange failed (${d.statusCode}): ${y}`));return}let f=oc(y);f?a(f):c(new Error(`Token endpoint returned non-JSON response: ${y}`))})});g.on("error",d=>c(new Error(`Request failed: ${d.message}`))),g.write(u),g.end()})}var ki=" ";function G(e){let n=e;return n._def??n.def??{}}function J(e){let n=e.typeName;if(n)return n;let t=e.type;if(t)return`Zod${t.split("_").map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("")}`}function Z(e){return e.innerType??e.schema??e.out??e.in}function wi(e,n){switch(n){case"ZodPipe":return e.in??e.innerType;case"ZodEffects":return e.schema??e.innerType;case"ZodTransform":return e.schema??e.innerType??e.in;default:return Z(e)}}function vi(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function ft(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function Ze(e){return Array.isArray(e.options)?e.options:Array.isArray(e.values)?e.values:e.entries!==null&&typeof e.entries=="object"&&!Array.isArray(e.entries)?Object.values(e.entries):[]}function Ti(e,n){return e.description??n.description}function ic(e){let n=e;for(;n;){let t=G(n),r=Ti(n,t);if(r)return r;let o=J(t);if(Mr(o)||o==="ZodPipe"||o==="ZodEffects"||o==="ZodTransform"){n=wi(t,o);continue}break}}function Mr(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function U(e){let n=G(e),t=J(n);switch(t){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"Date";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(n.value??Ze(n)[0]??"unknown");case"ZodEnum":return Ze(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=Z(n);return r?U(r):"unknown"}case"ZodNullable":{let r=Z(n);return`${r?U(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=Z(n);return r?U(r):"unknown"}case"ZodArray":{let r=vi(n);if(!r)return"unknown[]";let o=G(r),i=J(o)==="ZodUnion",s=U(r);return`${i?`(${s})`:s}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=ft(e,n),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([s,a])=>{let c=J(G(a));return`${c==="ZodOptional"||c==="ZodNullable"?s+"?":s}: ${U(a)}`}).join(", ")} }`}case"ZodUnion":return Ze(n).map(r=>U(r)).join(" | ");case"ZodIntersection":return`${U(n.left)} & ${U(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=wi(n,t);return r?U(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function le(e){let n=G(e),t=J(n),r=Ti(e,n);switch(t){case"ZodString":return{kind:"string",optional:!1,description:r};case"ZodNumber":return{kind:"number",optional:!1,description:r};case"ZodBoolean":return{kind:"boolean",optional:!1,description:r};case"ZodLiteral":{let o=n.value??Ze(n)[0],i=typeof o=="string"||typeof o=="number"||typeof o=="boolean"?o:String(o??"");return{kind:"literal",optional:!1,description:r,value:i}}case"ZodEnum":{let o=Ze(n).map(i=>String(i));return{kind:"string",optional:!1,description:r,enum:o}}case"ZodOptional":{let o=Z(n),i=o?le(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodNullable":{let o=Z(n),i=o?le(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodDefault":case"ZodCatch":{let o=Z(n);return o?{...le(o),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let o=vi(n);return{kind:"array",optional:!1,description:r,items:o?le(o):{kind:"unknown",optional:!1}}}case"ZodObject":{let o=ft(e,n),i={};for(let[s,a]of Object.entries(o))i[s]=le(a);return{kind:"object",optional:!1,description:r,fields:i}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let o=Ze(n);for(let i of o){let s=G(i);if(J(s)==="ZodObject")return{...le(i),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let o=Z(n);return o?{...le(o),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function Xg(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let o=t.slice(0,r),i=t.slice(r+1),s=e.find(u=>u.id===o);if(!s)return null;let a=i;a.startsWith("api.")&&(a=a.slice(4));let c=ve(s.endpointMeta,a),l=ve(s.endpointSchemas,a);return!c&&!l?null:{input:l?.input?le(l.input):null,output:l?.output?le(l.output):null,description:c?.description}}var Hr=["equals","contains","startsWith","endsWith","in"],sc=["equals","gt","gte","lt","lte","in"],ac=["equals"],cc=["equals","before","after","between"];function Pi(e){let n=G(e);switch(J(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=Z(n);return r?Pi(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Fr(e){let n=G(e),t=J(n);if(Mr(t)){let i=Z(n);return i?Fr(i):{}}if(t!=="ZodObject")return{};let r=ft(e,n),o={};for(let[i,s]of Object.entries(r)){let a=Pi(s);a==="string"?o[i]={type:"string",operators:Hr}:a==="number"?o[i]={type:"number",operators:sc}:a==="boolean"?o[i]={type:"boolean",operators:ac}:a==="date"&&(o[i]={type:"date",operators:cc})}return o}function Ai(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function Er(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];typeof o=="function"?t.push(i.join(".")):o!==null&&typeof o=="object"&&Er(o,i,t)}}function Dr(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Or(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];Dr(o)?t.push(i.join(".")):o!==null&&typeof o=="object"&&Or(o,i,t)}}function Ur(e,n){if(n.length===0)return null;let[t,...r]=n,o=Object.entries(e).find(([a])=>a.toLowerCase()===t);if(!o)return null;let[i,s]=o;if(r.length===0)return Dr(s)?[i]:null;if(s!==null&&typeof s=="object"&&!Dr(s)){let a=Ur(s,r);if(a!==null)return[i,...a]}return null}function xi(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let i=0;i<n.length;i++){let s=" ".repeat(i+2);t.push(`${s}${n[i]}: {`)}let r=" ".repeat(n.length+2),o=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${o}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let i=n.length-1;i>=0;i--){let s=" ".repeat(i+2);t.push(`${s}},`)}return t.push(" },"),t.push("})"),t.join(`
26
+ `)}var uc=new Set(bn);function De(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let i=e.find(a=>a.id===r);if(!i)return uc.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:De(e);if(t==="webhooks"){if(!i.webhooks)return[];let a=[];return Or(i.webhooks,[],a),a.map(c=>`${i.id}.webhooks.${c}`)}if(t==="db"){let a=i.schema?.entities;return a?Object.keys(a).map(c=>`${i.id}.db.${c}.search`):[]}if(!i.endpoints)return[];let s=[];return Er(i.endpoints,[],s),s.map(a=>`${i.id}.api.${a}`)}let o={};if(t==="webhooks")for(let i of e){if(!i.webhooks)continue;let s=[];Or(i.webhooks,[],s),o[i.id]=s.map(a=>`${i.id}.webhooks.${a}`)}else if(t==="db")for(let i of e){let s=i.schema?.entities;s&&(o[i.id]=Object.keys(s).map(a=>`${i.id}.db.${a}.search`))}else for(let i of e){if(!i.endpoints)continue;let s=[];Er(i.endpoints,[],s),o[i.id]=s.map(a=>`${i.id}.api.${a}`)}return o}function ve(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function lc(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let i=t.slice(n.length+1),s=i.startsWith(".")?i.slice(1):i;return s.startsWith("api.")&&(s=s.slice(4)),{shortPath:s,lookupKey:s}}let o=e.slice(n.length+1);return o.toLowerCase().startsWith("api.")&&(o=o.slice(4)),{shortPath:o,lookupKey:o.toLowerCase()}}function _r(e,n){return typeof e=="string"?e:Array.isArray(e)?`${n}:
27
+ ${e.join(", ")}`:`${n}:
28
+ `+Object.entries(e).map(([t,r])=>` ${t}: ${r.join(", ")}`).join(`
29
+ `)}function ef(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let o=t.slice(0,r),i=t.slice(r+1),s=e.find(a=>a.id===o);if(s){if(i.startsWith("db.")){let u=i.slice(3),p=u.lastIndexOf(".");if(p!==-1){let g=u.slice(0,p),d=u.slice(p+1),y=s.schema?.entities;if(d==="search"&&y){let f=Ai(y,g);if(f){let[m,h]=f,b=Fr(h),v=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Hr.join(", ")}]`];for(let[O,T]of Object.entries(b))v.push(` ${O}?: ${T.type} [${T.operators.join(", ")}]`);return v.push("}"),v.join(`
30
+ `)}}}return _r(De(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let u=i.slice(9);if(s.webhooks){let p=Ur(s.webhooks,u.split("."));if(p!==null){let g=p.join("."),d=ve(s.webhookSchemas,g.toLowerCase()),y=d?.response?U(d.response):null,f=[];return d?.description&&f.push(d.description),d?.payload&&f.push(`payload ${gt(Ge(d.payload))}`),y&&f.push(`response: ${y}`),f.push(`usage:
31
+ ${xi(o,p)}`),f.join(`
32
+
33
+ `)}}return _r(De(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=i;a.startsWith("api.")&&(a=a.slice(4));let c=ve(s.endpointMeta,a),l=ve(s.endpointSchemas,a);if(c||l){let u=[],p=[c?.riskLevel?`[${c.riskLevel}]`:"",c?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),g=[c?.description,p].filter(Boolean).join(" ");return g&&u.push(g),l?.input&&u.push(`input ${gt(Ge(l.input))}`),l?.output&&u.push(`output ${gt(Ge(l.output))}`),u.join(`
34
+
35
+ `)}}}return _r(De(e),"Path not found. Available operations")}function Ci(e){let n=e;for(;;){let t=G(n),r=J(t);if(Mr(r)){let o=Z(t);if(!o)return n;n=o;continue}return n}}function Ge(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=Ci(e),t=G(n);if(J(t)==="ZodObject"){let o=ft(n,t),i=[];for(let[s,a]of Object.entries(o)){let c=G(a),l=J(c),u=l==="ZodOptional"||l==="ZodNullable",p=Ci(a),g=ic(a);i.push({key:s,optional:u,type:U(p),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:i}}return{kind:"inline",type:U(n)}}function gt(e,n=0){if(e===void 0)return"{}";if(e.kind==="inline")return e.type;if(e.kind==="object"){if(e.fields.length===0)return"{}";let t=ki.repeat(n+1),r=ki.repeat(n);return`{
36
+ ${e.fields.map(i=>{let s=i.optional?`${i.key}?`:i.key,a=i.description?` // ${i.description}`:"";return`${t}${s}: ${i.type}${a}`}).join(`
37
+ `)}
38
+ ${r}}`}return"unknown"}function dc(e,n){let t=De(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(u=>u.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let o=[];for(let u of t){let{shortPath:p,lookupKey:g}=lc(u,n),d=ve(r.endpointMeta,g),y=ve(r.endpointSchemas,g);!d&&!y||o.push({path:u,shortPath:p,description:d?.description,riskLevel:d?.riskLevel,irreversible:d?.irreversible,input:Ge(y?.input),output:Ge(y?.output)})}o.sort((u,p)=>u.path.localeCompare(p.path));let i=[],s=De(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let u of s){let g=u.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("webhooks."))continue;let y=d.slice(9),f=Ur(r.webhooks,y.split("."));if(f===null)continue;let m=f.join("."),h=ve(r.webhookSchemas,m.toLowerCase()),b=h?.response?U(h.response):void 0;i.push({path:u,description:h?.description,payload:Ge(h?.payload),responseType:b,usageExample:xi(n,f)})}i.sort((u,p)=>u.path.localeCompare(p.path));let a=[],c=De(e,{plugin:n,type:"db"}),l=r.schema?.entities;if(Array.isArray(c)&&l)for(let u of c){let g=u.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("db."))continue;let y=d.slice(3),f=y.lastIndexOf(".");if(f===-1)continue;let m=y.slice(0,f);if(y.slice(f+1)!=="search")continue;let b=Ai(l,m);if(!b)continue;let[v,O]=b,T=Fr(O),A=Object.entries(T).map(([k,C])=>({field:k,type:C.type,operators:C.operators}));a.push({path:u,entityName:v,filters:[{field:"entity_id",type:"string",operators:Hr},...A]})}return a.sort((u,p)=>u.path.localeCompare(p.path)),{ok:!0,data:{pluginId:n,api:o,webhooks:i,db:a}}}import{randomUUID as Ii}from"crypto";async function pc(e,n){let t=await e.keys.get_access_token();if(!t)return null;let r=Ii(),o=Ii(),i=await fetch(n.watchUrl,{method:"POST",signal:AbortSignal.timeout(2e4),headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({id:r,type:"web_hook",address:n.webhookUrl,token:o,...n.body})});if(!i.ok)throw new Error(`Google channel watch failed (${i.status}): ${await i.text()}`);return{webhookLink:{linkType:"channel_id",externalId:r},webhookSecret:o}}import{randomUUID as gc}from"crypto";var yt="https://graph.microsoft.com/v1.0",Br=2e4,fc=60;async function yc(e,n){let t=await e.keys.get_access_token();if(!t)return null;let r={authorization:`Bearer ${t}`};try{let c=await fetch(`${yt}/subscriptions`,{headers:r,signal:AbortSignal.timeout(Br)});if(c.ok){let{value:l}=await c.json(),u=(l??[]).filter(p=>p.notificationUrl===n.webhookUrl);await Promise.all(u.map(p=>fetch(`${yt}/subscriptions/${p.id}`,{method:"DELETE",headers:r,signal:AbortSignal.timeout(Br)}).catch(()=>{})))}}catch{}let o=gc(),i=new Date(Date.now()+fc*6e4).toISOString(),s=await fetch(`${yt}/subscriptions`,{method:"POST",headers:{...r,"content-type":"application/json"},signal:AbortSignal.timeout(Br),body:JSON.stringify({changeType:n.changeType,notificationUrl:n.webhookUrl,resource:n.resource,expirationDateTime:i,clientState:o})});if(!s.ok)throw new Error(`MS Graph subscribe failed (${s.status}): ${await s.text()}`);let a=await s.json();return a.id?(await e.keys.set_webhook_signature(o),{webhookLink:{linkType:"subscription_id",externalId:a.id},webhookSecret:o}):null}function Si(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function mc(e,n){let t=Si(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let o=r.pluginTenantWebhookMatcher(n);return o?{plugin:t,tenantMatch:o}:null}function hc(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function Ri(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function _i(e){if(typeof e=="string"){let n=e.trim();return n.length>0?n:void 0}if(typeof e=="number"&&Number.isFinite(e))return String(e)}function fn(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function bc(e){return fn(e.body)}function Ei(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return mt(Array.isArray(r)?r:[r])}function Di(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let c of t){let l=mt(Array.isArray(c)?c:[c]);if(l)return decodeURIComponent(l)}let r=Ei({query:e.query},"validationToken");if(r)return r;let o=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let c of o){let l=n[c],u=Array.isArray(l)?l[0]:l;if(!(!u||typeof u!="string"))try{let g=(u.startsWith("http")?new URL(u):new URL(`https://example.invalid${u.startsWith("/")?u:`/${u}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let i=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,s=fn(typeof i=="string"?(()=>{try{return JSON.parse(i)}catch{return i}})():i);return mt([s?.validationToken])??null}function kc(e){if(Di(e))return!0;let n=fn(e.body??e.payload);return Ri(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function mt(e){for(let n of e){let t=_i(n);if(t)return t}}function Cc(e){let t=fn(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var gn=Symbol.for("corsair:internal");function bo(e){let n=e.database?Lr(e.database):void 0,t=n&&e.kek?ui(e.plugins,n,e.kek):lt(!!n,!!e.kek),r=li(e),o={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?Cn(e.hub):void 0},i=Eo(n),s=yi(o);if(e.multiTenancy)return Object.assign({withTenant:c=>{if(!c)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let l=Rr(e.plugins,{database:n,tenantId:c,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign(l,{[gn]:o})},keys:t,permissions:i,manage:s},{[gn]:o});let a=Rr(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign({},a,{keys:t,permissions:i,manage:s,[gn]:o})}async function Oi(e,n){try{return await In({hub:e,path:`/webhooks/endpoint?plugin=${encodeURIComponent(n)}`,parseResponse:t=>t?.url??null})}catch{return null}}async function ht(e,n,t,r){if(!n.subscribe)return;let o=M(e),i=await Oi(o,n.id);if(!i)return;let s=await n.subscribe({keys:r},{webhookUrl:i});s&&await Qt(e,{plugin:n,tenantId:t,verified:!0,webhookLink:s.webhookLink,webhookSecret:s.webhookSecret})}var B=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function Mi(e){let n=e.oauthConfig;if(!n)throw new B("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function wc(e,n,t,r){let o=Zr(e),i=await o.integrations.findByName(n);if(!i)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await o.accounts.findOne({tenant_id:t,integration_id:i.id}))return;let a=se(),c=await ae(a,r);await o.accounts.create({tenant_id:t,integration_id:i.id,config:{},dek:c})}async function St(e,n,t){let{tenantId:r,redirectUri:o,hubConnect:i=!1}=t,s=w(e,()=>new B("invalid_corsair_instance","Invalid corsair instance"));if(!s.database)throw new Error("No database configured on corsair instance");let a=F(s,n,g=>new B("plugin_not_found",g)),c=Mi(a),u=await E({authType:"oauth_2",integrationName:n,kek:s.kek,database:s.database}).get_client_id();if(!u)throw new Error(`client_id not configured for '${n}'`);if(i){let g=new URL(Se({oauthConfig:c,clientId:u,redirectUri:o,state:""}));return g.searchParams.delete("state"),{url:g.toString(),state:""}}let p=Ue(ke(n,r),s.kek);return{url:Se({oauthConfig:c,clientId:u,redirectUri:o,state:p}),state:p}}async function pn(e,n){let{code:t,state:r,redirectUri:o}=n,i=w(e,()=>new B("invalid_corsair_instance","Invalid corsair instance")),s,a;if(n.trusted){if(!n.plugin||!n.tenantId)throw new B("invalid_state","trusted callback requires plugin and tenantId");s=n.plugin,a=n.tenantId}else{let f=Un(r,i.kek);if(!f)throw new B("invalid_state","Invalid or tampered state parameter");s=f.plugin,a=f.tenantId}if(!i.database)throw new B("no_database","No database configured on corsair instance");let c=F(i,s,f=>new B("plugin_not_found",f)),l=Mi(c),u=E({authType:"oauth_2",integrationName:s,kek:i.kek,database:i.database}),p=await u.get_client_id(),g=await u.get_client_secret();if(!p||!g)throw new B("credentials_not_configured",`Credentials not configured for '${s}'`);await wc(i.database,s,a,i.kek);let d=await pt(t,p,g,l,o);if(!d.access_token)throw new B("no_access_token",`No access_token returned from ${l.providerName}`);let y=_({authType:"oauth_2",integrationName:s,tenantId:a,kek:i.kek,database:i.database,extraAccountFields:[...c.authConfig?.oauth_2?.account??[]]});await y.set_access_token(d.access_token),d.refresh_token&&await y.set_refresh_token(d.refresh_token),d.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+d.expires_in));try{let f=await st(i.plugins,s,d);if(f){try{let m=c.authConfig?.oauth_2?.account??[];await We({database:i.database,kek:i.kek,pluginId:s,tenantId:a,link:f,authType:"oauth_2",extraAccountFields:m})}catch(m){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${s}' tenant '${a}':`,m)}i.hub&&Ke(i.hub,{plugin:s,tenantId:a,link:f,authType:"oauth_2"})}}catch(f){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${s}' tenant '${a}':`,f)}if(c.subscribe)try{await ht(e,c,a,y)}catch(f){console.warn(`[corsair:oauth] BYO subscribe failed for '${s}' tenant '${a}':`,f)}return{plugin:s,tenantId:a}}async function vc(e){let{corsair:n,internal:t,rows:r}=e,o=e.subscribeAndReport??ht,i=[],s=[];if(!t.database)return{renewed:i,failed:s};for(let a of r){let c=t.plugins.find(u=>u.id===a.integrationName);if(!c?.subscribe)continue;let l=`${c.id}/${a.tenantId}`;try{let u=_({authType:"oauth_2",integrationName:c.id,tenantId:a.tenantId,kek:t.kek,database:t.database,extraAccountFields:[...c.authConfig?.oauth_2?.account??[]]}),p=c.keyBuilder;if(p){let g=Object.create(u,{get_expires_at:{value:async()=>"0"}});await p({authType:"oauth_2",keys:g},"endpoint")}await o(n,c,a.tenantId,u),i.push(l)}catch(u){console.warn(`[corsair:renewal] re-subscribe failed for '${l}':`,u),s.push(l)}}return{renewed:i,failed:s}}async function Hi(e){let n=w(e);if(!n.database)return{renewed:[],failed:[]};let t=await n.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id as tenantId","i.name as integrationName"]).where("a.dek","is not",null).execute();return vc({corsair:e,internal:n,rows:t.filter(r=>!!r.tenantId)})}function Tc(e,n={}){let t=!1,r=()=>{t||(t=!0,Hi(e).catch(i=>console.warn("[corsair:renewal] renewal pass failed:",i)).finally(()=>{t=!1}))};r();let o=setInterval(r,(n.intervalMinutes??45)*6e4);return o.unref?.(),()=>clearInterval(o)}export{Gr as a,ge as b,Ct as c,ze as d,Jr as e,zr as f,fe as g,Pe as h,oe as i,Me as j,He as k,ye as l,vt as m,Qr as n,Qe as o,ie as p,Cn as q,M as r,wn as s,Fe as t,vn as u,Tn as v,Pn as w,An as x,eo as y,xn as z,me as A,se as B,ae as C,K as D,Pt as E,en as F,he as G,ce as H,nn as I,E as J,_ as K,lo as L,po as M,ke as N,Et as O,Ke as P,We as Q,Yt as R,at as S,qo as T,Se as U,B as V,St as W,pn as X,Hi as Y,Tc as Z,Mn as _,Ds as $,Hn as aa,Su as ba,Rt as ca,Ru as da,vo as ea,_t as fa,Fn as ga,Po as ha,Ao as ia,Ot as ja,Bn as ka,Ln as la,$n as ma,Zs as na,_o as oa,Lt as pa,Vn as qa,qt as ra,$e as sa,je as ta,Yn as ua,Qn as va,on as wa,Zt as xa,Gt as ya,Xn as za,sn as Aa,et as Ba,nt as Ca,we as Da,qe as Ea,Yo as Fa,Re as Ga,ln as Ha,dn as Ia,ut as Ja,nr as Ka,tr as La,ir as Ma,sr as Na,ar as Oa,cr as Pa,ur as Qa,_e as Ra,ee as Sa,lr as Ta,ti as Ua,ri as Va,dr as Wa,pr as Xa,gr as Ya,fr as Za,yr as _a,mr as $a,hr as ab,br as bb,kr as cb,Cr as db,wr as eb,vr as fb,Tr as gb,Pr as hb,Ar as ib,Ee as jb,pi as kb,gi as lb,fi as mb,mi as nb,tc as ob,pt as pb,Xg as qb,De as rb,ef as sb,gt as tb,dc as ub,pc as vb,yt as wb,yc as xb,Si as yb,mc as zb,hc as Ab,Ri as Bb,_i as Cb,fn as Db,bc as Eb,Ei as Fb,Di as Gb,kc as Hb,mt as Ib,Cc as Jb,gn as Kb,bo as Lb};
@@ -1 +1 @@
1
- import{ea as a,fa as b,ga as c}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as createHubConnectSession,b as createHubConnectSessionForPlugin,a as postHubConnectSession};
1
+ import{ea as a,fa as b,ga as c}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as createHubConnectSession,b as createHubConnectSessionForPlugin,a as postHubConnectSession};
package/dist/core.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-DePcixJK.js';
1
+ export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-D7aqzKjb.js';
2
2
  import { CorsairDatabase } from './db.js';
3
- import { A as AccountKeyManagerFor, I as IntegrationKeyManagerFor, f as CorsairPluginSubscribeResult } from './index-Zg8W-Gnw.js';
4
- export { g as AccountFieldNames, k as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, h as BaseKeyManager, G as BeforeHookResult, n as BindEndpoints, a4 as BindWebhooks, a2 as Bivariant, o as BoundEndpointFn, p as BoundEndpointTree, a5 as BoundWebhook, a6 as BoundWebhookTree, m as CorsairClient, q as CorsairContext, r as CorsairEndpoint, t as CorsairErrorHandler, c as CorsairIntegration, J as CorsairKeyBuilder, K as CorsairKeyBuilderBase, a7 as CorsairOAuthWebhookTenantLinkResolver, z as CorsairPermissionsNamespace, C as CorsairPlugin, L as CorsairPluginContext, M as CorsairPluginSubscribe, e as CorsairSingleTenantClient, d as CorsairTenantWrapper, a8 as CorsairWebhook, a9 as CorsairWebhookHandler, aa as CorsairWebhookMatcher, ab as CorsairWebhookTenantMatcher, N as EndpointHooks, Q as EndpointMetaEntry, E as EndpointPathsOf, S as EndpointRiskLevel, s as EndpointTree, D as EnforcePermissionOptions, F as EnforcePermissionResult, u as ErrorContext, v as ErrorHandler, w as ErrorHandlerAndMatchFunction, x as ErrorMatcher, i as IntegrationFieldNames, U as KeyBuilderContext, j as OAuth2IntegrationCredentials, O as OAuthConfig, V as PermissionMode, X as PermissionPolicy, P as PluginAuthConfig, Y as PluginEndpointMeta, Z as PluginPermissionsConfig, ac as RawWebhookRequest, _ as RequiredPluginEndpointMeta, $ as RequiredPluginEndpointSchemas, a0 as RequiredPluginWebhookSchemas, R as RetryStrategies, y as RetryStrategy, T as TokenResponse, a3 as UnionToIntersection, a1 as WebhookHooks, ad as WebhookPathsOf, ae as WebhookRequest, af as WebhookResponse, W as WebhookTenantMatch, ag as WebhookTree, l as exchangeCodeForTokens } from './index-Zg8W-Gnw.js';
5
- export { A as AuthMissingError, D as DocSchemaFieldRow, a as DocSchemaShape, b as DocsApiEndpoint, c as DocsDbEntity, d as DocsDbFilterField, e as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, n as extractMicrosoftGraphValidationToken, o as firstString, f as formatDocSchemaShape, p as getHeader, i as introspectPluginForDocs, q as isMicrosoftGraphValidationHandshake, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, t as readQueryParam, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-VaW1D4fv.js';
3
+ import { A as AccountKeyManagerFor, I as IntegrationKeyManagerFor, f as CorsairPluginSubscribeResult } from './index-DwegPGYj.js';
4
+ export { g as AccountFieldNames, k as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, h as BaseKeyManager, M as BeforeHookResult, n as BindEndpoints, a8 as BindWebhooks, a6 as Bivariant, o as BoundEndpointFn, p as BoundEndpointTree, a9 as BoundWebhook, aa as BoundWebhookTree, m as CorsairClient, q as CorsairContext, r as CorsairEndpoint, t as CorsairErrorHandler, c as CorsairIntegration, N as CorsairKeyBuilder, Q as CorsairKeyBuilderBase, ab as CorsairOAuthWebhookTenantLinkResolver, z as CorsairPermissionsNamespace, C as CorsairPlugin, S as CorsairPluginContext, U as CorsairPluginSubscribe, e as CorsairSingleTenantClient, d as CorsairTenantWrapper, ac as CorsairWebhook, ad as CorsairWebhookHandler, ae as CorsairWebhookMatcher, af as CorsairWebhookTenantMatcher, V as EndpointHooks, X as EndpointMetaEntry, E as EndpointPathsOf, Y as EndpointRiskLevel, s as EndpointTree, D as EnforcePermissionOptions, F as EnforcePermissionResult, u as ErrorContext, v as ErrorHandler, w as ErrorHandlerAndMatchFunction, x as ErrorMatcher, i as IntegrationFieldNames, Z as KeyBuilderContext, j as OAuth2IntegrationCredentials, O as OAuthConfig, _ as PermissionMode, $ as PermissionPolicy, P as PluginAuthConfig, a0 as PluginEndpointMeta, a1 as PluginPermissionsConfig, ag as RawWebhookRequest, K as ReadonlyForbiddenError, a2 as RequiredPluginEndpointMeta, a3 as RequiredPluginEndpointSchemas, a4 as RequiredPluginWebhookSchemas, R as RetryStrategies, y as RetryStrategy, T as TokenResponse, a7 as UnionToIntersection, a5 as WebhookHooks, ah as WebhookPathsOf, ai as WebhookRequest, aj as WebhookResponse, W as WebhookTenantMatch, ak as WebhookTree, G as assertReadonlyAllowed, l as exchangeCodeForTokens, J as isReadonlyScopeActive, L as runReadonly } from './index-DwegPGYj.js';
5
+ export { A as AuthMissingError, D as DocSchemaFieldRow, a as DocSchemaShape, b as DocsApiEndpoint, c as DocsDbEntity, d as DocsDbFilterField, e as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, n as extractMicrosoftGraphValidationToken, o as firstString, f as formatDocSchemaShape, p as getHeader, i as introspectPluginForDocs, q as isMicrosoftGraphValidationHandshake, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, t as readQueryParam, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-f49OxmPU.js';
6
6
  import { A as AuthTypes } from './types-1nBbBn-U.js';
7
7
  export { g as AllProviders, B as BaseProviders, h as PickAuth, j as ProviderDisplayNames, i as formatProviderDisplayName } from './types-1nBbBn-U.js';
8
8
  import 'kysely';
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{Ab as F,B as d,Bb as G,C as e,Cb as H,D as f,Db as I,E as g,Eb as J,F as h,Fb as K,G as i,Gb as L,H as j,Hb as M,I as k,J as l,K as m,L as n,M as o,Oa as q,a,b,ja as p,jb as r,kb as s,lb as t,pb as u,qb as v,rb as w,sb as x,tb as y,ub as z,vb as A,wb as B,xb as C,yb as D,zb as E}from"./chunk-2FHSN2ZY.js";import{h as c}from"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,L as CORSAIR_INTERNAL,x as MS_GRAPH_API_BASE,a as ProviderDisplayNames,E as asRecord,B as collectPluginWebhookMatchers,m as createAccountKeyManager,M as createCorsair,l as createIntegrationKeyManager,K as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,H as extractMicrosoftGraphValidationToken,J as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,C as getHeader,w as googleChannelSubscribe,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,I as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,z as matchWebhookPlugin,A as matchWebhookPluginAndTenant,y as msGraphSubscribe,k as reEncryptConfig,F as readBodyRecord,G as readQueryParam,p as resolveConnectLink,D as toExternalId};
1
+ import{Ab as F,B as d,Bb as G,C as e,Cb as H,D as f,Db as I,E as g,Eb as J,F as h,Fb as K,G as i,Gb as L,H as j,Hb as M,I as k,Ib as N,J as l,Jb as O,K as m,Kb as P,L as n,Lb as Q,M as o,Sa as u,a,b,ja as p,ma as q,na as r,nb as v,oa as s,ob as w,pa as t,pb as x,tb as y,ub as z,vb as A,wb as B,xb as C,yb as D,zb as E}from"./chunk-6WGGD3SS.js";import{h as c}from"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{u as AuthMissingError,c as BASE_AUTH_FIELDS,P as CORSAIR_INTERNAL,B as MS_GRAPH_API_BASE,a as ProviderDisplayNames,q as ReadonlyForbiddenError,I as asRecord,t as assertReadonlyAllowed,F as collectPluginWebhookMatchers,m as createAccountKeyManager,Q as createCorsair,l as createIntegrationKeyManager,O as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,x as exchangeCodeForTokens,L as extractMicrosoftGraphValidationToken,N as firstString,y as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,G as getHeader,A as googleChannelSubscribe,o as initializeAccountDEK,n as initializeIntegrationDEK,z as introspectPluginForDocs,M as isMicrosoftGraphValidationHandshake,s as isReadonlyScopeActive,v as logEvent,w as logEventFromContext,D as matchWebhookPlugin,E as matchWebhookPluginAndTenant,C as msGraphSubscribe,k as reEncryptConfig,J as readBodyRecord,K as readQueryParam,p as resolveConnectLink,r as runReadonly,H as toExternalId};
package/dist/hub.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { A as AuthTypes } from './types-1nBbBn-U.js';
2
2
  export { i as formatProviderDisplayName } from './types-1nBbBn-U.js';
3
- import { ai as HubOAuthMode, aj as HubConnectSessionResult, ak as HubPermissionSessionResult, H as HubConfig, al as HubConfigInput, am as HubConnectSessionInput, an as HubListProjectConnectionsInput, A as AccountKeyManagerFor, ao as HubPermissionSessionInput } from './index-Zg8W-Gnw.js';
4
- export { ap as DEFAULT_HUB_API_URL, aq as HubEnvironmentSlug } from './index-Zg8W-Gnw.js';
5
- import { g as TunnelType, c as ProcessCorsairRequest, h as WebhookTenantLink } from './index-CXNdPXR3.js';
6
- export { i as BROWSER_DELIVERY_TTL_MS, j as BrowserDeliveryMode, B as BrowserDeliveryPayload, S as SIGNED_TUNNEL_REPLAY_WINDOW_MS, f as TunnelEnvelope } from './index-CXNdPXR3.js';
7
- export { b as buildBrowserDeliveryRedirectUrl, s as signBrowserDeliveryToken, v as verifyBrowserDeliveryToken } from './browser-delivery-DEaQVGsf.js';
3
+ import { am as HubOAuthMode, an as HubConnectSessionResult, ao as HubPermissionSessionResult, H as HubConfig, ap as HubConfigInput, aq as HubConnectSessionInput, ar as HubListProjectConnectionsInput, A as AccountKeyManagerFor, as as HubPermissionSessionInput } from './index-DwegPGYj.js';
4
+ export { at as DEFAULT_HUB_API_URL, au as HubEnvironmentSlug } from './index-DwegPGYj.js';
5
+ import { g as TunnelType, c as ProcessCorsairRequest, h as WebhookTenantLink } from './index-CdzrawUJ.js';
6
+ export { i as BROWSER_DELIVERY_TTL_MS, j as BrowserDeliveryMode, B as BrowserDeliveryPayload, S as SIGNED_TUNNEL_REPLAY_WINDOW_MS, f as TunnelEnvelope } from './index-CdzrawUJ.js';
7
+ export { b as buildBrowserDeliveryRedirectUrl, s as signBrowserDeliveryToken, v as verifyBrowserDeliveryToken } from './browser-delivery-ARqe7lph.js';
8
8
  import './index-eydqYIn0.js';
9
9
  import 'zod';
10
10
  import './db.js';
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$a as la,A as z,Aa as U,Ia as V,Ja as W,Ka as X,La as Y,Ma as Z,Na as _,P as A,Pa as $,Qa as aa,Ra as ba,Sa as ca,Ta as da,Ua as ea,Va as fa,Wa as ga,Xa as ha,Ya as ia,Za as ja,_a as ka,ab as ma,b as a,bb as na,c as b,cb as oa,d as c,db as pa,e as d,eb as qa,f as e,g as f,ga as B,h as g,ha as C,i as h,ia as D,j as i,k as j,ka as E,l as k,la as F,m as l,ma as G,n as m,na as H,o as n,oa as I,p as o,pa as J,q as p,qa as K,r as q,ra as L,s as r,sa as M,t as s,ta as N,u as t,ua as O,v as u,va as P,w as v,wa as Q,x as w,xa as R,y as x,ya as S,z as y,za as T}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{f as BROWSER_DELIVERY_TTL_MS,n as DEFAULT_HUB_API_URL,o as HubNotConfiguredError,T as ManagedOAuthDeliveryError,g as SIGNED_TUNNEL_REPLAY_WINDOW_MS,aa as attachManagedRefreshAuth,i as buildBrowserDeliveryRedirectUrl,l as buildClientBridgeBrowserDeliveryUrl,ca as createConnectSessionJti,ha as createConnectTokenJti,B as createHubConnectSession,E as createHubPermissionSession,ba as createHubRouteHandlers,na as createPermissionSessionJti,h as createSignedTokenJti,ga as decodeConnectSessionTokenFromPath,ma as decodeConnectTokenFromPath,qa as decodePermissionTokenFromPath,O as deliverConnectCreateLink,S as deliverSignedEnvelope,Q as describeDeliveryNetworkError,la as encodeConnectTokenForPath,M as extractConnectLinkFromDeliveryAck,L as extractSyncFromDeliveryAck,F as formatHubApprovalMessage,a as formatProviderDisplayName,R as formatServerDeliveryError,da as getConnectSessionExpiryMs,C as getConnectStatusForTenant,ia as getConnectTokenExpiryMs,q as getHubConfig,$ as getManagedAccessToken,V as handleHubDeliveryGet,W as handleHubDeliveryPost,Y as handleHubDeliveryRequest,X as hubDeliveryToResponse,s as inferHubEnvironmentSlug,b as isLoopbackUrl,K as isServerDeliveryAckSuccessful,D as listHubProjectConnections,p as normalizeHubConfig,N as parseConnectLinkFromDeliveryBody,t as parseConnectSessionResponse,x as parseConnectStatusResponse,y as parseHubApiErrorBody,w as parseOAuthRefreshResponse,v as parsePermissionSessionResponse,u as parseProjectConnectionsResponse,J as parseServerDeliveryAckBody,P as parseSyncFromDeliveryBody,m as prepareClientBridgeDeliveryTransport,U as processManagedOAuthDelivery,A as registerHubWebhookTenantLink,c as resolveDeliveryTransport,z as resolveHubDeliveryUrl,r as resolveHubOAuthCallbackUrl,Z as respondToHubDelivery,_ as respondToHubDeliveryFromRequest,j as signBrowserDeliveryToken,ea as signConnectSessionToken,ja as signConnectToken,G as signDeliveryEnvelope,oa as signPermissionToken,d as usesBrowserDelivery,e as validateProductionDeliveryUrl,k as verifyBrowserDeliveryToken,fa as verifyConnectSessionToken,ka as verifyConnectToken,H as verifyDeliveryEnvelope,pa as verifyPermissionToken,I as verifySignedTunnelDelivery};
1
+ import{$a as ha,A as z,Aa as Q,Ba as R,Ca as S,Da as T,Ea as U,Ma as V,Na as W,Oa as X,P as A,Pa as Y,Qa as Z,Ra as _,Ta as $,Ua as aa,Va as ba,Wa as ca,Xa as da,Ya as ea,Za as fa,_a as ga,ab as ia,b as a,bb as ja,c as b,cb as ka,d as c,db as la,e as d,eb as ma,f as e,fb as na,g as f,ga as B,gb as oa,h as g,ha as C,hb as pa,i as h,ia as D,ib as qa,j as i,k as j,ka as E,l as k,la as F,m as l,n as m,o as n,p as o,q as p,qa as G,r as q,ra as H,s as r,sa as I,t as s,ta as J,u as t,ua as K,v as u,va as L,w as v,wa as M,x as w,xa as N,y as x,ya as O,z as y,za as P}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{f as BROWSER_DELIVERY_TTL_MS,n as DEFAULT_HUB_API_URL,o as HubNotConfiguredError,T as ManagedOAuthDeliveryError,g as SIGNED_TUNNEL_REPLAY_WINDOW_MS,aa as attachManagedRefreshAuth,i as buildBrowserDeliveryRedirectUrl,l as buildClientBridgeBrowserDeliveryUrl,ca as createConnectSessionJti,ha as createConnectTokenJti,B as createHubConnectSession,E as createHubPermissionSession,ba as createHubRouteHandlers,na as createPermissionSessionJti,h as createSignedTokenJti,ga as decodeConnectSessionTokenFromPath,ma as decodeConnectTokenFromPath,qa as decodePermissionTokenFromPath,O as deliverConnectCreateLink,S as deliverSignedEnvelope,Q as describeDeliveryNetworkError,la as encodeConnectTokenForPath,M as extractConnectLinkFromDeliveryAck,L as extractSyncFromDeliveryAck,F as formatHubApprovalMessage,a as formatProviderDisplayName,R as formatServerDeliveryError,da as getConnectSessionExpiryMs,C as getConnectStatusForTenant,ia as getConnectTokenExpiryMs,q as getHubConfig,$ as getManagedAccessToken,V as handleHubDeliveryGet,W as handleHubDeliveryPost,Y as handleHubDeliveryRequest,X as hubDeliveryToResponse,s as inferHubEnvironmentSlug,b as isLoopbackUrl,K as isServerDeliveryAckSuccessful,D as listHubProjectConnections,p as normalizeHubConfig,N as parseConnectLinkFromDeliveryBody,t as parseConnectSessionResponse,x as parseConnectStatusResponse,y as parseHubApiErrorBody,w as parseOAuthRefreshResponse,v as parsePermissionSessionResponse,u as parseProjectConnectionsResponse,J as parseServerDeliveryAckBody,P as parseSyncFromDeliveryBody,m as prepareClientBridgeDeliveryTransport,U as processManagedOAuthDelivery,A as registerHubWebhookTenantLink,c as resolveDeliveryTransport,z as resolveHubDeliveryUrl,r as resolveHubOAuthCallbackUrl,Z as respondToHubDelivery,_ as respondToHubDeliveryFromRequest,j as signBrowserDeliveryToken,ea as signConnectSessionToken,ja as signConnectToken,G as signDeliveryEnvelope,oa as signPermissionToken,d as usesBrowserDelivery,e as validateProductionDeliveryUrl,k as verifyBrowserDeliveryToken,fa as verifyConnectSessionToken,ka as verifyConnectToken,H as verifyDeliveryEnvelope,pa as verifyPermissionToken,I as verifySignedTunnelDelivery};
@@ -1,5 +1,5 @@
1
1
  import { A as AuthTypes } from './types-1nBbBn-U.js';
2
- import { W as WebhookTenantMatch } from './index-Zg8W-Gnw.js';
2
+ import { W as WebhookTenantMatch } from './index-DwegPGYj.js';
3
3
  import { a as CorsairAccount } from './index-eydqYIn0.js';
4
4
  import { CorsairDatabase } from './db.js';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { CorsairDatabase } from './db.js';
2
- import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, H as HubConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-Zg8W-Gnw.js';
2
+ import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, H as HubConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-DwegPGYj.js';
3
3
 
4
4
  declare const CORSAIR_INTERNAL: unique symbol;
5
5
  type CorsairInternalConfig = {
@@ -346,6 +346,30 @@ type CorsairManageNamespace = {
346
346
  };
347
347
  };
348
348
 
349
+ /**
350
+ * Thrown when a write or destructive operation is attempted inside a
351
+ * {@link runReadonly} scope. Aborts the whole script so the agent must retry with
352
+ * read-only operations only — no permission record is created.
353
+ */
354
+ declare class ReadonlyForbiddenError extends Error {
355
+ readonly endpointPath: string;
356
+ readonly riskLevel: EndpointRiskLevel;
357
+ constructor(endpointPath: string, riskLevel: EndpointRiskLevel);
358
+ }
359
+ /**
360
+ * Runs `fn` in a scope where every Corsair endpoint call is forced to read-only.
361
+ * Any write/destructive endpoint invoked within (including in nested async calls)
362
+ * throws {@link ReadonlyForbiddenError}.
363
+ */
364
+ declare function runReadonly<T>(fn: () => T): T;
365
+ /** Whether the current async context is inside a {@link runReadonly} scope. */
366
+ declare function isReadonlyScopeActive(): boolean;
367
+ /**
368
+ * Guard invoked by the endpoint binding layer before any endpoint runs. When a
369
+ * read-only scope is active and the endpoint is not a `read` operation, throws
370
+ * {@link ReadonlyForbiddenError}. No-op otherwise.
371
+ */
372
+ declare function assertReadonlyAllowed(endpointPath: string, riskLevel: EndpointRiskLevel): void;
349
373
  /**
350
374
  * The `corsair.permissions` namespace available at the root of every corsair instance.
351
375
  * Provides methods for querying and transitioning permission records.
@@ -1336,4 +1360,4 @@ type CorsairDeprecatedApprovalConfig = {
1336
1360
  approval?: CorsairPermissionsOptions;
1337
1361
  };
1338
1362
 
1339
- export { type RequiredPluginEndpointSchemas as $, type AccountKeyManagerFor as A, type BaseAuthFieldConfig as B, type CorsairPlugin as C, type EnforcePermissionOptions as D, type EndpointPathsOf as E, type EnforcePermissionResult as F, type BeforeHookResult as G, type HubConfig as H, type IntegrationKeyManagerFor as I, type CorsairKeyBuilder as J, type CorsairKeyBuilderBase as K, type CorsairPluginContext as L, type CorsairPluginSubscribe as M, type EndpointHooks as N, type OAuthConfig as O, type PluginAuthConfig as P, type EndpointMetaEntry as Q, type RetryStrategies as R, type EndpointRiskLevel as S, type TokenResponse as T, type KeyBuilderContext as U, type PermissionMode as V, type WebhookTenantMatch as W, type PermissionPolicy as X, type PluginEndpointMeta as Y, type PluginPermissionsConfig as Z, type RequiredPluginEndpointMeta as _, type CorsairPermissionsOptions as a, type RequiredPluginWebhookSchemas as a0, type WebhookHooks as a1, type Bivariant$2 as a2, type UnionToIntersection$1 as a3, type BindWebhooks as a4, type BoundWebhook as a5, type BoundWebhookTree as a6, type CorsairOAuthWebhookTenantLinkResolver as a7, type CorsairWebhook as a8, type CorsairWebhookHandler as a9, type CorsairWebhookMatcher as aa, type CorsairWebhookTenantMatcher as ab, type RawWebhookRequest as ac, type WebhookPathsOf as ad, type WebhookRequest as ae, type WebhookResponse as af, type WebhookTree as ag, type CorsairManageNamespace as ah, type HubOAuthMode as ai, type HubConnectSessionResult as aj, type HubPermissionSessionResult as ak, type HubConfigInput as al, type HubConnectSessionInput as am, type HubListProjectConnectionsInput as an, type HubPermissionSessionInput as ao, DEFAULT_HUB_API_URL as ap, type HubEnvironmentSlug as aq, type CorsairManualConfig as b, type CorsairIntegration as c, type CorsairTenantWrapper as d, type CorsairSingleTenantClient as e, type CorsairPluginSubscribeResult as f, type AccountFieldNames as g, type BaseKeyManager as h, type IntegrationFieldNames as i, type OAuth2IntegrationCredentials as j, BASE_AUTH_FIELDS as k, exchangeCodeForTokens as l, type CorsairClient as m, type BindEndpoints as n, type BoundEndpointFn as o, type BoundEndpointTree as p, type CorsairContext as q, type CorsairEndpoint as r, type EndpointTree as s, type CorsairErrorHandler as t, type ErrorContext as u, type ErrorHandler as v, type ErrorHandlerAndMatchFunction as w, type ErrorMatcher as x, type RetryStrategy as y, type CorsairPermissionsNamespace as z };
1363
+ export { type PermissionPolicy as $, type AccountKeyManagerFor as A, type BaseAuthFieldConfig as B, type CorsairPlugin as C, type EnforcePermissionOptions as D, type EndpointPathsOf as E, type EnforcePermissionResult as F, assertReadonlyAllowed as G, type HubConfig as H, type IntegrationKeyManagerFor as I, isReadonlyScopeActive as J, ReadonlyForbiddenError as K, runReadonly as L, type BeforeHookResult as M, type CorsairKeyBuilder as N, type OAuthConfig as O, type PluginAuthConfig as P, type CorsairKeyBuilderBase as Q, type RetryStrategies as R, type CorsairPluginContext as S, type TokenResponse as T, type CorsairPluginSubscribe as U, type EndpointHooks as V, type WebhookTenantMatch as W, type EndpointMetaEntry as X, type EndpointRiskLevel as Y, type KeyBuilderContext as Z, type PermissionMode as _, type CorsairPermissionsOptions as a, type PluginEndpointMeta as a0, type PluginPermissionsConfig as a1, type RequiredPluginEndpointMeta as a2, type RequiredPluginEndpointSchemas as a3, type RequiredPluginWebhookSchemas as a4, type WebhookHooks as a5, type Bivariant$2 as a6, type UnionToIntersection$1 as a7, type BindWebhooks as a8, type BoundWebhook as a9, type BoundWebhookTree as aa, type CorsairOAuthWebhookTenantLinkResolver as ab, type CorsairWebhook as ac, type CorsairWebhookHandler as ad, type CorsairWebhookMatcher as ae, type CorsairWebhookTenantMatcher as af, type RawWebhookRequest as ag, type WebhookPathsOf as ah, type WebhookRequest as ai, type WebhookResponse as aj, type WebhookTree as ak, type CorsairManageNamespace as al, type HubOAuthMode as am, type HubConnectSessionResult as an, type HubPermissionSessionResult as ao, type HubConfigInput as ap, type HubConnectSessionInput as aq, type HubListProjectConnectionsInput as ar, type HubPermissionSessionInput as as, DEFAULT_HUB_API_URL as at, type HubEnvironmentSlug as au, type CorsairManualConfig as b, type CorsairIntegration as c, type CorsairTenantWrapper as d, type CorsairSingleTenantClient as e, type CorsairPluginSubscribeResult as f, type AccountFieldNames as g, type BaseKeyManager as h, type IntegrationFieldNames as i, type OAuth2IntegrationCredentials as j, BASE_AUTH_FIELDS as k, exchangeCodeForTokens as l, type CorsairClient as m, type BindEndpoints as n, type BoundEndpointFn as o, type BoundEndpointTree as p, type CorsairContext as q, type CorsairEndpoint as r, type EndpointTree as s, type CorsairErrorHandler as t, type ErrorContext as u, type ErrorHandler as v, type ErrorHandlerAndMatchFunction as w, type ErrorMatcher as x, type RetryStrategy as y, type CorsairPermissionsNamespace as z };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { C as CorsairClientOptions, a as CorsairManagementClient } from './types-DvDEtIUw.js';
2
2
  export { b as CorsairClientError } from './types-DvDEtIUw.js';
3
- export { c as createCorsair } from './index-DePcixJK.js';
4
- import { e as CorsairSingleTenantClient, C as CorsairPlugin, d as CorsairTenantWrapper, m as CorsairClient, z as CorsairPermissionsNamespace, a6 as BoundWebhookTree, ac as RawWebhookRequest, ab as CorsairWebhookTenantMatcher, af as WebhookResponse } from './index-Zg8W-Gnw.js';
5
- export { ah as CorsairManageNamespace, b as CorsairManualConfig, a as CorsairPermissionsOptions } from './index-Zg8W-Gnw.js';
6
- import { F as FormFieldSchema, L as ListOperationsOptions } from './tenant-match-utils-VaW1D4fv.js';
7
- export { A as AuthMissingError, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, o as firstString, f as formatDocSchemaShape, p as getHeader, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-VaW1D4fv.js';
3
+ export { c as createCorsair } from './index-D7aqzKjb.js';
4
+ import { e as CorsairSingleTenantClient, C as CorsairPlugin, d as CorsairTenantWrapper, m as CorsairClient, z as CorsairPermissionsNamespace, aa as BoundWebhookTree, ag as RawWebhookRequest, af as CorsairWebhookTenantMatcher, aj as WebhookResponse } from './index-DwegPGYj.js';
5
+ export { al as CorsairManageNamespace, b as CorsairManualConfig, a as CorsairPermissionsOptions, K as ReadonlyForbiddenError, L as runReadonly } from './index-DwegPGYj.js';
6
+ import { F as FormFieldSchema, L as ListOperationsOptions } from './tenant-match-utils-f49OxmPU.js';
7
+ export { A as AuthMissingError, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, o as firstString, f as formatDocSchemaShape, p as getHeader, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-f49OxmPU.js';
8
8
  export { SetupCorsairOptions, setupCorsair } from './setup.js';
9
- export { O as OAuthCallbackTunnelPayload, P as ProcessCorsairOptions, c as ProcessCorsairRequest, R as ResolveAccountFromWebhookLinkInput, T as TunnelAck, f as TunnelEnvelope, g as TunnelType, h as WebhookTenantLink, W as WebhookTunnelPayload, p as processCorsair, r as resolveAccountFromWebhookLink, d as resolveTenantFromWebhookLink, e as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './index-CXNdPXR3.js';
9
+ export { O as OAuthCallbackTunnelPayload, P as ProcessCorsairOptions, c as ProcessCorsairRequest, R as ResolveAccountFromWebhookLinkInput, T as TunnelAck, f as TunnelEnvelope, g as TunnelType, h as WebhookTenantLink, W as WebhookTunnelPayload, p as processCorsair, r as resolveAccountFromWebhookLink, d as resolveTenantFromWebhookLink, e as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './index-CdzrawUJ.js';
10
10
  import { B as BaseProviders } from './types-1nBbBn-U.js';
11
11
  export { c as ConnectLink, a as ConnectionStatus, d as CreateConnectLinkInput, C as CreateTenantInput, M as ManagementOk, e as OAuthCallbackInput, O as OAuthCallbackResult, f as PermissionLookupInput, b as PermissionRecord, k as PluginConnectionState, P as PluginInfo, R as ResolvedConnectLink, T as Tenant } from './types-1nBbBn-U.js';
12
12
  import './db.js';
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{a as N,b as j}from"./chunk-XLNT2UI2.js";import{Ab as $,Ba as S,Eb as M,Fb as D,Gb as g,Ha as w,Hb as H,Oa as I,Q as y,R as h,S as k,T as x,_ as P,fb as O,gb as R,hb as T,ib as A,ja as b,mb as l,nb as c,ob as d,pb as m,ub as L,vb as W,wb as F,xb as v,yb as E,zb as _}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";function s(n){let t=n[g];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function B(n,t){let r=c(s(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
1
+ import{a as B,b as J}from"./chunk-XLNT2UI2.js";import{Ab as E,Bb as _,Cb as $,Db as M,Eb as D,Fa as I,Ib as H,Jb as N,Kb as g,La as O,Lb as j,Q as y,R as h,S as k,Sa as R,T as x,_ as P,ja as b,jb as T,kb as A,lb as L,ma as S,mb as F,na as w,qb as l,rb as c,sb as d,tb as m,yb as W,zb as v}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";function s(n){let t=n[g];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function q(n,t){let r=c(s(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
2
2
  `):Object.values(r).flat().join(`
3
- `)}function J(n,t){return d(s(n),t)}function q(n,t){return l(s(n),t)}var Y=Symbol.for("corsair:internal");function z(n,t){let r=n;for(let e of t){if(!r||typeof r!="object")return null;r=r[e]}return typeof r=="function"?r:null}function C(n){return n[Y]?.database}async function G(n,t){let r=new Date().toISOString(),e=await n.permissions.find_by_token(t);if(!e)return console.error("executePermission: no permission found for token."),{error:"executePermission: no permission found for token."};if(e.status!=="approved")return console.error(`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`};if(e.expires_at<r){let o=C(n);return o&&await o.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",e.id).execute(),console.error(`executePermission: permission '${e.id}' has expired.`),{error:`executePermission: permission '${e.id}' has expired.`,endpoint:e.endpoint,plugin:e.plugin,result:null}}let f=e.tenant_id??"default",a=(n.withTenant?n.withTenant(f):n)[e.plugin];if(!a?.api)return console.error(`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`),{error:`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`,plugin:e.plugin,endpoint:e.endpoint,result:null};let p=z(a.api,e.endpoint.split("."));if(!p)return console.error(`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`};await n.permissions.set_executing(e.id);try{let o=typeof e.args=="string"?JSON.parse(e.args):e.args,i=await p(o);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:i}}catch(o){let i=o instanceof Error?o.message:String(o),u=C(n);return u&&await u.db.updateTable("corsair_permissions").set({status:"failed",error:i,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:i}}}export{I as AuthMissingError,N as CorsairClientError,_ as asRecord,F as collectPluginWebhookMatchers,H as createCorsair,j as createCorsairClient,D as decodePubSubData,G as executePermission,M as firstString,m as formatDocSchemaShape,v as getHeader,J as getSchema,q as getStructuredSchema,B as listOperations,O as managementHandler,L as matchWebhookPlugin,W as matchWebhookPluginAndTenant,w as processCorsair,S as processWebhook,$ as readBodyRecord,h as resolveAccountFromWebhookLink,b as resolveConnectLink,x as resolveTenantFromWebhookLink,k as resolveTenantIdFromWebhookLink,y as setWebhookTenantLink,P as setupCorsair,R as toExpressHandler,E as toExternalId,T as toHonoHandler,A as toNextJsHandler};
3
+ `)}function Y(n,t){return d(s(n),t)}function z(n,t){return l(s(n),t)}var G=Symbol.for("corsair:internal");function K(n,t){let r=n;for(let e of t){if(!r||typeof r!="object")return null;r=r[e]}return typeof r=="function"?r:null}function C(n){return n[G]?.database}async function Q(n,t){let r=new Date().toISOString(),e=await n.permissions.find_by_token(t);if(!e)return console.error("executePermission: no permission found for token."),{error:"executePermission: no permission found for token."};if(e.status!=="approved")return console.error(`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`};if(e.expires_at<r){let o=C(n);return o&&await o.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",e.id).execute(),console.error(`executePermission: permission '${e.id}' has expired.`),{error:`executePermission: permission '${e.id}' has expired.`,endpoint:e.endpoint,plugin:e.plugin,result:null}}let f=e.tenant_id??"default",a=(n.withTenant?n.withTenant(f):n)[e.plugin];if(!a?.api)return console.error(`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`),{error:`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`,plugin:e.plugin,endpoint:e.endpoint,result:null};let p=K(a.api,e.endpoint.split("."));if(!p)return console.error(`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`};await n.permissions.set_executing(e.id);try{let o=typeof e.args=="string"?JSON.parse(e.args):e.args,i=await p(o);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:i}}catch(o){let i=o instanceof Error?o.message:String(o),u=C(n);return u&&await u.db.updateTable("corsair_permissions").set({status:"failed",error:i,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:i}}}export{R as AuthMissingError,B as CorsairClientError,S as ReadonlyForbiddenError,M as asRecord,E as collectPluginWebhookMatchers,j as createCorsair,J as createCorsairClient,N as decodePubSubData,Q as executePermission,H as firstString,m as formatDocSchemaShape,_ as getHeader,Y as getSchema,z as getStructuredSchema,q as listOperations,T as managementHandler,W as matchWebhookPlugin,v as matchWebhookPluginAndTenant,O as processCorsair,I as processWebhook,D as readBodyRecord,h as resolveAccountFromWebhookLink,b as resolveConnectLink,x as resolveTenantFromWebhookLink,k as resolveTenantIdFromWebhookLink,w as runReadonly,y as setWebhookTenantLink,P as setupCorsair,A as toExpressHandler,$ as toExternalId,L as toHonoHandler,F as toNextJsHandler};
package/dist/oauth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { O as OAuthConfig } from './index-Zg8W-Gnw.js';
1
+ import { O as OAuthConfig } from './index-DwegPGYj.js';
2
2
  import 'zod';
3
3
  import './db.js';
4
4
  import 'kysely';
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{N as a,O as b,U as c,V as d,W as e,X as f,Y as g,Z as h}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{d as OAuthCallbackError,c as buildOAuthAuthorizeUrl,b as decodeOAuthState,a as encodeOAuthState,e as generateOAuthUrl,f as processOAuthCallback,g as renewSubscriptions,h as startSubscriptionRenewal};
1
+ import{N as a,O as b,U as c,V as d,W as e,X as f,Y as g,Z as h}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{d as OAuthCallbackError,c as buildOAuthAuthorizeUrl,b as decodeOAuthState,a as encodeOAuthState,e as generateOAuthUrl,f as processOAuthCallback,g as renewSubscriptions,h as startSubscriptionRenewal};
@@ -1 +1 @@
1
- import{$ as b,_ as a}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{$ as b,_ as a}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
@@ -1 +1 @@
1
- import{aa as a,ba as b,ca as c,da as d}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as buildConnectPluginManifest,a as buildConnectPluginManifestFromContext,d as ensureConnectAccountRows,c as ensureConnectAccountRowsFromContext};
1
+ import{aa as a,ba as b,ca as c,da as d}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as buildConnectPluginManifest,a as buildConnectPluginManifestFromContext,d as ensureConnectAccountRows,c as ensureConnectAccountRowsFromContext};
package/dist/setup.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as CorsairInternalConfig } from './index-DePcixJK.js';
1
+ import { a as CorsairInternalConfig } from './index-D7aqzKjb.js';
2
2
  import { CorsairDatabase } from './db.js';
3
- import { C as CorsairPlugin, e as CorsairSingleTenantClient, d as CorsairTenantWrapper } from './index-Zg8W-Gnw.js';
3
+ import { C as CorsairPlugin, e as CorsairSingleTenantClient, d as CorsairTenantWrapper } from './index-DwegPGYj.js';
4
4
  import 'kysely';
5
5
  import './index-eydqYIn0.js';
6
6
  import 'zod';
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{$ as b,_ as a}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{$ as b,_ as a}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
@@ -1,4 +1,4 @@
1
- import { S as EndpointRiskLevel, C as CorsairPlugin, aa as CorsairWebhookMatcher, ab as CorsairWebhookTenantMatcher, ac as RawWebhookRequest, W as WebhookTenantMatch } from './index-Zg8W-Gnw.js';
1
+ import { Y as EndpointRiskLevel, C as CorsairPlugin, ae as CorsairWebhookMatcher, af as CorsairWebhookTenantMatcher, ag as RawWebhookRequest, W as WebhookTenantMatch } from './index-DwegPGYj.js';
2
2
  import { g as AllProviders } from './types-1nBbBn-U.js';
3
3
 
4
4
  /**
package/dist/tunnel.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { B as BrowserDeliveryPayload } from './index-CXNdPXR3.js';
2
- export { O as OAuthCallbackTunnelPayload, b as OAuthTokensTunnelPayload, P as ProcessCorsairOptions, c as ProcessCorsairRequest, T as TunnelAck, f as TunnelEnvelope, g as TunnelType, W as WebhookTunnelPayload, a as applyPermissionDecision, p as processCorsair, r as resolveAccountFromWebhookLink, d as resolveTenantFromWebhookLink, e as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './index-CXNdPXR3.js';
3
- export { v as verifyBrowserDeliveryToken } from './browser-delivery-DEaQVGsf.js';
1
+ import { B as BrowserDeliveryPayload } from './index-CdzrawUJ.js';
2
+ export { O as OAuthCallbackTunnelPayload, b as OAuthTokensTunnelPayload, P as ProcessCorsairOptions, c as ProcessCorsairRequest, T as TunnelAck, f as TunnelEnvelope, g as TunnelType, W as WebhookTunnelPayload, a as applyPermissionDecision, p as processCorsair, r as resolveAccountFromWebhookLink, d as resolveTenantFromWebhookLink, e as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './index-CdzrawUJ.js';
3
+ export { v as verifyBrowserDeliveryToken } from './browser-delivery-ARqe7lph.js';
4
4
  import './types-1nBbBn-U.js';
5
5
  import './index-eydqYIn0.js';
6
6
  import 'zod';
7
- import './index-Zg8W-Gnw.js';
7
+ import './index-DwegPGYj.js';
8
8
  import './db.js';
9
9
  import 'kysely';
10
10
  import 'pg';
package/dist/tunnel.js CHANGED
@@ -1 +1 @@
1
- import{Ca as f,Da as g,Ea as h,Fa as i,Ga as j,Ha as k,Q as b,R as c,S as d,T as e,l as a}from"./chunk-2FHSN2ZY.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{j as applyPermissionDecision,f as isAuthCredentialsBrowserDelivery,i as isByoOAuthBrowserDelivery,h as isManagedBrowserDelivery,g as isPermissionBrowserDelivery,k as processCorsair,c as resolveAccountFromWebhookLink,e as resolveTenantFromWebhookLink,d as resolveTenantIdFromWebhookLink,b as setWebhookTenantLink,a as verifyBrowserDeliveryToken};
1
+ import{Ga as f,Ha as g,Ia as h,Ja as i,Ka as j,La as k,Q as b,R as c,S as d,T as e,l as a}from"./chunk-6WGGD3SS.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{j as applyPermissionDecision,f as isAuthCredentialsBrowserDelivery,i as isByoOAuthBrowserDelivery,h as isManagedBrowserDelivery,g as isPermissionBrowserDelivery,k as processCorsair,c as resolveAccountFromWebhookLink,e as resolveTenantFromWebhookLink,d as resolveTenantIdFromWebhookLink,b as setWebhookTenantLink,a as verifyBrowserDeliveryToken};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.106",
3
+ "version": "0.1.107",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,38 +0,0 @@
1
- import{a as Ur,b as de,c as Br,d as w,e as U,f as Lr,g as j,h as H,i as S,j as mn,k as Nr,l as $r,m as mt,n as jr,o as Wr}from"./chunk-BPFUYXOD.js";import{a as Fr}from"./chunk-IGGCNGU2.js";var hn=["agentql","algolia","ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","confluence","cursor","datadog","deepseek","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","gemini","github","gitlab","gmail","googlecalendar","googledocs","googledrive","googlemeet","googlesheets","grafana","hackernews","hubspot","insightoai","instagram","intercom","jira","linear","linkedin","mailchimp","monday","neon","notion","onedrive","openai","openweathermap","oura","outlook","pagerduty","perplexityai","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","supabase","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],Kr={agentql:"AgentQL",algolia:"Algolia",ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",confluence:"Confluence",cursor:"Cursor",datadog:"Datadog",deepseek:"DeepSeek",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",gemini:"Gemini",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledocs:"Google Docs",googledrive:"Google Drive",googlemeet:"Google Meet",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",insightoai:"Insighto.ai",instagram:"Instagram",intercom:"Intercom",jira:"Jira",linear:"Linear",linkedin:"LinkedIn",mailchimp:"Mailchimp",monday:"Monday",neon:"Neon",notion:"Notion",onedrive:"OneDrive",openai:"OpenAI",openweathermap:"OpenWeatherMap",oura:"Oura",outlook:"Outlook",pagerduty:"PagerDuty",posthog:"PostHog",razorpay:"Razorpay",reddit:"Reddit",resend:"Resend",sentry:"Sentry",sharepoint:"SharePoint",slack:"Slack",spotify:"Spotify",strava:"Strava",stripe:"Stripe",supabase:"Supabase",tally:"Tally",tavily:"Tavily",teams:"Teams",telegram:"Telegram",todoist:"Todoist",trello:"Trello",twilio:"Twilio",twitter:"Twitter",twitterapiio:"Twitter API IO",typeform:"Typeform",vapi:"Vapi",xquik:"XQuik",youtube:"YouTube",zendesk:"Zendesk",zohomail:"Zoho Mail",zoom:"Zoom",perplexityai:"Perplexity AI"};function pe(e){let n=Kr[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}import{randomUUID as Bi}from"crypto";var Di="corsair:client-bridge";function ht(e){return new URL(e).origin}function De(e){let n=JSON.stringify({type:Di,requestId:e.requestId,ok:e.ok,body:e.body??null,error:e.error??null}),t=JSON.stringify(ht(e.hubOrigin));return`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><script>
2
- (function () {
3
- var message = ${n};
4
- var targetOrigin = ${t};
5
- if (window.parent && window.parent !== window) {
6
- window.parent.postMessage(message, targetOrigin);
7
- }
8
- })();
9
- </script></body></html>`}var Oi=new Set(["localhost","127.0.0.1","[::1]","::1"]);function bt(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Oi.has(n)}catch{return!1}}function ze(e){return e==="development"?"browser":"server"}function qr(e){return ze(e)==="browser"}function Zr(e){return bt(e)?"Production delivery URL must be a public URL, not localhost":null}import{randomBytes as Ui}from"crypto";var Gr=new Set(["oauth.callback","oauth.tokens","webhook","permission.approve","permission.deny","auth.credentials","integration.credentials","connect.create_link","connections.sync"]),ge=60*1e3,Te=300*1e3;import{createHmac as Mi,randomBytes as Hi,timingSafeEqual as Fi}from"crypto";function oe(){return Hi(16).toString("base64url")}function Ve(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Mi("sha256",t).update(e).digest("base64url")}function Q(e,n){let t=n.trim();if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[o,i]=r;if(!o||!i)return null;let s=Ve(o,t);try{if(!Fi(Buffer.from(i,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function bn(e,n,t){let r=Math.floor(Date.now()/1e3),o={...e,iat:r,exp:t},i=Buffer.from(JSON.stringify(o)).toString("base64url"),s=Ve(i,n);return`${i}.${s}`}function Ye(e,n,t){let r=Math.floor(Date.now()/1e3);return bn(e,n,r+Math.floor(t/1e3))}function Pe(e){return decodeURIComponent(e)}function kt(e){return encodeURIComponent(e)}function Jr(e){let n=e.trim();return n.length>0?n:null}function Oe(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Me(e,n){if(!Jr(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??Ui(16).toString("base64url"),iat:t,exp:t+Math.floor(ge/1e3)},o=Buffer.from(JSON.stringify(r)).toString("base64url"),i=Ve(o,n);return`${o}.${i}`}function fe(e,n){return Jr(n)?Q(e,n):null}function Li(e){let n=ht(e.hubOrigin),t={connectJti:e.requestId,projectId:e.projectId,hubSuccessUrl:e.hubOrigin,deliveryMode:e.deliveryMode,hubOrigin:n,requestId:e.requestId};switch(e.deliveryMode){case"connections.sync":return{...t,plugin:"connections.sync",tenantId:"*"};case"connect.create_link":return{...t,plugin:"connect.create_link",tenantId:e.tenantId,connectLinkPlugins:e.plugins}}}function Ct(e){let n=Me(Li(e),e.signingSecret);return Oe(e.deliveryUrl,n)}function zr(e){if(ze(e.environmentSlug)==="server")return{transport:"server"};if(!e.hubOrigin)throw new Error(`hubOrigin is required for development ${e.deliveryMode} delivery`);let t=Bi(),r={...e,hubOrigin:e.hubOrigin,requestId:t};return{transport:"browser",requestId:t,deliveryUrl:Ct(r)}}var Qe="https://auth.corsair.dev";var ie=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret } to createCorsair()."),this.name="HubNotConfiguredError"}};function kn(e){let n=(e.apiUrl?.trim()||Qe).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim();if(!t||!r)throw new Error("Hub config requires non-empty projectApiKey and signingSecret");return{apiUrl:n,projectApiKey:t,signingSecret:r,oauthCallbackUrl:e.oauthCallbackUrl?.trim().replace(/\/$/,"")}}function Ni(e){return e.apiUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function M(e){let n=w(e).hub;if(!n||!Ni(n))throw new ie;return n}function Vr(e){return e.replace(/\/$/,"")}function Cn(e){return e.oauthCallbackUrl?Vr(e.oauthCallbackUrl.trim()):`${Vr(e.apiUrl)}/oauth/callback`}function He(e){if(e.startsWith("ck_dev_"))return"development";if(e.startsWith("ck_prod_"))return"production";throw new Error("Hub API key must start with ck_dev_ (development) or ck_prod_ (production)")}function x(e){return typeof e=="string"&&e.length>0}function $i(e){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"}function ji(e){return e==="oauth_2"||e==="api_key"||e==="bot_token"||e==="managed"}function wn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!x(n.connectUrl)||!x(n.token)||!x(n.projectId))throw new Error("Hub API returned an incomplete connect session (expected connectUrl, token, and projectId)");let t={connectUrl:n.connectUrl,token:n.token,projectId:n.projectId,environmentId:x(n.environmentId)?n.environmentId:n.projectId};return x(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function vn(e){if(!Array.isArray(e))throw new Error("Hub API returned an invalid connections response (expected array)");let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;if(!x(r.tenantId)||!x(r.plugin)||!$i(r.status)||!ji(r.authType)||typeof r.connected!="boolean"||typeof r.verified!="boolean")continue;let o=Array.isArray(r.missingFields)?r.missingFields.filter(i=>typeof i=="string"):[];n.push({tenantId:r.tenantId,plugin:r.plugin,status:r.status,authType:r.authType,connected:r.connected,verified:r.verified,missingFields:o,reportedAt:x(r.reportedAt)?r.reportedAt:new Date().toISOString()})}return n}function Tn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!x(n.approvalUrl)||!x(n.token)||!x(n.projectId)||!x(n.expiresAt))throw new Error("Hub API returned an incomplete permission session (expected approvalUrl, token, projectId, and expiresAt)");return{approvalUrl:n.approvalUrl,token:n.token,projectId:n.projectId,expiresAt:n.expiresAt}}function Pn(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(x(n.access_token))return{access_token:n.access_token,refresh_token:x(n.refresh_token)?n.refresh_token:void 0,expires_in:(()=>{if(typeof n.expires_in=="number")return n.expires_in;if(typeof n.expires_in=="string"&&n.expires_in.trim().length>0){let t=Number(n.expires_in);return Number.isFinite(t)?t:void 0}})(),scope:x(n.scope)?n.scope:void 0};throw new Error(x(n.error)?x(n.error_description)?n.error_description:n.error:"Hub token refresh returned no access_token")}function Wi(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function Ki(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;x(r.name)&&n.push({name:r.name,level:r.level==="integration"||r.level==="account"?r.level:"account",required:r.required===!0,configured:r.configured===!0})}return n}function qi(e,n,t,r){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"?e:n?"ready":t.some(i=>i.level==="integration"&&i.required&&!i.configured)?"missing_integration":t.some(i=>i.level==="account"&&i.required&&i.configured)?"partial":(r.length>0,"not_started")}function Yr(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!x(n.tenantId)||!Array.isArray(n.plugins))throw new Error("Connect status response was incomplete (expected tenantId and plugins)");let t=[];for(let r of n.plugins){if(!r||typeof r!="object")continue;let o=r;if(!x(o.plugin)||typeof o.connected!="boolean")continue;let i=o.authKind==="oauth"||o.authKind==="api_key"||o.authKind==="bot_token"?o.authKind:"api_key",s=Ki(o.fields),a=Wi(o.missingRequiredFields),c=qi(o.status,o.connected,s,a);t.push({plugin:o.plugin,providerName:x(o.providerName)?o.providerName:o.plugin,authKind:i,status:c,connected:o.connected,fields:s,missingRequiredFields:a})}return{tenantId:n.tenantId,plugins:t}}function An(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}var Zi="3000",Gi="/api/corsair";function Ji(e){return e.replace(/\/$/,"")}function ye(e){let n=e?.deliveryUrl?.trim()||process.env.CORSAIR_DELIVERY_URL?.trim();if(n){let r=/^https?:\/\//i.test(n)?n:`https://${n}`;return Ji(r)}return`http://localhost:${process.env.PORT?.trim()||Zi}${Gi}`}function Qr(e){return e.replace(/\/$/,"")}function wt(e){if(!e.projectApiKey.startsWith("ck_dev_"))return null;try{return ye()}catch{return null}}function Xr(e){let n=wt(e);return n?{"x-corsair-delivery-url":n}:{}}async function eo(e){let n=e.headers.get("content-type")??"",t=await e.text();if(!t)return null;if(!n.includes("application/json")&&t.trimStart().startsWith("<"))throw new Error(`Hub API returned HTML instead of JSON (HTTP ${e.status}). Check HUB_API_URL and deploy the latest hub API.`);try{return JSON.parse(t)}catch{throw new Error(`Hub API returned invalid JSON (HTTP ${e.status})`)}}function no(e,n,t){if(n===404&&t)return t;let r=An(e);return r||`Hub API returned HTTP ${n}`}async function W(e){let n=Qr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.hub.projectApiKey}`,...Xr(e.hub)},body:JSON.stringify(e.body)}),r=await eo(t);if(!t.ok)throw new Error(no(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function xn(e){let n=Qr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`,...Xr(e.hub)}}),r=await eo(t);if(!t.ok)throw new Error(no(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as to,createDecipheriv as ro,randomBytes as In,scrypt as zi}from"crypto";import{promisify as Vi}from"util";var oo=Vi(zi),Sn="aes-256-gcm",io=12,Rn=16,Yi=16,Xe=32;function se(){return In(Xe).toString("base64")}async function ae(e,n){let t=In(Yi),r=await oo(n,t,Xe),o=In(io),i=to(Sn,r,o,{authTagLength:Rn}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[t.toString("base64"),o.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function q(e,n){let[t,r,o,i]=e.split(":");if(!t||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),l=Buffer.from(i,"base64"),u=await oo(n,s,Xe),p=ro(Sn,u,a,{authTagLength:Rn});return p.setAuthTag(c),Buffer.concat([p.update(l),p.final()]).toString("utf8")}function vt(e,n){let t=Buffer.from(n,"base64"),r=In(io),o=to(Sn,t,r,{authTagLength:Rn}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function en(e,n){let[t,r,o]=e.split(":");if(!t||!r||!o)throw new Error("Invalid encrypted data format");let i=Buffer.from(n,"base64"),s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),l=ro(Sn,i,s,{authTagLength:Rn});return l.setAuthTag(a),Buffer.concat([l.update(c),l.final()]).toString("utf8")}function me(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=vt(o,n);return t}function ce(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=en(o,n);return t}function nn(e,n,t){let r=ce(e,n);return me(r,t)}function so(e,n,t){let r={};for(let o of t)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await n({[o]:s})};return r}var Tt=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function E(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,s=[...H[n].integration,...i],a=null,c={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let m=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!m)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:m.id,config:Tt(m.config),dek:m.dek??null},a},updateIntegration:async m=>{let h=await c.getIntegration();await o.db.updateTable("corsair_integrations").set({...m.config!==void 0?{config:m.config}:{},...m.dek!==void 0?{dek:m.dek}:{},updated_at:new Date}).where("id","=",h.id).execute(),a=null}},l=null,u=async()=>{if(l)return l;let m=await c.getIntegration();if(!m.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return l=await q(m.dek,r),l},p=async()=>{let m=await c.getIntegration(),h=await u(),b=m.config;return!b||Object.keys(b).length===0?{}:ce(b,h)},g=Promise.resolve(),d=m=>{let h=g.then(()=>y(m));return g=h.catch(()=>{}),h},y=async m=>{let h=await u(),b;try{b=await p()}catch(T){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,T),b={}}let v={...b};for(let[T,A]of Object.entries(m))A===null?delete v[T]:v[T]=A;let O=me(v,h);await c.updateIntegration({config:O})};return{get_dek:u,issue_new_dek:async()=>{let m=await c.getIntegration(),h=se(),b={};if(m.dek){let O=await q(m.dek,r),T=m.config;T&&Object.keys(T).length>0&&(b=nn(T,O,h))}let v=await ae(h,r);return await c.updateIntegration({config:b,dek:v}),l=h,h},...so(p,d,s)}}function _(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:s=[],ensureProvisioned:a}=e,c=[...H[n].account,...s],l=null,u=null,p=async()=>{if(u)return u;let k=!1;for(;;){let C=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!C){if(!k&&a){k=!0,await a();continue}throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`)}return u={id:C.id,config:Tt(C.config),dek:C.dek??null},u}},g={kek:o,integrationName:t,tenantId:r,getIntegration:p,getAccount:async()=>{if(l)return l;let k=!1;for(;;){let C=await p(),P=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",C.id).executeTakeFirst();if(!P){if(!k&&a){k=!0,await a();continue}throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`)}return l={id:P.id,config:Tt(P.config),dek:P.dek??null},l}},updateAccount:async k=>{let C=await g.getAccount();await i.db.updateTable("corsair_accounts").set({...k.config!==void 0?{config:k.config}:{},...k.dek!==void 0?{dek:k.dek}:{},updated_at:new Date}).where("id","=",C.id).execute(),l=null}},d=null,y=null,f=async()=>{if(d)return d;let k=await g.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return d=await q(k.dek,o),d},m=async()=>{if(y)return y;let k=await g.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return y=await q(k.dek,o),y},h=async()=>{let k=await g.getAccount(),C=await f(),P=k.config;return!P||Object.keys(P).length===0?{}:ce(P,C)},b=async()=>{let k=await g.getIntegration(),C=await m(),P=k.config;return!P||Object.keys(P).length===0?{}:ce(P,C)},v=Promise.resolve(),O=k=>{let C=v.then(()=>T(k));return v=C.catch(()=>{}),C},T=async k=>{let C=await f(),P;try{P=await h()}catch(I){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,I),P={}}let N={...P};for(let[I,$]of Object.entries(k))$===null?delete N[I]:N[I]=$;let te=me(N,C);await g.updateAccount({config:te})},A={get_dek:f,issue_new_dek:async()=>{let k=await g.getAccount(),C=se(),P={};if(k.dek){let te=await q(k.dek,o),I=k.config;I&&Object.keys(I).length>0&&(P=nn(I,te,C))}let N=await ae(C,o);return await g.updateAccount({config:P,dek:N}),d=C,C},...so(h,O,c)};return n==="oauth_2"&&(A.get_integration_credentials=async()=>{let k=await b();return{...k,client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),A}async function ao(e,n,t){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!r)throw new Error(`Integration "${n}" not found.`);let o=se(),i=await ae(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function co(e,n,t,r){let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!o)throw new Error(`Integration "${n}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",o.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let s=se(),a=await ae(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var Qi=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function he(e){return Qi.has(e)}function Xi(e,n){return he(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function es(e){return!he(e)}function ns(e){switch(e){case"oauth_2":case"managed":return["access_token","refresh_token"];case"api_key":return["api_key"];case"bot_token":return["bot_token"]}}function ts(e,n){return ns(e).every(r=>n.find(i=>i.level==="account"&&i.name===r)?.configured??!1)}async function uo(e,n){if(!e)return!1;let t=j(e,`get_${n}`);if(!t)return!1;try{let r=await t();return typeof r=="string"&&r.length>0}catch{return!1}}function rs(e,n){let r=e.authConfig?.[n]?.integration??[];return[...H[n].integration,...r]}function os(e,n){let r=e.authConfig?.[n]?.account??[];return[...H[n].account,...r]}function is(e,n,t){let r=t.filter(a=>a.required&&!a.configured).map(a=>a.name),o=t.filter(a=>a.level==="integration"&&a.required&&!a.configured).map(a=>a.name),i=t.filter(a=>a.level==="account"&&a.required&&a.configured),s;return o.length>0?s="missing_integration":r.length===0?s="ready":i.length>0?s="partial":s="not_started",{plugin:e,authType:n,status:s,connected:ts(n,t),fields:t,missingRequiredFields:r}}async function Ae(e,n,t){let r=S(n);if(!r||!e.database||!e.kek)return null;let o=t.trim()||"default",i=n.authConfig,s=i?.[r]?.integration??[],a=i?.[r]?.account??[],c=E({authType:r,integrationName:n.id,kek:e.kek,database:e.database,extraIntegrationFields:s}),l=_({authType:r,integrationName:n.id,tenantId:o,kek:e.kek,database:e.database,extraAccountFields:a}),u=rs(n,r),p=os(n,r),g=[];for(let d of u)g.push({name:d,level:"integration",required:Xi(r,d),configured:await uo(c,d)});for(let d of p)g.push({name:d,level:"account",required:es(d),configured:await uo(l,d)});return is(n.id,r,g)}async function tn(e,n,t={}){let r=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,i=[];for(let s of e.plugins){if(o&&!o.has(s.id))continue;let a=await Ae(e,s,r);a&&i.push(a)}return i}function _n(e){return e.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}var lo=Symbol.for("corsair:internal"),po=new WeakMap;function ss(e){let n=po.get(e);return n||(n=new Map,po.set(e,n)),n}function as(e){return e.multiTenancy?{withTenant:()=>({}),[lo]:e}:{[lo]:e}}async function En(e,n){if(!e.database)return;let t=n.trim()||"default",r=ss(e),o=t,i=r.get(o);if(i){await i;return}let s=(async()=>{let{setupCorsair:a}=await import("./setup-ZXL3B2P6.js");await a(as(e),{tenantId:e.multiTenancy?t:void 0,silent:!0})})().finally(()=>{r.delete(o)});r.set(o,s),await s}import{ZodBoolean as us,ZodDate as ls,ZodEnum as ds,ZodNullable as ps,ZodNumber as gs,ZodObject as fs,ZodOptional as ys,ZodRecord as ms,ZodString as hs,ZodType as bs}from"zod";var cs={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},repositories:{list:{}}},discord:{guilds:{list:{}},channels:{list:{}}},hubspot:{contacts:{getMany:{}},companies:{getMany:{}},deals:{getMany:{}}},gmail:{messages:{list:{}},labels:{list:{}},drafts:{list:{}},threads:{list:{}}},googlecalendar:{events:{getMany:{}}},googlemeet:{conferenceRecords:{list:{}}},googledrive:{files:{list:{}},folders:{list:{}},sharedDrives:{list:{}}},notion:{databases:{getManyDatabases:{}},databasePages:{getManyDatabasePages:{}},users:{getManyUsers:{}}},airtable:{bases:{getMany:{}}},todoist:{projects:{getMany:{}},tasks:{getMany:{}}},cal:{bookings:{list:{}}},zohomail:{folders:{list:{}},messages:{list:{}}}},Pt=cs;async function On(e,n){let t=[],r=n?.silent??!1,o=d=>{t.push(d),r||console.log(d)},i=d=>{t.push(d),r||console.warn(d)},s=n?.caller??"script",a=Br(e);if(!a)throw new Error("setupCorsair: invalid corsair instance");if(!a.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let c=Cs(e,a.plugins,n),l={...a,database:a.database},u=l.database.db;await Ts(u,i);let p=await Ps(u,l,c.tenantId,c.provisionAccounts,o);n?.credentials&&Object.keys(n.credentials).length>0&&await Is(e,c,n.credentials,l,o,i);let g=await Rs(p,c,o,s);if(n?.backfill){o("[corsair:setup] Starting backfill...");let d=yo({plugins:a.plugins,database:u,kek:a.kek,multiTenancy:!0}).withTenant(c.tenantId);await _s(d,a.plugins,g,o,i),o("[corsair:setup] Backfill complete.")}return t.join(`
10
- `)}function At(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...H[n][t],...r])}function ks(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let o=n.find(a=>a.id===t);if(!o)continue;let i=S(o);if(!i)continue;let s=At(o,i,"account");for(let a of Object.keys(r))if(s.has(a))return!0}return!1}function Cs(e,n,t){let r=Lr(e),o=t?.tenantId?.trim(),i=o!==void 0&&o.length>0;if(r&&t?.backfill&&!i)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(r&&ks(t?.credentials,n)&&!i)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(i&&!o)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:r,tenantIdProvided:i,tenantId:i?o:"default",provisionAccounts:!r||i}}function fo(e,n){return de(e)?n===0?!0:Object.values(e).every(t=>fo(t,n-1)):!1}function ws(e){return fo(e,4)}var vs={...jr};function Dn(e){if(e instanceof fs){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof bs?Dn(r):"unknown";return n}return e instanceof ps?`${Dn(e.unwrap())} | null`:e instanceof ys?`${Dn(e.unwrap())} | undefined`:e instanceof ds?e.options.join(" | "):e instanceof hs?"string":e instanceof gs?"number":e instanceof us?"boolean":e instanceof ls?"date":e instanceof ms?"jsonb":"unknown"}async function Ts(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(o=>o.name));for(let[o,i]of Object.entries(vs))r.has(o)||n(`[corsair:setup] Table "${o}" does not exist. Run your database migrations before calling setupCorsair.
11
- Schema: ${JSON.stringify(Dn(i),null,2)}`)}async function Ps(e,n,t,r,o){let i=new Date,s=new Map;for(let a of n.plugins){let c=a.id,l=S(a),u=await e.selectFrom("corsair_integrations").selectAll().where("name","=",c).executeTakeFirst();if(!u){let f=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:f,name:c,config:{},created_at:i,updated_at:i}).execute(),u=await e.selectFrom("corsair_integrations").selectAll().where("id","=",f).executeTakeFirst(),o(`[corsair:setup] Created integration: ${c}`)}let p=l?a.authConfig?.[l]?.integration??[]:[],g=l?a.authConfig?.[l]?.account??[]:[],d=l&&u?E({authType:l,integrationName:c,kek:n.kek,database:n.database,extraIntegrationFields:p}):void 0;if(u&&!u.dek&&d&&(await d.issue_new_dek(),o(`[corsair:setup] Issued integration DEK: ${c}`)),!u||!l||!d)continue;let y;if(r){let f=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",u.id).executeTakeFirst();if(!f){let m=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:m,tenant_id:t,integration_id:u.id,config:{},created_at:i,updated_at:i}).execute(),f=await e.selectFrom("corsair_accounts").selectAll().where("id","=",m).executeTakeFirst(),o(`[corsair:setup] Created account: ${c}`)}y=f&&_({authType:l,integrationName:c,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),f&&y&&!f.dek&&(await y.issue_new_dek(),o(`[corsair:setup] Issued account DEK: ${c}`))}s.set(c,{pluginId:c,authType:l,integration:d,account:y,integrationFields:[...H[l].integration,...p],accountFields:r?[...H[l].account,...g]:[]})}return s}function As(e){if(!de(e))return;let n=e.keys;return de(n)?n:void 0}function xs(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function Is(e,n,t,r,o,i){let s=As(e),a=n.provisionAccounts?xs(e,n.tenantId):void 0;for(let[c,l]of Object.entries(t)){let u=r.plugins.find(h=>h.id===c);if(!u){i(`[corsair:setup] Unknown plugin '${c}' \u2014 skipping credentials.`);continue}let p=S(u);if(!p){i(`[corsair:setup] Plugin '${c}' has no auth type \u2014 skipping credentials.`);continue}let g=At(u,p,"integration"),d=At(u,p,"account"),y=s?.[c],f=a?.[c],m=de(f)?f.keys:void 0;for(let[h,b]of Object.entries(l))if(b){if(g.has(h)){if(n.multiTenant&&n.tenantIdProvided)throw new Error(`[corsair:setup] '${c}.${h}' is an integration-level credential shared across all tenants. You passed tenantId="${n.tenantId}", which only scopes account-level credentials. Run setup without --tenant if you intend to change this credential globally.`);let v=j(y,`set_${h}`);if(!v){i(`[corsair:setup] Cannot set integration field '${h}' for '${c}'.`);continue}await v(b),o(`[corsair:setup] Set ${c} integration.${h}`);continue}if(d.has(h)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${c}.${h}' on a multi-tenant instance`);let v=j(m,`set_${h}`);if(!v){i(`[corsair:setup] Cannot set account field '${h}' for '${c}'.`);continue}await v(b),o(`[corsair:setup] Set ${c} account.${h} (tenant=${n.tenantId})`);continue}i(`[corsair:setup] Unknown credential field '${h}' for plugin '${c}'.`)}}}var go=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function Ss(e,n,t,r,o,i,s,a,c){let l=[],u=[];for(let g of o){if(go.has(g))continue;let d=j(t,`get_${g}`);if(!d)continue;let y=null;try{let f=await d();y=typeof f=="string"?f:null}catch{}y||l.push(g)}if(r&&i.length>0)for(let g of i){if(go.has(g))continue;let d=j(r,`get_${g}`);if(!d)continue;let y=null;try{let f=await d();y=typeof f=="string"?f:null}catch{}y||u.push(g)}let p=l.length===0&&u.length===0;if(p)a(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else if(n==="managed")a(`[corsair:setup] '${e}' (managed) is not connected yet. Use Connect in your app \u2014 Corsair Hub delivers OAuth tokens after authorization.`);else{let g=[...l,...u];if(c==="cli"){let d=g.map(y=>`${y}=VALUE`).join(" ");a(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
12
- corsair setup --${e} ${d}`)}else{let d=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let y of l)d.push(` await corsair.keys.${e}.set_${y}(value)`);for(let y of u){let f=s.provisionAccounts?s.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(s.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;d.push(` await ${f}.keys.set_${y}(value)`)}a(d.join(`
13
- `))}}return p}async function Rs(e,n,t,r){let o=new Set;for(let i of e.values())await Ss(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function _s(e,n,t,r,o){if(!ws(Pt)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=Pt,s=new Set(n.map(a=>a.id));for(let[a,c]of Object.entries(i)){if(!s.has(a))continue;if(!t.has(a)){r(`[corsair:setup] Skipping backfill for '${a}' \u2014 auth not configured.`);continue}let l=de(e)?e[a]:void 0,u=de(l)?l.api:void 0;if(u)for(let[p,g]of Object.entries(c))for(let[d,y]of Object.entries(g)){r(`[corsair:setup] Backfilling ${a} \u203A ${p}.${d}...`);try{let f=de(u)?u[p]:void 0;await j(f,d)?.(y)}catch(f){o(`[corsair:setup] ${a} \u203A ${p}.${d} failed: `+(f instanceof Error?f.message:String(f)))}}}}async function mo(e){if(!w(e).database)throw new Error("A database must be configured to provision Corsair integrations");await On(e,{silent:!0})}async function xe(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to provision Corsair for connect");await En(t,n)}var Es=Symbol.for("corsair:internal"),Ds=new Set(["access_token","refresh_token","expires_at","scope"]);function Os(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Ms(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!he(t)&&!Ds.has(t)):n.filter(t=>!he(t))}function ho(e){return{plugins:e.plugins,database:e.database,kek:e.kek,multiTenancy:!1}}function bo(e){return{[Es]:ho(e)}}async function Mn(e,n,t={}){let r=Cn(e.hub),o=[],i=t.pluginIds?new Set(t.pluginIds):null,s=ho(e),a=bo(e);for(let c of e.plugins){if(i&&!i.has(c.id))continue;let l=S(c);if(!l)continue;let u=Os(l),p=t.providerNameOverrides?.[c.id]??pe(c.id),g=await Ae(s,c,n),d=mn(c,l),y=Ms(l,d),f={plugin:c.id,providerName:p,authKind:u,alreadyConfigured:g?.connected??!1};if(y.length>0&&(f.credentialFields=y),u==="oauth"){let h=t.oauthModeOverrides?.[c.id]??(l==="managed"?"managed":"byo");if(f.oauthMode=h,!t.skipOAuthUrlGeneration&&h!=="managed")try{let b=await xt(a,c.id,{tenantId:n,redirectUri:r,hubConnect:!0});f.oauthUrl=b.url}catch(b){f.setupError=b instanceof Error?b.message:`Could not prepare OAuth for ${c.id}`}}o.push(f)}return o}async function wu(e,n,t={}){let r=w(e),o=r.hub;if(!o)throw new Error("Hub is not configured");return Mn({plugins:r.plugins,database:r.database,kek:r.kek,hub:o},n,t)}async function It(e,n){if(!e.database)throw new Error("A database must be configured to provision Corsair for connect");await xe(bo(e),n)}async function vu(e,n){await xe(e,n)}async function ko(e,n){let t=He(e.projectApiKey),r={tenantId:n.tenantId,plugins:n.plugins};return t==="development"&&(r.deliveryUrl=ye({deliveryUrl:n.deliveryUrl})),W({hub:e,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:wn})}async function St(e,n){let t={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await It(t,n.tenantId);let r=await Mn(t,n.tenantId,{pluginIds:[n.plugin.id]});if(r.length===0)throw new Error(`Plugin '${n.plugin.id}' is not configured on this Corsair instance`);return ko(e,{tenantId:n.tenantId,plugins:r,deliveryUrl:n.deliveryUrl})}async function Hn(e,n){let t=w(e),r=M(e),o={plugins:t.plugins,database:t.database,kek:t.kek,hub:r};await It(o,n.tenantId);let i=n.plugin?[n.plugin]:void 0,s=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,a=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,c=await Mn(o,n.tenantId,{pluginIds:i,oauthModeOverrides:s,providerNameOverrides:a});if(c.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is not configured on this Corsair instance`:"No plugins are configured on this Corsair instance");return ko(r,{tenantId:n.tenantId,plugins:c,deliveryUrl:n.deliveryUrl})}function Co(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Hs(e,n){return n&&!n.has(e.id)?!1:S(e)!==null}async function wo(e,n,t={}){let r=w(e),o=n.trim()||"default",i=t.pluginIds?.length?new Set(t.pluginIds):null,s=await tn(r,o,{pluginIds:t.pluginIds}),a=new Map(s.map(l=>[l.plugin,l])),c=r.plugins.filter(l=>Hs(l,i)).map(l=>{let u=S(l),p=a.get(l.id);return p?{plugin:l.id,providerName:pe(l.id),authKind:Co(u),status:p.status,connected:p.connected,fields:p.fields.map(g=>({name:g.name,level:g.level,required:g.required,configured:g.configured})),missingRequiredFields:p.missingRequiredFields}:{plugin:l.id,providerName:pe(l.id),authKind:Co(u),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:o,plugins:c}}async function vo(e,n){let t=M(e);return xn({hub:t,path:`/projects/${encodeURIComponent(n.projectId)}/connections`,notFoundMessage:"Hub REST API not found at /projects/:id/connections. Check HUB_API_URL and ensure the Hub API is deployed.",parseResponse:vn})}import*as rn from"crypto";function be(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function Rt(e,{maxAgeMs:n}={}){try{let t=e.includes(".")?e.split(".")[0]:e,r=JSON.parse(Buffer.from(t,"base64url").toString("utf-8"));if(r!==null&&typeof r=="object"&&"plugin"in r&&"tenantId"in r&&typeof r.plugin=="string"&&typeof r.tenantId=="string"){let o=r;return n!==void 0&&typeof o.iat=="number"&&Date.now()-o.iat>n?null:o}return null}catch{return null}}function Fe(e,n){let t=rn.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var _t=600*1e3;function Fn(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),o=e.slice(t+1),i=rn.createHmac("sha256",n).update(r).digest("base64url"),s=Buffer.from(o,"base64url"),a=Buffer.from(i,"base64url");return s.length!==a.length||!rn.timingSafeEqual(s,a)?null:Rt(r,{maxAgeMs:_t})}function Ue(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}import*as To from"querystring";function Ie(e){let{oauthConfig:n,clientId:t,redirectUri:r,state:o}=e,i={...n.authParams,client_id:t,redirect_uri:r,response_type:"code",scope:n.scopes.join(" "),state:o};return`${n.authUrl}?${To.stringify(i)}`}var Z=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function Fs(e){let n=e.oauthConfig;if(!n)throw new Z("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Et(e,n){let t=w(e,()=>new Z("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Z("no_database","No database configured on corsair instance");let r=t.manual?.redirectUri;if(!r)throw new Z("no_redirect_uri","No redirectUri configured. Set manual.redirectUri in createCorsair().");let o=Fn(n,t.kek);if(!o)throw new Z("invalid_state","Invalid or tampered state parameter");let{plugin:i,tenantId:s}=o,a=U(t,i,g=>new Z("plugin_not_found",g)),c=Fs(a),u=await E({authType:"oauth_2",integrationName:i,kek:t.kek,database:t.database}).get_client_id();if(!u)throw new Z("client_id_not_configured",`client_id not configured for '${i}'`);let p=Ie({oauthConfig:c,clientId:u,redirectUri:r,state:n});return{plugin:i,tenantId:s,providerName:c.providerName,oauthUrl:p,state:n}}import{randomBytes as Bs}from"crypto";import{v4 as Ls}from"uuid";async function Un(e,n){let t=He(e.projectApiKey),r={permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,expiresAt:n.expiresAt};return t==="development"&&(r.deliveryUrl=ye({deliveryUrl:n.deliveryUrl})),W({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:Tn})}function Bn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var Dt="Permission approval required. Set manual.approvalBaseUrl (or use hub for hosted approval) so an approval URL can be generated. Optionally set manual.onApprovalRequired to customize the agent message.";function Mt(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function Po(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Ot(e){return Bn(e)}async function Ht(e,n){if(Mt(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?Po(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await Un(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:Us(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function Us(e){try{return JSON.parse(e)}catch{return e}}async function Ln(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await Ht(e,n);return{...n,approvalUrl:r}}async function Ft(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:o,permissionToken:i,plugin:s,endpoint:a,args:c,tenantId:l,expiresAt:u,operationPath:p}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:i,id:o,plugin:s,endpoint:a,args:c});let d=await Ht({manual:t,hub:r},{id:o,token:i,plugin:s,endpoint:a,args:JSON.stringify(c),tenant_id:l,expires_at:u});return Mt(t)?d?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:d}):Ot(d):Dt:r?d?Ot(d):`Action '${p}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Dt}var Ns={open:{read:"allow",write:"allow",destructive:"allow"},cautious:{read:"allow",write:"allow",destructive:"require_approval"},strict:{read:"allow",write:"require_approval",destructive:"deny"},readonly:{read:"allow",write:"deny",destructive:"deny"}};function $s(e,n,t){return t!==void 0?t:Ns[n][e]}function Ut(e){let n=/(\d+)(d|h|m|s)/g,t=0,r;for(;(r=n.exec(e))!==null;){let o=parseInt(r[1],10);switch(r[2]){case"d":t+=o*864e5;break;case"h":t+=o*36e5;break;case"m":t+=o*6e4;break;case"s":t+=o*1e3;break}}return t>0?t:600*1e3}function xo(e){return{async find_by_permission_id(n){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst()},async find_by_token(n){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst()},async set_executing(n){e&&await e.db.updateTable("corsair_permissions").set({status:"executing",updated_at:new Date}).where("id","=",n).execute()},async set_completed(n){e&&await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}}}async function Ao(e,n,t){let r=Date.now()+t;for(;Date.now()<r;){let o=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!o)return{result:"blocked",reason:"pending"};if(o.status==="approved")return{result:"allow",onComplete:async()=>{await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}};if(o.status==="denied")return{result:"blocked",reason:"denied"};if(o.status==="expired"||o.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(i=>setTimeout(i,500))}return{result:"blocked",reason:"timeout"}}async function Io(e){let n=$s(e.riskLevel,e.mode,e.override);if(n==="allow")return{result:"allow"};let t=e.meta?.irreversible?" (irreversible)":"",r=e.meta?.description?`${e.meta.description}${t}`:`${e.pluginId}.${e.endpointPath}${t}`;if(n==="deny"||!e.db)return console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 denied by permission mode '${e.mode}'.`,`
14
- Action: ${r}`,`
15
- To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let o=JSON.stringify(e.args),i=new Date().toISOString(),s=e.tenantId??"default",a=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",o).where("tenant_id","=",s).where("expires_at",">",i).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(a){if(a.status==="approved"){let y=e.db,f=a.id;return{result:"allow",onComplete:async()=>{await y.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",f).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
16
- Action: ${r}`,`
17
- Permission ID: ${a.id}`,`
18
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Ao(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:a.id,token:a.token,expiresAt:a.expires_at})}let c=Ls(),l=Bs(32).toString("hex"),u=e.timeoutMs??600*1e3,p=new Date(Date.now()+u).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:c,created_at:new Date,updated_at:new Date,token:l,plugin:e.pluginId,endpoint:e.endpointPath,args:o,tenant_id:s,status:"pending",expires_at:p}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
19
- Action: ${r}`,`
20
- Permission ID: ${c}`,`
21
- Permission token: ${l}`,`
22
- Expires at: ${p}`,`
23
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Ao(e.db,c,u):{result:"blocked",reason:"pending",id:c,token:l,expiresAt:p}}var R=class extends Error{status;code;extra;constructor(n,t,r,o={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=o}};function D(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function So(e){let n={error:e.code,message:e.message,...e.extra};return D(e.status,n)}function ke(e){return new R(404,"not_found",e)}function ue(e,n={}){return new R(400,"bad_request",e,n)}function Ro(e,n){return U(e,n,t=>ke(t))}async function _o(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=E({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),o=H[t].integration,i=r,s;try{s=await Promise.all(o.map(l=>i[`get_${l}`]()))}catch{s=o.map(()=>null)}let a=o.filter((l,u)=>s[u]==null),c;return t==="oauth_2"?c=!a.includes("client_id")&&!a.includes("client_secret"):c=a.length===0,{configured:c,missingFields:a}}async function Eo(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:o,missingFields:i}=await _o(e,n);return{id:e.id,authType:t,configured:o,missingFields:i,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function Nn(){return{ok:!0}}async function Be(e){return Promise.all(e.plugins.map(n=>Eo(n,e)))}async function $n(e,n){let t=Ro(e,n);return Eo(t,e)}async function js(e,n){return e.database?(await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.id as accountId","a.dek as dek","i.name as integrationName"]).where("a.tenant_id","=",n).execute()).map(r=>({integrationName:r.integrationName,hasCredentials:!!r.dek})):[]}async function Do(e,n){let t=await js(e,n),r=t.filter(o=>o.hasCredentials).map(o=>o.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function Le(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let o=r.tenant_id;if(!o)continue;let i=n.get(o);i||(i={id:o,accounts:[],connectedPlugins:[]},n.set(o,i));let s=!!r.dek;i.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&i.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function jn(e,n){if(!n)throw ue("Tenant id must be a non-empty string");return Do(e,n)}async function Wn(e,n){let t=n?.id?.trim();if(!t)throw ue("Tenant id is required",{missingFields:["id"]});return Do(e,t)}async function Kn(e,n){let t=n?.trim()||"default",r={},o=await tn(e,t);for(let i of o)r[i.plugin]=_n(i);for(let i of e.plugins)i.id in r||(!i.options?.authType||!e.database||!e.kek?r[i.id]="missing_credentials":r[i.id]="not_connected");return r}async function Bt(e,n){if(!e.database)throw ke(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ke(`Permission '${n}' not found`);return Ln(e,t)}function Ws(e){if(!e.oauthConfig)throw ue(`Plugin '${e.id}' has no oauthConfig`)}function Ks(e){if(!e.manual)throw new R(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function Lt(e){let n=Ks(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new R(500,"connect_not_configured","Manual connect requires manual.baseUrl and manual.redirectUri. Use hub for hosted connect, or set both URLs for manual OAuth.");return n}function qs(e){let n=!!e.hub,t=Ue(e.manual);if(!n&&!t)throw new R(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function Oo(e){if(!e.database||!e.kek)throw new R(500,"database_not_configured","A database and kek are required to issue connect links.")}async function Zs(e,n){let t=n?.plugin?.trim();if(!t)throw ue("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",o=Ro(e,t);Ws(o);let i=Lt(e);Oo(e);let s=await _o(o,e);if(!s.configured)throw new R(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:s.missingFields});let a=Fe(be(t,r),e.kek),c;try{c=new URL(i.baseUrl)}catch{throw new R(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return c.searchParams.set("state",a),{connectUrl:c.toString(),expiresAt:new Date(Date.now()+_t).toISOString()}}async function Gs(e,n,t){Oo(n);let o={tenantId:t.tenantId?.trim()||"default",oauthMode:t.oauthMode},i=t.plugin?.trim();i&&(o.plugin=i);let s=t.providerName?.trim();s&&(o.providerName=s);let a=await Hn(e,o);return{connectUrl:a.connectUrl,expiresAt:a.expiresAt}}async function qn(e,n,t){return qs(n),n.hub?Gs(e,n,t):Zs(n,t)}async function Zn(e,n,t){if(n.hub&&!Ue(n.manual))throw new R(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw ue("state is required",{missingFields:["state"]});Lt(n);try{return await Et(e,r)}catch(o){if(o instanceof Z)switch(o.code){case"invalid_state":throw ue("Invalid or expired state");case"client_id_not_configured":throw new R(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new R(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function Gn(e,n,t){if(n.hub&&!Ue(n.manual))throw new R(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),o=t?.state?.trim(),i=[];if(r||i.push("code"),o||i.push("state"),i.length)throw ue("Missing required fields",{missingFields:i});let s=Lt(n),{processOAuthCallback:a}=await import("./oauth.js");try{return await a(e,{code:r,state:o,redirectUri:s.redirectUri})}catch(c){if(c instanceof Error&&c.name==="OAuthCallbackError")switch(c.code){case"invalid_state":throw ue("Invalid or expired state");case"credentials_not_configured":throw new R(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new R(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function Nt(e,n){if(!e.database)throw ke("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ke("Permission not found");return Ln(e,t)}async function Mo(e,n){return"id"in n?Bt(e,n.id):Nt(e,n.token)}import{createCipheriv as ea,createDecipheriv as wl,randomBytes as Bo,scryptSync as na}from"crypto";import{createHmac as $t,randomUUID as Js,timingSafeEqual as Fo}from"crypto";function Uo(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Jn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=$t("sha256",e.signingSecret.trim()).update(n).digest("hex");return{body:n,headers:{"content-type":"application/json","x-corsair-signature":`sha256=${r}`,"x-corsair-timestamp":t,"x-corsair-project":e.projectId,"x-corsair-nonce":Js()}}}function jt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Uo(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>Te)return!1;let i=$t("sha256",n).update(e.body).digest("hex");try{return Fo(Buffer.from(i,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function Ne(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Uo(e.signatureHeader);if(!t)return{ok:!1,error:"Invalid tunnel signature"};let r=Number(e.timestampHeader);if(!Number.isFinite(r))return{ok:!1,error:"Invalid or missing tunnel timestamp"};if(Math.abs(Date.now()-r*1e3)>Te)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let i=$t("sha256",n).update(e.body).digest("hex");try{if(!Fo(Buffer.from(i,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function $e(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function zn(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function Vn(e){let n=e.sync?.encrypted;return typeof n!="string"||!n.trim()?null:{encrypted:n.trim()}}function on(e){let n=e.connectUrl?.trim();return n?{connectUrl:n,expiresAt:e.expiresAt}:null}function Wt(e){return on($e(e))}async function Kt(e){let n=await Xn({deliveryUrl:e.deliveryUrl,projectId:e.projectId,signingSecret:e.signingSecret,type:"connect.create_link",payload:{tenantId:e.tenantId,plugins:e.plugins}}),t=$e(n.body),r=zn({httpOk:n.ok,status:n.status,body:t}),o=on(t);if(!r||!o)throw new Error(Qn({deliveryUrl:e.deliveryUrl,status:n.status,body:n.body,ack:t}));return o}function Yn(e){return Vn($e(e))}function zs(e){let n=e;for(;n;){if(n instanceof Error){let t=n.code;if(typeof t=="string")return t;n=n.cause;continue}if(typeof n=="object"&&n!==null&&"code"in n){let t=n.code;if(typeof t=="string")return t}break}}function Ho(e,n=200){let t=e.trim();return t.length<=n?t:`${t.slice(0,n)}\u2026`}var Vs="Verify hub.signingSecret in your app matches the signing secret shown in Hub project settings.",Ys="Check the delivery URL configured for this environment.";function Qs(e){return`${e.ack.error?`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`:`App rejected the signed delivery (HTTP ${e.status} from ${e.deliveryUrl})`}. ${Vs}`}function Xs(e){return`${e.ack.error?`${e.ack.error} (HTTP 404 from ${e.deliveryUrl})`:`Delivery endpoint not found at ${e.deliveryUrl} (HTTP 404)`}. ${Ys}`}function sn(e,n){let t=zs(n),r=n instanceof Error?n.message:"Delivery request failed",o;switch(t){case"ECONNREFUSED":o="connection refused \u2014 nothing accepted a TCP connection on that host and port";break;case"ENOTFOUND":o="host not found \u2014 DNS could not resolve the hostname";break;case"ETIMEDOUT":case"UND_ERR_CONNECT_TIMEOUT":o="connection timed out before the app responded";break;case"ECONNRESET":o="connection reset while talking to the app";break;case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":o=`TLS certificate error (${t})`;break;default:o=r==="fetch failed"&&t?`${r} (${t})`:r}return[`Could not reach ${e}`,o].join(". ")}function Qn(e){if(e.status===0)return e.ack.error?e.ack.error:e.body.startsWith("Could not reach")?e.body:sn(e.deliveryUrl,new Error(e.body||"Delivery request failed"));if(e.status===401||e.status===403)return Qs(e);if(e.status===404)return Xs(e);if(e.ack.error)return`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`;if(e.status>=500){let t=e.body.trim();return t?`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl}): ${Ho(t)}`:`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl})`}let n=e.body.trim();return n?`${Ho(n)} (HTTP ${e.status} from ${e.deliveryUrl})`:`Delivery failed with HTTP ${e.status} from ${e.deliveryUrl}`}async function Xn(e){let{body:n,headers:t}=Jn(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),o=await r.text();return{ok:r.ok,status:r.status,body:o}}catch(r){return{ok:!1,status:0,body:sn(e.deliveryUrl,r)}}}var ta="aes-256-gcm",ra=12,oa=16,ia=16,sa=32;function aa(e,n){return na(e.trim(),n,sa)}function qt(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required to encrypt sync manifest");let r=Bo(ia),o=aa(t,r),i=Bo(ra),s=ea(ta,o,i,{authTagLength:oa}),a=JSON.stringify(e),c=Buffer.concat([s.update(a,"utf8"),s.final()]),l=s.getAuthTag();return[r.toString("base64"),i.toString("base64"),l.toString("base64"),c.toString("base64")].join(":")}var ca=["invalid corsair instance","a database must be configured to sync connections from the app","a database must be configured on the corsair instance","signing secret is required to encrypt sync manifest"];function Zt(e){if(e instanceof Ur)return!1;if(!(e instanceof Error))return!0;let n=e.message.toLowerCase();return!ca.some(t=>n.includes(t))}function ua(e){if(!e)return[];let n=S(e);return n?(e.authConfig?.[n]?.integration??[]).filter(r=>!he(r)):[]}async function an(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to sync connections from the app");await On(e,{silent:!0});let[r,o]=await Promise.all([Le(t),Be(t)]),i={tenants:r.map(s=>({id:s.id})),plugins:o.map(s=>{let a=ua(t.plugins.find(c=>c.id===s.id));return{id:s.id,authType:s.authType,configured:s.configured,missingFields:s.missingFields,...a.length>0?{integrationCredentialFields:a}:{}}}),syncedAt:new Date().toISOString()};return qt(i,n)}async function et(e,n){let t=n.tenantId.trim();if(!t)throw new Error("tenantId is required");let r=n.plugins.map(s=>s.trim()).filter(Boolean);if(r.length===0)throw new Error("At least one plugin is required");let o=w(e);if(!o.hub)throw new Error("Hub is not configured on this Corsair instance");if(!o.database)throw new Error("Database not configured");let i=await la(o.hub,{plugins:o.plugins,database:o.database,kek:o.kek},{tenantId:t,pluginIds:r});return{connectUrl:i.connectUrl,expiresAt:i.expiresAt}}async function la(e,n,t){let{buildConnectPluginManifestFromContext:r,ensureConnectAccountRowsFromContext:o}=await import("./setup-introspect-L7VOSJF5.js"),{postHubConnectSession:i}=await import("./connect-EOKSLJEB.js"),s={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await o(s,t.tenantId);let a=await r(s,t.tenantId,{pluginIds:t.pluginIds});if(a.length===0)throw new Error("No connectable plugins found for this tenant");let c=a.find(l=>l.setupError);if(c)throw new Error(c.setupError??`Could not prepare connect link for ${c.plugin}`);return i(e,{tenantId:t.tenantId,plugins:a})}var X=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function nt(e,n){let t=w(e,()=>new X("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new X("no_database","Database not configured");let r=U(t,n.plugin,u=>new X("plugin_not_found",u)),o=S(r);if(!o)throw new X("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(o==="oauth_2"||o==="managed")throw new X("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await xe(e,n.tenantId);let i=new Set(mn(r,o)),a=r.authConfig?.[o]?.account??[],c=_({authType:o,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a}),l=0;for(let[u,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(u))throw new X("invalid_credentials",`Unknown credential field '${u}' for plugin '${n.plugin}'`);let g=j(c,`set_${u}`);if(!g)throw new X("invalid_credentials",`Cannot set credential field '${u}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new X("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var ee=class extends Error{code;constructor(n,t){super(t),this.name="IntegrationCredentialsDeliveryError",this.code=n}};async function Gt(e,n){let t=w(e,()=>new ee("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new ee("no_database","Database not configured");let r=U(t,n.plugin,u=>new ee("plugin_not_found",u)),o=S(r);if(!o)throw new ee("invalid_credentials",`Plugin '${r.id}' has no authType configured`);await mo(e);let i=new Set(Nr(r,o)),a=r.authConfig?.[o]?.integration??[],c=E({authType:o,integrationName:n.plugin,kek:t.kek,database:t.database,extraIntegrationFields:a}),l=0;for(let[u,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(u))throw new ee("invalid_credentials",`Unknown integration credential field '${u}' for plugin '${n.plugin}'`);let g=j(c,`set_${u}`);if(!g)throw new ee("invalid_credentials",`Cannot set integration field '${u}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new ee("invalid_credentials","Provide at least one integration credential field to save");return{plugin:n.plugin}}var tt=new Map;function da(e){for(let[n,t]of tt)t<=e&&tt.delete(n)}function rt(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return da(r),tt.has(t)?{ok:!1,error:"Delivery request already consumed"}:(tt.set(t,r+n),{ok:!0})}async function ot(e,n,t){for(let r of e){if(r.id!==n)continue;let o=r.oauthWebhookTenantLinkResolver;return o?o(t):null}return null}var Lo=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function pa(e){let n=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.pluginId).executeTakeFirst();if(!n)throw new Error(`Integration '${e.pluginId}' not found. Run setupCorsair before registering webhook tenant links.`);let t=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",n.id).executeTakeFirst();if(!t)throw new Error(`Account not found for tenant '${e.tenantId}' and integration '${e.pluginId}'.`);return{integrationId:n.id,accountId:t.id}}async function ga(e){let n=await e.database.db.selectFrom("corsair_accounts").selectAll().where("id","=",e.accountId).executeTakeFirst();if(!n?.dek)throw new Error(`Account '${e.accountId}' has no DEK.`);let t=await q(n.dek,e.kek),r=Lo(n.config),o={};Object.keys(r).length>0&&(o=ce(r,t)),o[e.link.linkType]=e.link.externalId;let i=me(o,t);await e.database.db.updateTable("corsair_accounts").set({config:i,updated_at:new Date}).where("id","=",n.id).execute()}async function je(e){let{database:n,kek:t,pluginId:r,tenantId:o,link:i,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await pa({database:n,pluginId:r,tenantId:o}),l=!1;if(s){let u=_({authType:s,integrationName:r,tenantId:o,kek:t,database:n,extraAccountFields:a}),p=`set_${i.linkType}`,g=u[p];typeof g=="function"&&(await g(i.externalId),l=!0)}l||await ga({database:n,kek:t,accountId:c,link:i})}async function Jt(e){let{database:n,kek:t,pluginId:r,linkType:o,externalId:i}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let c=await q(a.dek,t),u=Lo(a.config)[o];if(!u)continue;if(en(u,c)===i)return a}catch{continue}return null}async function it(e){return(await Jt(e))?.tenant_id??null}async function No(e){return it({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}function $o(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType??"oauth_2",status:"ready",connected:!0,verified:!0,webhookLink:e.link}}function jo(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType,status:e.status,connected:e.connected,verified:e.verified,missingFields:e.missingFields,webhookLink:e.webhookLink,webhookSecret:e.webhookSecret}}async function We(e,n){await W({hub:e,path:"/connections/report",body:$o(n),parseResponse:()=>({ok:!0})}).catch(()=>{})}function fa(e,n){try{let t=M(e);W({hub:t,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}catch(t){if(t instanceof ie)return}}async function ya(e){if(!e.hub||!e.database||!e.kek)return;let n={database:e.database,kek:e.kek,plugins:e.plugins};if(!S(e.plugin))return;let r=e.tenantId?.trim()||"default",o=await Ae(n,e.plugin,r);o&&Ko(e.hub,jo({tenantId:r,plugin:e.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:e.verified??o.connected,missingFields:o.missingRequiredFields}))}function Wo(e,n){fa(e,n)}function Ko(e,n){W({hub:e,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}function cn(e){ya(e).catch(()=>{})}async function zt(e,n){let t=w(e);if(!S(n.plugin))return;let o=await Ae(t,n.plugin,n.tenantId);o&&Wo(e,jo({tenantId:n.tenantId.trim()||"default",plugin:n.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:n.verified??o.connected,missingFields:o.missingRequiredFields,webhookLink:n.webhookLink,webhookSecret:n.webhookSecret}))}var Ce=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Ke(e,n){let{plugin:t,tenantId:r,accessToken:o,refreshToken:i,expiresIn:s,scope:a}=n;if(!o.trim())throw new Ce("no_access_token","Managed OAuth delivery missing access_token");let c=w(e,()=>new Ce("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new Ce("no_database","No database configured on corsair instance");let l=U(c,t,p=>new Ce("plugin_not_found",p));await xe(e,r);let u=_({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await u.set_access_token(o),i&&await u.set_refresh_token(i),s&&await u.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await u.set_scope(a);try{let p=await ot(c.plugins,t,{access_token:o,refresh_token:i,scope:a});if(p){try{let g=l.authConfig?.managed?.account??[];await je({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:p,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}c.hub&&We(c.hub,{plugin:t,tenantId:r,link:p,authType:"managed"})}}catch(p){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,p)}return{plugin:t,tenantId:r}}function ma(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function qo(e,n,t=[]){for(let[r,o]of Object.entries(e))if(ma(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=qo(o,n,[...t,r]);if(i)return i}return null}function ha(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function ba(e){let n=e["x-goog-resource-uri"],t=e["x-goog-channel-id"];if(!n||!t)return null;let r={resourceId:e["x-goog-resource-id"]||"",resourceState:e["x-goog-resource-state"]||"",resourceUri:n,channelId:t,channelExpiration:e["x-goog-channel-expiration"]||""};return n.includes("/drive/")&&(r.kind="drive#change"),{message:{data:Buffer.from(JSON.stringify(r)).toString("base64"),messageId:e["x-goog-message-number"]||""}}}async function Zo(e,n,t,r,o){let i=ha(n),s=typeof t=="string"?JSON.parse(t):t;(!s||typeof s=="object"&&Object.keys(s).length===0)&&i["x-goog-resource-uri"]&&(s=ba(i)||s);let c={headers:i,body:s,...r?{query:r}:{}},l=r?.tenantId||"default",u=e.withTenant?e.withTenant(l):e,p=o?.plugin,g=p?[p]:hn;for(let d of g){let y=u[d];if(!y||!y.webhooks||!p&&y.pluginWebhookMatcher&&!y.pluginWebhookMatcher(c))continue;let f=qo(y.webhooks,c);if(!f)continue;let m=f.path.join("."),h={payload:s,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let b=await f.webhook.handler(h),v=!!Object.keys(b.returnToSender||{})?.length;return{plugin:d,action:m,body:s,response:v?{...b?.returnToSender,success:!0}:{success:!0},...b.responseHeaders&&{responseHeaders:b.responseHeaders}}}catch(b){return console.error(`Error executing webhook handler for ${d}.${m}:`,b),{plugin:d,action:m,body:s,response:{success:!1,error:b instanceof Error?b.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}function Se(e){return e.deliveryMode==="auth.credentials"}function un(e){return e.deliveryMode==="connections.sync"}function st(e){return e.deliveryMode==="connect.create_link"}function ln(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function dn(e){return e.deliveryMode==="oauth.tokens"}function at(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!Se(e)&&!un(e)&&!st(e)&&!ln(e)&&!dn(e)}async function ka(e,n){try{return{status:"ok",webhookResponse:{status:200,body:{status:"ok",sync:{encrypted:await an(e,n)}}}}}catch(t){return{status:"failed",retryable:Zt(t),error:t instanceof Error?t.message:"Connections sync delivery failed"}}}async function Ca(e,n){try{let t=await et(e,n);return{status:"ok",webhookResponse:{status:200,body:{status:"ok",connectUrl:t.connectUrl,expiresAt:t.expiresAt}}}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Connect link delivery failed"}}}function Vt(e,n){if(e instanceof Headers)return e.get(n)??void 0;let t=e[n]??e[n.toLowerCase()];return Array.isArray(t)?t[0]:typeof t=="string"?t:void 0}async function wa(e,n,t){let r=typeof t.tenantId=="string"?t.tenantId:typeof t.query?.tenantId=="string"?t.query.tenantId:void 0;return r||(!n.database||!t.plugin||!t.linkType||!t.externalId?void 0:await it({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function va(e,n,t){let r=await wa(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await Zo(e,t.headers,t.body,o,t.plugin?{plugin:t.plugin}:void 0);if(!i.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(i.response&&i.response.success===!1)return{status:"failed",retryable:!1,error:typeof i.response.error=="string"?i.response.error:"Webhook handler failed"};let s=i.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(i.response?.data??i.response);return{status:"ok",webhookResponse:{status:i.response?.statusCode??200,body:a,headers:i.responseHeaders}}}async function Ta(e,n){return await pn(e,{code:n.code,state:n.state,redirectUri:n.redirectUri,...n.plugin&&n.tenantId?{trusted:!0,plugin:n.plugin,tenantId:n.tenantId}:{}}),{status:"ok"}}async function Pa(e,n){return await Ke(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function Qt(e,n,t){let r=await Yt(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function Yt(e,n,t){let r=w(e),o=n.token?.trim();if(!o)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let i=new Date().toISOString(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",o).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<i?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Aa(e,n){try{return await nt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function xa(e,n){try{return await Gt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Integration credential delivery failed"}}}async function Xt(e,n,t={}){let r=w(e),o=Vt(n.headers,"x-corsair-signature"),i=Vt(n.headers,"x-corsair-timestamp"),s=Vt(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let c=Ne({body:n.body,signatureHeader:o,timestampHeader:i,signingSecret:t.signingSecret});if(!c.ok)return{status:"failed",retryable:!1,error:c.error};if(!s?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let l=rt(`nonce:${s.trim()}`,Te);if(!l.ok)return{status:"failed",retryable:!1,error:l.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let a;try{a=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}if(a.type==="connect.status")return{status:"failed",retryable:!1,error:"connect.status is deprecated; use connections.sync signed delivery instead"};switch(a.type){case"webhook":return va(e,r,a.payload);case"oauth.callback":return Ta(e,a.payload);case"oauth.tokens":return Pa(e,a.payload);case"permission.approve":return Yt(e,a.payload,"approved");case"permission.deny":return Yt(e,a.payload,"denied");case"auth.credentials":return Aa(e,a.payload);case"integration.credentials":return xa(e,a.payload);case"connect.create_link":return Ca(e,a.payload);case"connections.sync":{let c=t.signingSecret?.trim();return c?ka(e,c):{status:"failed",retryable:!1,error:"Tunnel signing secret is required for connections.sync"}}default:return Ia(String(a.type))}}function Ia(e){return Gr.has(e)?{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}:{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}}var er=new Map;function Go(e){let n;try{n=M(e)}catch{return}let t=wt(n);t&&er.get(n.projectApiKey)!==t&&(er.set(n.projectApiKey,t),W({hub:n,path:"/apps/announce",body:{deliveryUrl:t},parseResponse:()=>({ok:!0})}).catch(()=>{er.delete(n.projectApiKey)}))}var Sa=[".corsair.dev"];function Ra(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function _a(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Ra(n)?!0:Sa.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Jo(e){return!e||!_a(e)?null:{"Access-Control-Allow-Origin":e,"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"content-type, x-corsair-signature, x-corsair-timestamp, x-corsair-project, x-corsair-nonce, access-control-request-private-network","Access-Control-Allow-Private-Network":"true","Access-Control-Max-Age":"0",Vary:"Origin"}}function zo(e,n){if(!n)return e;let t=new Headers(e.headers);for(let[r,o]of Object.entries(n))t.set(r,o);return new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function nr(e,n){let t=new URL(e);return n.error?(t.searchParams.set("error",n.error),t.toString()):n.connectedPlugin?(t.searchParams.set("connected",n.connectedPlugin),t.toString()):(n.status!==void 0&&t.searchParams.set("status",Buffer.from(JSON.stringify(n.status)).toString("base64url")),t.toString())}async function tr(e,n){let t=M(e),o=new URL(n).searchParams.get("d");if(!o)return{type:"json",status:200,body:{status:"ok",message:"Corsair tunnel endpoint is active",timestamp:new Date().toISOString()}};let i=fe(o,t.signingSecret);if(!i)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let s=rt(`browser:${i.jti}`,ge);if(!s.ok)return{type:"json",status:400,body:{error:s.error}};try{if(un(i)){if(!i.hubOrigin||!i.requestId)return{type:"json",status:400,body:{error:"Connections sync delivery requires hubOrigin and requestId for client bridge"}};let a=await an(e,t.signingSecret);return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:De({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",sync:{encrypted:a}}})}}if(st(i)){if(!i.hubOrigin||!i.requestId)return{type:"json",status:400,body:{error:"Connect link delivery requires hubOrigin and requestId for client bridge"}};let a=i.connectLinkPlugins?.filter(Boolean)??[];if(a.length===0)return{type:"json",status:400,body:{error:"Connect link delivery requires at least one plugin in connectLinkPlugins"}};let c=await et(e,{tenantId:i.tenantId,plugins:a});return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:De({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",connectUrl:c.connectUrl,expiresAt:c.expiresAt}})}}if(Se(i))return i.hubSuccessUrl?i.credentials?(await nt(e,{plugin:i.plugin,tenantId:i.tenantId,credentials:i.credentials}),{type:"redirect",url:nr(i.hubSuccessUrl,{connectedPlugin:i.plugin})}):{type:"redirect",url:nr(i.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(ln(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await Qt(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(dn(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Ke(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!at(i)||!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await pn(e,{code:i.code,state:i.state,redirectUri:i.redirectUri,trusted:!0,plugin:i.plugin,tenantId:i.tenantId})}}catch(a){let c=a instanceof Error?a.message:"Hub delivery failed";return un(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:De({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:st(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:De({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:Se(i)&&i.hubSuccessUrl?{type:"redirect",url:nr(i.hubSuccessUrl,{error:c})}:Se(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:De({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:{type:"json",status:400,body:{error:c}}}return{type:"redirect",url:i.hubSuccessUrl}}async function rr(e,n){let t=M(e),r=await Xt(e,n,{signingSecret:t.signingSecret});if(r.status!=="ok")return{type:"json",status:r.retryable===!1?400:502,body:{error:r.error??"Tunnel processing failed"}};let o=r.webhookResponse;if(!o)return{type:"json",status:200,body:{status:"ok"}};let i=o.status??200,s=o.headers;return o.body&&typeof o.body=="object"&&!(o.body instanceof ArrayBuffer)?{type:"json",status:i,body:o.body,headers:s}:{type:"text",status:i,body:typeof o.body=="string"?o.body:o.body?JSON.stringify(o.body):null,headers:s}}function or(e){if(e.type==="redirect")return Response.redirect(e.url,302);let n=new Headers;for(let[t,r]of Object.entries(e.headers??{}))typeof r=="string"&&n.set(t,r);return e.type==="json"?Response.json(e.body,{status:e.status,headers:n}):new Response(e.body,{status:e.status,headers:n})}async function ir(e,n){return n.method==="GET"?tr(e,n.url):rr(e,{headers:n.headers,body:n.body??""})}async function sr(e,n){try{let t=await ir(e,n);return or(t)}catch(t){if(t instanceof ie)return Response.json({error:t.message},{status:503});throw t}}async function Re(e,n){Go(e);let t=n.method.toUpperCase(),r=Jo(n.headers.get("origin"));if(t==="OPTIONS")return r?new Response(null,{status:204,headers:r}):Response.json({error:"Method not allowed"},{status:405});if(t!=="GET"&&t!=="POST")return Response.json({error:"Method not allowed"},{status:405});let o=await sr(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return zo(o,r)}var ne=class extends Error{pluginId;authType;constructor(n,t,r){super(r??`[auth-missing:${n}:${t}]`),Object.setPrototypeOf(this,new.target.prototype),this.name="AuthMissingError",this.pluginId=n,this.authType=t}};var Vo=300;async function ar(e,n){let{keys:t,hub:r,plugin:o,tenantId:i}=e,s=n?.forceRefresh??!1,[a,c,l]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!a&&!l)throw new ne(o,"managed");let u=Math.floor(Date.now()/1e3);if(!s&&a&&c&&Number(c)>u+Vo)return{accessToken:a,expiresAt:Number(c),refreshed:!1};if(!l&&a&&!s){let d=c?Number(c):null;if(d===null||d>u+Vo)return{accessToken:a,expiresAt:d??u+3600,refreshed:!1}}let p=await Da(r,o,i),g=p.expires_in?u+p.expires_in:c?Number(c):u+3600;return await t.set_access_token(p.access_token),await t.set_expires_at(String(g)),p.refresh_token&&await t.set_refresh_token(p.refresh_token),p.scope&&await t.set_scope(p.scope),{accessToken:p.access_token,expiresAt:g,refreshed:!0}}function Ea(e){return e.includes("Managed OAuth connection not found")||e.includes("Managed OAuth connection has no tokens")}async function Da(e,n,t){try{return await W({hub:e,path:"/oauth/refresh",body:{plugin:n,tenantId:t},parseResponse:Pn})}catch(r){let o=r instanceof Error?r.message:"";throw Ea(o)?new ne(n,"managed"):r}}async function Yo(e,n){e._refreshAuth=async()=>(await ar(n,{forceRefresh:!0})).accessToken}function Qo(e){return{delivery:n=>Re(e,n),deliveryOptions:n=>Re(e,n)}}var Xo=1200*1e3;function cr(){return oe()}function ur(){return Xo}function lr(e,n){return Ye(e,n,Xo)}function dr(e,n){return Q(e,n)}function pr(e){return Pe(e)}var ei=600*1e3;function gr(){return oe()}function fr(){return ei}function yr(e,n){return Ye(e,n,ei)}function mr(e,n){return Q(e,n)}function hr(e){return kt(e)}function br(e){return Pe(e)}function kr(){return oe()}function Cr(e,n,t){return bn(e,n,Math.floor(t.getTime()/1e3))}function wr(e,n){return Q(e,n)}function vr(e){return Pe(e)}function ct(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(o,i){let s=t.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${t.join(" and ")} ${s?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
24
-
25
- To generate a KEK, run: openssl rand -base64 ${Xe}`)}})}async function Oa(e){let n=!1;for(;;){let t=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.integrationName).executeTakeFirst();if(!t){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Integration "${e.integrationName}" not found. Make sure to create the integration first.`)}let r=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",t.id).executeTakeFirst();if(!r){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Account not found for tenant "${e.tenantId}" and integration "${e.integrationName}". Make sure to create the account first.`)}return{integrationId:t.id,accountId:r.id,integration:{id:t.id,config:t.config,dek:t.dek??null},account:{id:r.id,config:r.config,dek:r.dek??null}}}}async function ni(e){let{integrationId:n,accountId:t}=await Oa(e);return{integrationId:n,accountId:t}}function Tr(e,n){return`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${n}`}async function Ma(e,n){let t=e.hub;if(!t||!n.database||!n.kek)return null;try{return(await St(t,{tenantId:n.tenantId,plugin:n.plugin,database:n.database,kek:n.kek,plugins:n.plugins})).connectUrl}catch{return null}}async function Ha(e){let n=e.hub;if(n&&e.database&&e.kek)try{let r=await St(n,{tenantId:e.tenantId,plugin:e.plugin,database:e.database,kek:e.kek,plugins:e.plugins});return e.manual?.onAuthMissing?e.manual.onAuthMissing({plugin:e.pluginId,connectUrl:r.connectUrl,state:r.token}):Tr(e.pluginId,r.connectUrl)}catch{return`[auth-missing:${e.pluginId}:${e.authType}] Authentication required. Could not create connect link. Check hub configuration and server logs.`}let t=await Ma({manual:e.manual,hub:e.hub},{plugin:e.plugin,tenantId:e.tenantId,database:e.database,kek:e.kek,plugins:e.plugins});return t?Tr(e.pluginId,t):`[auth-missing:${e.pluginId}:${e.authType}]`}function Fa(e,n,t){let r=Fe(be(e,n.tenantId??t??"default"),n.kek),o=new URL(n.baseUrl);o.searchParams.set("state",r);let i=o.toString();return n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:i,state:r}):Tr(e,i)}async function ti(e){let n=e.tenantId??"default",t=e.error.pluginId;return e.manual&&Ue(e.manual)&&e.manual.oauthConfig&&e.manual.kek&&e.error.authType==="oauth_2"?Fa(t,{...e.manual,baseUrl:e.manual.baseUrl,kek:e.manual.kek},e.tenantId):e.hub&&e.plugin&&e.kek&&e.database&&e.plugins?Ha({manual:e.manual,hub:e.hub,plugin:e.plugin,pluginId:t,tenantId:n,authType:e.error.authType,database:e.database,kek:e.kek,plugins:e.plugins}):e.error.message}var Ua=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function ri(e,n,t,r,o){let i={pluginId:n,operation:t,input:r,originalError:e},s=Object.keys(o).find(l=>o[l]?.match(e,i));return await(o[s||"DEFAULT"]?.handler||Ua)(e,i)}function Ba(e){return typeof e=="function"}function Pr({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:o,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:c,endpointMeta:l,database:u,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:y,plugin:f,kek:m,allPlugins:h}){for(let[b,v]of Object.entries(e)){let O=n?.[b];if(Ba(v)){let T=O,A=[...s,b].join("."),k=async(C={})=>{let P;if(c){let F=l?.[A],{result:yn,reason:V,onComplete:Je,token:re,id:ve,expiresAt:K}=await Io({pluginId:o,endpointPath:A,args:C,mode:c.mode,override:c.overrides?.[A],riskLevel:F?.riskLevel??"write",meta:F,db:u,timeoutMs:p?Ut(p.timeout):void 0,tenantId:g,approvalMode:p?.mode});if(yn==="blocked"){let Y;throw V==="denied"?Y=`Action '${A}' was denied by the user. Await further instructions before proceeding.`:V==="policy"?Y=`Action '${A}' is blocked by the permission policy. Update the corsair config to allow it.`:V==="timeout"?Y=`Action '${A}' timed out waiting for approval.`:re&&ve?Y=await Ft({permissionsOptions:p,manual:d,hub:y,permissionId:ve,permissionToken:re,plugin:o,endpoint:A,args:C,tenantId:g??"default",expiresAt:K??new Date(Date.now()+(p?Ut(p.timeout):600*1e3)).toISOString(),operationPath:A}):Y=`Action '${A}' requires user approval before it can run.`,new Error(Y)}P=Je}let N=async(F,yn,V)=>{try{return await v(yn,V)}catch(Je){if(Je instanceof Error){let re=await ri(Je,o,A,typeof V=="object"&&V!==null?V:{args:V},i);if(F<(re.maxRetries||0)){let ve=F+1;console.log(`Retrying (${ve} / ${re.maxRetries})...`);let K;if(re.headersRetryAfterMs)K=re.headersRetryAfterMs;else switch(re.retryStrategy){case"exponential_backoff":K=Math.pow(2,ve-1)*1e3;break;case"exponential_backoff_jitter":let Y=Math.pow(2,ve-1)*1e3,Ei=(Math.random()-.5)*1e3;K=Math.max(0,Y+Ei);break;case"linear_1s":K=1e3;break;case"linear_2s":K=2e3;break;case"linear_3s":K=3e3;break;case"linear_4s":K=4e3;break;default:K=1e3;break}await new Promise(Y=>setTimeout(Y,K)),await N(ve,yn,V),console.log(`[corsair:${o}:${A}] Retry strategy:`,re)}}throw Je}},te;try{te=a?await a(t,"endpoint"):void 0}catch(F){if(F instanceof ne)return f&&y&&cn({hub:y,database:u,kek:m,plugins:h??[],plugin:f,tenantId:g,verified:!1}),ti({error:F,manual:d,hub:y,plugin:f,tenantId:g,database:u,kek:m,plugins:h});throw F}if(!T?.before&&!T?.after){let F=await N(0,{...t,key:te},C);return await P?.(),f&&y&&cn({hub:y,database:u,kek:m,plugins:h??[],plugin:f,tenantId:g,verified:!0}),F}let I={...t,key:te},$=T.before?await T.before(I,C):{ctx:I,args:C,continue:!0,passToAfter:void 0};if($.continue===!1)return;let Ge=await N(0,$.ctx,$.args);return await T.after?.($.ctx,Ge,$.passToAfter),await P?.(),f&&y&&cn({hub:y,database:u,kek:m,plugins:h??[],plugin:f,tenantId:g,verified:!0}),Ge};r[b]=k}else if(v&&typeof v=="object"){let T={};Pr({endpoints:v,hooks:O,ctx:t,tree:T,pluginId:o,errorHandlers:i,currentPath:[...s,b],keyBuilder:a,permissionsConfig:c,endpointMeta:l,database:u,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:y,plugin:f,kek:m,allPlugins:h}),r[b]=T}}}function La(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Ar({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:o}){for(let[i,s]of Object.entries(e)){let a=n?.[i];if(La(s)){let c=a,l=async u=>{let p=(d,y)=>s.handler(d,y),g=o?await o(t,"webhook"):void 0;return!c?.before&&!c?.after?p({...t,key:g},u):(async()=>{let d={...t,key:g},y=c.before?await c.before(d,u):{ctx:d,args:u,continue:!0,passToAfter:void 0};if(y.continue===!1)return;let f=await p(y.ctx,y.args);return f?.success===!0&&await c.after?.(y.ctx,f,y.passToAfter),f})()};r[i]={match:s.match,handler:l}}else if(s&&typeof s=="object"){let c={};Ar({webhooks:s,hooks:a,ctx:t,webhooksTree:c,keyBuilder:o}),r[i]=c}}}function Na(e,n,t,r){let o=null;return async()=>{if(o)return o;if(!e)throw new Error("Database not configured");let{accountId:i}=await ni({database:e,integrationName:n,tenantId:t,ensureProvisioned:r});return o=i,o}}function $a(e,n,t,r,o){return e?mt(e.db,n,t,r,o):{findByEntityId:async()=>null,existsByEntityId:async()=>!1,findIdByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function xr(e,n){let{database:t,tenantId:r,kek:o,rootErrorHandlers:i,permissionsOptions:s,manualConfig:a,hubConfig:c,internalConfig:l}=n,u=l&&t?()=>En(l,r??"default"):void 0,p={},g={};for(let d of e)p[d.id]={},g[d.id]={};for(let d of e){let y=d.schema,f=r??"default",m=Na(t,d.id,f,u);if(y?.entities){let I={};for(let[$,Ge]of Object.entries(y.entities)){let F=t?mt(t.db,m,$,y.version,Ge):$a(void 0,m,$,y.version,Ge);I[$]=F}g[d.id].db=I,p[d.id].db=I}let h=d.options,b=d.authConfig,v;if(t&&o&&h?.authType){let I=b?.[h.authType]?.account??[];v=_({authType:h.authType,integrationName:d.id,tenantId:f,kek:o,database:t,extraAccountFields:I,ensureProvisioned:u}),p[d.id].keys=v}let O={database:t,db:g[d.id]?.db??{},$getAccountId:m,...d.options?{options:d.options}:{},...v?{keys:v,authType:h?.authType}:{},tenantId:f,...c?{hub:c}:{}},T=d.endpoints??{},A=d.hooks,k={...i,...d.errorHandlers},C={},P=d.options?.permissions;Pr({endpoints:T,hooks:A,ctx:O,tree:C,pluginId:d.id,errorHandlers:k,currentPath:[],keyBuilder:d.keyBuilder,permissionsConfig:P,endpointMeta:d.endpointMeta,database:t,permissionsOptions:s,tenantId:r,manualConfig:a?{...a,oauthConfig:d.oauthConfig,kek:o,tenantId:f}:void 0,hubConfig:c,plugin:d,kek:o,allPlugins:e}),Object.keys(C).length>0&&(p[d.id].api=C),O.endpoints=C;let N=d.webhooks??{},te=d.webhookHooks;if(Object.keys(N).length>0){let I={};Ar({webhooks:N,hooks:te,ctx:O,webhooksTree:I,keyBuilder:d.keyBuilder}),p[d.id].webhooks=I,d.pluginWebhookMatcher&&(p[d.id].pluginWebhookMatcher=d.pluginWebhookMatcher),d.pluginTenantWebhookMatcher&&(p[d.id].pluginTenantWebhookMatcher=d.pluginTenantWebhookMatcher)}}return p}function oi(e,n,t){let r={};for(let o of e){let i=o.options,s=o.authConfig;if(i?.authType){let a=s?.[i.authType]?.integration??[],c=E({authType:i.authType,integrationName:o.id,kek:t,database:n,extraIntegrationFields:a});r[o.id]=c}}return r}var ja="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function ii(e){let{permissions:n,approval:t}=e;if(n&&t)throw new Error("createCorsair was given both permissions and approval config. Use permissions only \u2014 approval is deprecated.");return t?(console.warn(`[corsair] ${ja}`),t):n}var si=[{method:"GET",pattern:"/ok",handler:async()=>D(200,Nn())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>D(200,await Le(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>D(201,await Wn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>D(200,await jn(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>D(200,await Be(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>D(200,await $n(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>D(200,await Kn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>D(200,await Bt(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?D(200,await Nt(e,t)):D(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>D(200,await qn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>D(200,await Zn(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>D(200,await Gn(e,n,t))}];(()=>{let e=new Set;for(let n of si){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function Wa(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let o={};for(let i=0;i<t.length;i++){let s=t[i],a=r[i];if(s.startsWith(":"))o[s.slice(1)]=decodeURIComponent(a);else if(s!==a)return null}return o}function Ka(e,n){if(!n)return e;let t=n.endsWith("/")?n.slice(0,-1):n;return e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length):e}async function qa(e){if(!(e.method==="GET"||e.method==="HEAD"||!(e.headers.get("content-type")??"").includes("application/json")))try{let t=await e.text();return t?JSON.parse(t):void 0}catch{throw new R(400,"invalid_json","Request body is not valid JSON")}}var Za="/api/corsair";function _e(e,n={}){let t=n.basePath??Za,r=w(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async o=>{try{let i=new URL(o.url),s=Ka(i.pathname,t),a=o.method.toUpperCase();if(a==="OPTIONS"||s==="/"||s==="")return await Re(e,o);if(a!=="GET"&&a!=="POST")return D(405,{error:"method_not_allowed",message:`Method ${a} not allowed`});let c=Object.fromEntries(i.searchParams);for(let l of si){if(l.method!==a)continue;let u=Wa(l.pattern,s);if(!u)continue;let p=await qa(o);return await l.handler({corsair:e,internal:r,req:o,params:u,query:c,body:p})}throw ke(`No route for ${a} ${s}`)}catch(i){if(n.onError){let a=await n.onError(i,o);if(a)return a}if(i instanceof R)return So(i);let s=i instanceof Error?i.message:"Internal server error";return D(500,{error:"internal_error",message:s})}}}function Ga(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,o=`${t}://${n}${r}`,i=new Headers;for(let[c,l]of Object.entries(e.headers))if(l!=null)if(Array.isArray(l))for(let u of l)i.append(c,u);else i.set(c,l);let s=e.method!=="GET"&&e.method!=="HEAD",a={method:e.method,headers:i};return s&&e.body!==void 0&&(a.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),i.has("content-type")||i.set("content-type","application/json")),new Request(o,a)}async function Ja(e,n){e.status(n.status),n.headers.forEach((r,o)=>e.setHeader(o,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function ai(e,n){let t=_e(e,n);return async(r,o,i)=>{try{let s=await t(Ga(r));await Ja(o,s)}catch(s){i(s)}}}function ci(e,n){let t=_e(e,n);return r=>t(r.req.raw)}function ui(e,n){let t=_e(e,n);return{GET:t,POST:t,OPTIONS:t}}function li(e){let n={[gn]:e};return{ok:Nn,tenants:{list:()=>Le(e),create:t=>Wn(e,t),get:t=>jn(e,t)},plugins:{list:()=>Be(e),get:t=>$n(e,t)},connectionStatus:{get:t=>Kn(e,t?.tenantId)},permissions:{get:t=>Mo(e,t)},connect:{createLink:t=>qn(n,e,t),resolve:t=>Zn(n,e,t),oauthCallback:t=>Gn(n,e,t)}}}async function di(e,n,t,r,o="pending"){if(!e)return null;try{let i=$r(),s=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:s,updated_at:s,account_id:n,event_type:t,payload:r,status:o}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function za(e,n,t,r="pending"){try{let o=await e.$getAccountId();return di(e.database,o,n,t,r)}catch(o){return console.warn("Failed to log event:",o),null}}import*as gi from"https";import*as ut from"querystring";var Va=["expires_in","refresh_token_expires_in"];function pi(e){let n={...e};for(let t of Va){let r=e[t];if(typeof r=="string"){let o=Number(r);n[t]=Number.isFinite(o)?o:void 0}}return n}function Ya(e){try{return pi(JSON.parse(e))}catch{}if(!e.includes("="))return null;let n=ut.parse(e);return!n.access_token&&!n.error?null:pi({...n})}function lt(e,n,t,r,o){let i=new URL(r.tokenUrl),s=r.tokenAuthMethod==="basic";return new Promise((a,c)=>{let l={code:e.trim(),redirect_uri:o,grant_type:"authorization_code"};s||(l.client_id=n,l.client_secret=t);let u=ut.stringify(l),p={"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json","Content-Length":Buffer.byteLength(u).toString()};s&&(p.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=gi.request({hostname:i.hostname,...i.port?{port:Number(i.port)}:{},path:i.pathname+i.search,method:"POST",headers:p},d=>{let y="";d.on("data",f=>{y+=f}),d.on("end",()=>{if(d.statusCode!==200){c(new Error(`Token exchange failed (${d.statusCode}): ${y}`));return}let f=Ya(y);f?a(f):c(new Error(`Token endpoint returned non-JSON response: ${y}`))})});g.on("error",d=>c(new Error(`Request failed: ${d.message}`))),g.write(u),g.end()})}var fi=" ";function J(e){let n=e;return n._def??n.def??{}}function z(e){let n=e.typeName;if(n)return n;let t=e.type;if(t)return`Zod${t.split("_").map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("")}`}function G(e){return e.innerType??e.schema??e.out??e.in}function mi(e,n){switch(n){case"ZodPipe":return e.in??e.innerType;case"ZodEffects":return e.schema??e.innerType;case"ZodTransform":return e.schema??e.innerType??e.in;default:return G(e)}}function hi(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function pt(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function qe(e){return Array.isArray(e.options)?e.options:Array.isArray(e.values)?e.values:e.entries!==null&&typeof e.entries=="object"&&!Array.isArray(e.entries)?Object.values(e.entries):[]}function bi(e,n){return e.description??n.description}function Qa(e){let n=e;for(;n;){let t=J(n),r=bi(n,t);if(r)return r;let o=z(t);if(Er(o)||o==="ZodPipe"||o==="ZodEffects"||o==="ZodTransform"){n=mi(t,o);continue}break}}function Er(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function B(e){let n=J(e),t=z(n);switch(t){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"Date";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(n.value??qe(n)[0]??"unknown");case"ZodEnum":return qe(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=G(n);return r?B(r):"unknown"}case"ZodNullable":{let r=G(n);return`${r?B(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=G(n);return r?B(r):"unknown"}case"ZodArray":{let r=hi(n);if(!r)return"unknown[]";let o=J(r),i=z(o)==="ZodUnion",s=B(r);return`${i?`(${s})`:s}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=pt(e,n),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([s,a])=>{let c=z(J(a));return`${c==="ZodOptional"||c==="ZodNullable"?s+"?":s}: ${B(a)}`}).join(", ")} }`}case"ZodUnion":return qe(n).map(r=>B(r)).join(" | ");case"ZodIntersection":return`${B(n.left)} & ${B(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=mi(n,t);return r?B(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function le(e){let n=J(e),t=z(n),r=bi(e,n);switch(t){case"ZodString":return{kind:"string",optional:!1,description:r};case"ZodNumber":return{kind:"number",optional:!1,description:r};case"ZodBoolean":return{kind:"boolean",optional:!1,description:r};case"ZodLiteral":{let o=n.value??qe(n)[0],i=typeof o=="string"||typeof o=="number"||typeof o=="boolean"?o:String(o??"");return{kind:"literal",optional:!1,description:r,value:i}}case"ZodEnum":{let o=qe(n).map(i=>String(i));return{kind:"string",optional:!1,description:r,enum:o}}case"ZodOptional":{let o=G(n),i=o?le(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodNullable":{let o=G(n),i=o?le(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodDefault":case"ZodCatch":{let o=G(n);return o?{...le(o),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let o=hi(n);return{kind:"array",optional:!1,description:r,items:o?le(o):{kind:"unknown",optional:!1}}}case"ZodObject":{let o=pt(e,n),i={};for(let[s,a]of Object.entries(o))i[s]=le(a);return{kind:"object",optional:!1,description:r,fields:i}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let o=qe(n);for(let i of o){let s=J(i);if(z(s)==="ZodObject")return{...le(i),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let o=G(n);return o?{...le(o),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function qg(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let o=t.slice(0,r),i=t.slice(r+1),s=e.find(u=>u.id===o);if(!s)return null;let a=i;a.startsWith("api.")&&(a=a.slice(4));let c=we(s.endpointMeta,a),l=we(s.endpointSchemas,a);return!c&&!l?null:{input:l?.input?le(l.input):null,output:l?.output?le(l.output):null,description:c?.description}}var Dr=["equals","contains","startsWith","endsWith","in"],Xa=["equals","gt","gte","lt","lte","in"],ec=["equals"],nc=["equals","before","after","between"];function ki(e){let n=J(e);switch(z(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=G(n);return r?ki(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Or(e){let n=J(e),t=z(n);if(Er(t)){let i=G(n);return i?Or(i):{}}if(t!=="ZodObject")return{};let r=pt(e,n),o={};for(let[i,s]of Object.entries(r)){let a=ki(s);a==="string"?o[i]={type:"string",operators:Dr}:a==="number"?o[i]={type:"number",operators:Xa}:a==="boolean"?o[i]={type:"boolean",operators:ec}:a==="date"&&(o[i]={type:"date",operators:nc})}return o}function Ci(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function Sr(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];typeof o=="function"?t.push(i.join(".")):o!==null&&typeof o=="object"&&Sr(o,i,t)}}function Rr(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function _r(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];Rr(o)?t.push(i.join(".")):o!==null&&typeof o=="object"&&_r(o,i,t)}}function Mr(e,n){if(n.length===0)return null;let[t,...r]=n,o=Object.entries(e).find(([a])=>a.toLowerCase()===t);if(!o)return null;let[i,s]=o;if(r.length===0)return Rr(s)?[i]:null;if(s!==null&&typeof s=="object"&&!Rr(s)){let a=Mr(s,r);if(a!==null)return[i,...a]}return null}function wi(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let i=0;i<n.length;i++){let s=" ".repeat(i+2);t.push(`${s}${n[i]}: {`)}let r=" ".repeat(n.length+2),o=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${o}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let i=n.length-1;i>=0;i--){let s=" ".repeat(i+2);t.push(`${s}},`)}return t.push(" },"),t.push("})"),t.join(`
26
- `)}var tc=new Set(hn);function Ee(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let i=e.find(a=>a.id===r);if(!i)return tc.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:Ee(e);if(t==="webhooks"){if(!i.webhooks)return[];let a=[];return _r(i.webhooks,[],a),a.map(c=>`${i.id}.webhooks.${c}`)}if(t==="db"){let a=i.schema?.entities;return a?Object.keys(a).map(c=>`${i.id}.db.${c}.search`):[]}if(!i.endpoints)return[];let s=[];return Sr(i.endpoints,[],s),s.map(a=>`${i.id}.api.${a}`)}let o={};if(t==="webhooks")for(let i of e){if(!i.webhooks)continue;let s=[];_r(i.webhooks,[],s),o[i.id]=s.map(a=>`${i.id}.webhooks.${a}`)}else if(t==="db")for(let i of e){let s=i.schema?.entities;s&&(o[i.id]=Object.keys(s).map(a=>`${i.id}.db.${a}.search`))}else for(let i of e){if(!i.endpoints)continue;let s=[];Sr(i.endpoints,[],s),o[i.id]=s.map(a=>`${i.id}.api.${a}`)}return o}function we(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function rc(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let i=t.slice(n.length+1),s=i.startsWith(".")?i.slice(1):i;return s.startsWith("api.")&&(s=s.slice(4)),{shortPath:s,lookupKey:s}}let o=e.slice(n.length+1);return o.toLowerCase().startsWith("api.")&&(o=o.slice(4)),{shortPath:o,lookupKey:o.toLowerCase()}}function Ir(e,n){return typeof e=="string"?e:Array.isArray(e)?`${n}:
27
- ${e.join(", ")}`:`${n}:
28
- `+Object.entries(e).map(([t,r])=>` ${t}: ${r.join(", ")}`).join(`
29
- `)}function Zg(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let o=t.slice(0,r),i=t.slice(r+1),s=e.find(a=>a.id===o);if(s){if(i.startsWith("db.")){let u=i.slice(3),p=u.lastIndexOf(".");if(p!==-1){let g=u.slice(0,p),d=u.slice(p+1),y=s.schema?.entities;if(d==="search"&&y){let f=Ci(y,g);if(f){let[m,h]=f,b=Or(h),v=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Dr.join(", ")}]`];for(let[O,T]of Object.entries(b))v.push(` ${O}?: ${T.type} [${T.operators.join(", ")}]`);return v.push("}"),v.join(`
30
- `)}}}return Ir(Ee(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let u=i.slice(9);if(s.webhooks){let p=Mr(s.webhooks,u.split("."));if(p!==null){let g=p.join("."),d=we(s.webhookSchemas,g.toLowerCase()),y=d?.response?B(d.response):null,f=[];return d?.description&&f.push(d.description),d?.payload&&f.push(`payload ${dt(Ze(d.payload))}`),y&&f.push(`response: ${y}`),f.push(`usage:
31
- ${wi(o,p)}`),f.join(`
32
-
33
- `)}}return Ir(Ee(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=i;a.startsWith("api.")&&(a=a.slice(4));let c=we(s.endpointMeta,a),l=we(s.endpointSchemas,a);if(c||l){let u=[],p=[c?.riskLevel?`[${c.riskLevel}]`:"",c?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),g=[c?.description,p].filter(Boolean).join(" ");return g&&u.push(g),l?.input&&u.push(`input ${dt(Ze(l.input))}`),l?.output&&u.push(`output ${dt(Ze(l.output))}`),u.join(`
34
-
35
- `)}}}return Ir(Ee(e),"Path not found. Available operations")}function yi(e){let n=e;for(;;){let t=J(n),r=z(t);if(Er(r)){let o=G(t);if(!o)return n;n=o;continue}return n}}function Ze(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=yi(e),t=J(n);if(z(t)==="ZodObject"){let o=pt(n,t),i=[];for(let[s,a]of Object.entries(o)){let c=J(a),l=z(c),u=l==="ZodOptional"||l==="ZodNullable",p=yi(a),g=Qa(a);i.push({key:s,optional:u,type:B(p),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:i}}return{kind:"inline",type:B(n)}}function dt(e,n=0){if(e===void 0)return"{}";if(e.kind==="inline")return e.type;if(e.kind==="object"){if(e.fields.length===0)return"{}";let t=fi.repeat(n+1),r=fi.repeat(n);return`{
36
- ${e.fields.map(i=>{let s=i.optional?`${i.key}?`:i.key,a=i.description?` // ${i.description}`:"";return`${t}${s}: ${i.type}${a}`}).join(`
37
- `)}
38
- ${r}}`}return"unknown"}function oc(e,n){let t=Ee(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(u=>u.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let o=[];for(let u of t){let{shortPath:p,lookupKey:g}=rc(u,n),d=we(r.endpointMeta,g),y=we(r.endpointSchemas,g);!d&&!y||o.push({path:u,shortPath:p,description:d?.description,riskLevel:d?.riskLevel,irreversible:d?.irreversible,input:Ze(y?.input),output:Ze(y?.output)})}o.sort((u,p)=>u.path.localeCompare(p.path));let i=[],s=Ee(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let u of s){let g=u.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("webhooks."))continue;let y=d.slice(9),f=Mr(r.webhooks,y.split("."));if(f===null)continue;let m=f.join("."),h=we(r.webhookSchemas,m.toLowerCase()),b=h?.response?B(h.response):void 0;i.push({path:u,description:h?.description,payload:Ze(h?.payload),responseType:b,usageExample:wi(n,f)})}i.sort((u,p)=>u.path.localeCompare(p.path));let a=[],c=Ee(e,{plugin:n,type:"db"}),l=r.schema?.entities;if(Array.isArray(c)&&l)for(let u of c){let g=u.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("db."))continue;let y=d.slice(3),f=y.lastIndexOf(".");if(f===-1)continue;let m=y.slice(0,f);if(y.slice(f+1)!=="search")continue;let b=Ci(l,m);if(!b)continue;let[v,O]=b,T=Or(O),A=Object.entries(T).map(([k,C])=>({field:k,type:C.type,operators:C.operators}));a.push({path:u,entityName:v,filters:[{field:"entity_id",type:"string",operators:Dr},...A]})}return a.sort((u,p)=>u.path.localeCompare(p.path)),{ok:!0,data:{pluginId:n,api:o,webhooks:i,db:a}}}import{randomUUID as vi}from"crypto";async function ic(e,n){let t=await e.keys.get_access_token();if(!t)return null;let r=vi(),o=vi(),i=await fetch(n.watchUrl,{method:"POST",signal:AbortSignal.timeout(2e4),headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({id:r,type:"web_hook",address:n.webhookUrl,token:o,...n.body})});if(!i.ok)throw new Error(`Google channel watch failed (${i.status}): ${await i.text()}`);return{webhookLink:{linkType:"channel_id",externalId:r},webhookSecret:o}}import{randomUUID as sc}from"crypto";var gt="https://graph.microsoft.com/v1.0",Hr=2e4,ac=60;async function cc(e,n){let t=await e.keys.get_access_token();if(!t)return null;let r={authorization:`Bearer ${t}`};try{let c=await fetch(`${gt}/subscriptions`,{headers:r,signal:AbortSignal.timeout(Hr)});if(c.ok){let{value:l}=await c.json(),u=(l??[]).filter(p=>p.notificationUrl===n.webhookUrl);await Promise.all(u.map(p=>fetch(`${gt}/subscriptions/${p.id}`,{method:"DELETE",headers:r,signal:AbortSignal.timeout(Hr)}).catch(()=>{})))}}catch{}let o=sc(),i=new Date(Date.now()+ac*6e4).toISOString(),s=await fetch(`${gt}/subscriptions`,{method:"POST",headers:{...r,"content-type":"application/json"},signal:AbortSignal.timeout(Hr),body:JSON.stringify({changeType:n.changeType,notificationUrl:n.webhookUrl,resource:n.resource,expirationDateTime:i,clientState:o})});if(!s.ok)throw new Error(`MS Graph subscribe failed (${s.status}): ${await s.text()}`);let a=await s.json();return a.id?(await e.keys.set_webhook_signature(o),{webhookLink:{linkType:"subscription_id",externalId:a.id},webhookSecret:o}):null}function Ti(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function uc(e,n){let t=Ti(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let o=r.pluginTenantWebhookMatcher(n);return o?{plugin:t,tenantMatch:o}:null}function lc(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function Pi(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function Ai(e){if(typeof e=="string"){let n=e.trim();return n.length>0?n:void 0}if(typeof e=="number"&&Number.isFinite(e))return String(e)}function fn(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function dc(e){return fn(e.body)}function xi(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return ft(Array.isArray(r)?r:[r])}function Ii(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let c of t){let l=ft(Array.isArray(c)?c:[c]);if(l)return decodeURIComponent(l)}let r=xi({query:e.query},"validationToken");if(r)return r;let o=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let c of o){let l=n[c],u=Array.isArray(l)?l[0]:l;if(!(!u||typeof u!="string"))try{let g=(u.startsWith("http")?new URL(u):new URL(`https://example.invalid${u.startsWith("/")?u:`/${u}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let i=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,s=fn(typeof i=="string"?(()=>{try{return JSON.parse(i)}catch{return i}})():i);return ft([s?.validationToken])??null}function pc(e){if(Ii(e))return!0;let n=fn(e.body??e.payload);return Pi(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function ft(e){for(let n of e){let t=Ai(n);if(t)return t}}function gc(e){let t=fn(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var gn=Symbol.for("corsair:internal");function yo(e){let n=e.database?Fr(e.database):void 0,t=n&&e.kek?oi(e.plugins,n,e.kek):ct(!!n,!!e.kek),r=ii(e),o={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?kn(e.hub):void 0},i=xo(n),s=li(o);if(e.multiTenancy)return Object.assign({withTenant:c=>{if(!c)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let l=xr(e.plugins,{database:n,tenantId:c,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign(l,{[gn]:o})},keys:t,permissions:i,manage:s},{[gn]:o});let a=xr(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign({},a,{keys:t,permissions:i,manage:s,[gn]:o})}async function Si(e,n){try{return await xn({hub:e,path:`/webhooks/endpoint?plugin=${encodeURIComponent(n)}`,parseResponse:t=>t?.url??null})}catch{return null}}async function yt(e,n,t,r){if(!n.subscribe)return;let o=M(e),i=await Si(o,n.id);if(!i)return;let s=await n.subscribe({keys:r},{webhookUrl:i});s&&await zt(e,{plugin:n,tenantId:t,verified:!0,webhookLink:s.webhookLink,webhookSecret:s.webhookSecret})}var L=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function Ri(e){let n=e.oauthConfig;if(!n)throw new L("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function fc(e,n,t,r){let o=Wr(e),i=await o.integrations.findByName(n);if(!i)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await o.accounts.findOne({tenant_id:t,integration_id:i.id}))return;let a=se(),c=await ae(a,r);await o.accounts.create({tenant_id:t,integration_id:i.id,config:{},dek:c})}async function xt(e,n,t){let{tenantId:r,redirectUri:o,hubConnect:i=!1}=t,s=w(e,()=>new L("invalid_corsair_instance","Invalid corsair instance"));if(!s.database)throw new Error("No database configured on corsair instance");let a=U(s,n,g=>new L("plugin_not_found",g)),c=Ri(a),u=await E({authType:"oauth_2",integrationName:n,kek:s.kek,database:s.database}).get_client_id();if(!u)throw new Error(`client_id not configured for '${n}'`);if(i){let g=new URL(Ie({oauthConfig:c,clientId:u,redirectUri:o,state:""}));return g.searchParams.delete("state"),{url:g.toString(),state:""}}let p=Fe(be(n,r),s.kek);return{url:Ie({oauthConfig:c,clientId:u,redirectUri:o,state:p}),state:p}}async function pn(e,n){let{code:t,state:r,redirectUri:o}=n,i=w(e,()=>new L("invalid_corsair_instance","Invalid corsair instance")),s,a;if(n.trusted){if(!n.plugin||!n.tenantId)throw new L("invalid_state","trusted callback requires plugin and tenantId");s=n.plugin,a=n.tenantId}else{let f=Fn(r,i.kek);if(!f)throw new L("invalid_state","Invalid or tampered state parameter");s=f.plugin,a=f.tenantId}if(!i.database)throw new L("no_database","No database configured on corsair instance");let c=U(i,s,f=>new L("plugin_not_found",f)),l=Ri(c),u=E({authType:"oauth_2",integrationName:s,kek:i.kek,database:i.database}),p=await u.get_client_id(),g=await u.get_client_secret();if(!p||!g)throw new L("credentials_not_configured",`Credentials not configured for '${s}'`);await fc(i.database,s,a,i.kek);let d=await lt(t,p,g,l,o);if(!d.access_token)throw new L("no_access_token",`No access_token returned from ${l.providerName}`);let y=_({authType:"oauth_2",integrationName:s,tenantId:a,kek:i.kek,database:i.database,extraAccountFields:[...c.authConfig?.oauth_2?.account??[]]});await y.set_access_token(d.access_token),d.refresh_token&&await y.set_refresh_token(d.refresh_token),d.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+d.expires_in));try{let f=await ot(i.plugins,s,d);if(f){try{let m=c.authConfig?.oauth_2?.account??[];await je({database:i.database,kek:i.kek,pluginId:s,tenantId:a,link:f,authType:"oauth_2",extraAccountFields:m})}catch(m){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${s}' tenant '${a}':`,m)}i.hub&&We(i.hub,{plugin:s,tenantId:a,link:f,authType:"oauth_2"})}}catch(f){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${s}' tenant '${a}':`,f)}if(c.subscribe)try{await yt(e,c,a,y)}catch(f){console.warn(`[corsair:oauth] BYO subscribe failed for '${s}' tenant '${a}':`,f)}return{plugin:s,tenantId:a}}async function yc(e){let{corsair:n,internal:t,rows:r}=e,o=e.subscribeAndReport??yt,i=[],s=[];if(!t.database)return{renewed:i,failed:s};for(let a of r){let c=t.plugins.find(u=>u.id===a.integrationName);if(!c?.subscribe)continue;let l=`${c.id}/${a.tenantId}`;try{let u=_({authType:"oauth_2",integrationName:c.id,tenantId:a.tenantId,kek:t.kek,database:t.database,extraAccountFields:[...c.authConfig?.oauth_2?.account??[]]}),p=c.keyBuilder;if(p){let g=Object.create(u,{get_expires_at:{value:async()=>"0"}});await p({authType:"oauth_2",keys:g},"endpoint")}await o(n,c,a.tenantId,u),i.push(l)}catch(u){console.warn(`[corsair:renewal] re-subscribe failed for '${l}':`,u),s.push(l)}}return{renewed:i,failed:s}}async function _i(e){let n=w(e);if(!n.database)return{renewed:[],failed:[]};let t=await n.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id as tenantId","i.name as integrationName"]).where("a.dek","is not",null).execute();return yc({corsair:e,internal:n,rows:t.filter(r=>!!r.tenantId)})}function mc(e,n={}){let t=!1,r=()=>{t||(t=!0,_i(e).catch(i=>console.warn("[corsair:renewal] renewal pass failed:",i)).finally(()=>{t=!1}))};r();let o=setInterval(r,(n.intervalMinutes??45)*6e4);return o.unref?.(),()=>clearInterval(o)}export{Kr as a,pe as b,bt as c,ze as d,qr as e,Zr as f,ge as g,Te as h,oe as i,Oe as j,Me as k,fe as l,Ct as m,zr as n,Qe as o,ie as p,kn as q,M as r,Cn as s,He as t,wn as u,vn as v,Tn as w,Pn as x,Yr as y,An as z,ye as A,se as B,ae as C,q as D,vt as E,en as F,me as G,ce as H,nn as I,E as J,_ as K,ao as L,co as M,be as N,Rt as O,We as P,je as Q,Jt as R,it as S,No as T,Ie as U,L as V,xt as W,pn as X,_i as Y,mc as Z,On as _,Is as $,Mn as aa,wu as ba,It as ca,vu as da,ko as ea,St as fa,Hn as ga,wo as ha,vo as ia,Et as ja,Un as ka,Bn as la,Jn as ma,jt as na,Ne as oa,$e as pa,zn as qa,Vn as ra,on as sa,Wt as ta,Kt as ua,Yn as va,sn as wa,Qn as xa,Xn as ya,Ce as za,Ke as Aa,Zo as Ba,Se as Ca,ln as Da,dn as Ea,at as Fa,Qt as Ga,Xt as Ha,tr as Ia,rr as Ja,or as Ka,ir as La,sr as Ma,Re as Na,ne as Oa,ar as Pa,Yo as Qa,Qo as Ra,cr as Sa,ur as Ta,lr as Ua,dr as Va,pr as Wa,gr as Xa,fr as Ya,yr as Za,mr as _a,hr as $a,br as ab,kr as bb,Cr as cb,wr as db,vr as eb,_e as fb,ai as gb,ci as hb,ui as ib,di as jb,za as kb,lt as lb,qg as mb,Ee as nb,Zg as ob,dt as pb,oc as qb,ic as rb,gt as sb,cc as tb,Ti as ub,uc as vb,lc as wb,Pi as xb,Ai as yb,fn as zb,dc as Ab,xi as Bb,Ii as Cb,pc as Db,ft as Eb,gc as Fb,gn as Gb,yo as Hb};