corsair 0.1.84 → 0.1.87

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.
@@ -0,0 +1,38 @@
1
+ import{a as se,b as nr,c as P,d as $,e as tr,f as J,g as E,h as H,i as en,j as rr,k as qn,l as or,m as ir}from"./chunk-NZS35HPL.js";import{a as er}from"./chunk-IGGCNGU2.js";var nn=["ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gitlab","gmail","googlecalendar","googledrive","googlesheets","grafana","hackernews","hubspot","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],sr={ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",cursor:"Cursor",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledrive:"Google Drive",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",intercom:"Intercom",jira:"Jira",linear:"Linear",monday:"Monday",notion:"Notion",onedrive:"OneDrive",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",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"};function ae(e){let n=sr[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var Ne="https://auth.corsair.dev";var he=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret, deliveryUrl } to createCorsair()."),this.name="HubNotConfiguredError"}};function tn(e){let n=(e.apiUrl?.trim()||Ne).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim(),i=e.deliveryUrl.trim();if(!t||!r||!i)throw new Error("Hub config requires non-empty projectApiKey, signingSecret, and deliveryUrl");return{apiUrl:n,projectApiKey:t,signingSecret:r,deliveryUrl:i,oauthCallbackUrl:e.oauthCallbackUrl?.trim()}}function vo(e){return e.apiUrl.trim().length>0&&e.deliveryUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function B(e){let n=P(e).hub;if(!n||!vo(n))throw new he;return n}function rn(e){return e.oauthCallbackUrl?e.oauthCallbackUrl:`${e.apiUrl.replace(/\/$/,"")}/oauth/callback`}function R(e){return typeof e=="string"&&e.length>0}function on(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!R(n.connectUrl)||!R(n.token)||!R(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};return R(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function sn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!R(n.approvalUrl)||!R(n.token)||!R(n.projectId)||!R(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(!R(n.access_token))throw new Error("Hub token refresh returned no access_token");return{access_token:n.access_token,refresh_token:R(n.refresh_token)?n.refresh_token:void 0,expires_in:typeof n.expires_in=="number"?n.expires_in:void 0,scope:R(n.scope)?n.scope:void 0}}function Ao(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function xo(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;R(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 So(e,n,t,r){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"?e:n?"ready":t.some(o=>o.level==="integration"&&o.required&&!o.configured)?"missing_integration":t.some(o=>o.level==="account"&&o.required&&o.configured)?"partial":(r.length>0,"not_started")}function ar(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!R(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 i=r;if(!R(i.plugin)||typeof i.connected!="boolean")continue;let o=i.authKind==="oauth"||i.authKind==="api_key"||i.authKind==="bot_token"?i.authKind:"api_key",a=xo(i.fields),s=Ao(i.missingRequiredFields),u=So(i.status,i.connected,a,s);t.push({plugin:i.plugin,providerName:R(i.providerName)?i.providerName:i.plugin,authKind:o,status:u,connected:i.connected,fields:a,missingRequiredFields:s})}return{tenantId:n.tenantId,plugins:t}}function un(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}function Ro(e){return e.replace(/\/$/,"")}async function Io(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 _o(e,n,t){if(n===404&&t)return t;let r=un(e);return r||`Hub API returned HTTP ${n}`}async function Ae(e){let n=Ro(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.hub.projectApiKey}`},body:JSON.stringify(e.body)}),r=await Io(t);if(!t.ok)throw new Error(_o(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as ur,createDecipheriv as cr,randomBytes as cn,scrypt as Eo}from"crypto";import{promisify as Do}from"util";var lr=Do(Eo),ln="aes-256-gcm",dr=12,dn=16,Oo=16,$e=32;function ee(){return cn($e).toString("base64")}async function ne(e,n){let t=cn(Oo),r=await lr(n,t,$e),i=cn(dr),o=ur(ln,r,i,{authTagLength:dn}),a=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[t.toString("base64"),i.toString("base64"),s.toString("base64"),a.toString("base64")].join(":")}async function L(e,n){let[t,r,i,o]=e.split(":");if(!t||!r||!i||!o)throw new Error("Invalid encrypted DEK format");let a=Buffer.from(t,"base64"),s=Buffer.from(r,"base64"),u=Buffer.from(i,"base64"),c=Buffer.from(o,"base64"),d=await lr(n,a,$e),l=cr(ln,d,s,{authTagLength:dn});return l.setAuthTag(u),Buffer.concat([l.update(c),l.final()]).toString("utf8")}function Gn(e,n){let t=Buffer.from(n,"base64"),r=cn(dr),i=ur(ln,t,r,{authTagLength:dn}),o=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[r.toString("base64"),a.toString("base64"),o.toString("base64")].join(":")}function Le(e,n){let[t,r,i]=e.split(":");if(!t||!r||!i)throw new Error("Invalid encrypted data format");let o=Buffer.from(n,"base64"),a=Buffer.from(t,"base64"),s=Buffer.from(r,"base64"),u=Buffer.from(i,"base64"),c=cr(ln,o,a,{authTagLength:dn});return c.setAuthTag(s),Buffer.concat([c.update(u),c.final()]).toString("utf8")}function ue(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=Gn(i,n);return t}function te(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=Le(i,n);return t}function We(e,n,t){let r=te(e,n);return ue(r,t)}function pr(e,n,t){let r={};for(let i of t)r[`get_${i}`]=async()=>(await e())[i]??null,r[`set_${i}`]=async o=>{let a=[null,void 0,""].includes(o)?null:o;await n({[i]:a})};return r}var Jn=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function I(e){let{authType:n,integrationName:t,kek:r,database:i,extraIntegrationFields:o=[]}=e,a=[...E[n].integration,...o],s=null,u={kek:r,integrationName:t,getIntegration:async()=>{if(s)return s;let g=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!g)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return s={id:g.id,config:Jn(g.config),dek:g.dek??null},s},updateIntegration:async g=>{let y=await u.getIntegration();await i.db.updateTable("corsair_integrations").set({...g.config!==void 0?{config:g.config}:{},...g.dek!==void 0?{dek:g.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),s=null}},c=null,d=async()=>{if(c)return c;let g=await u.getIntegration();if(!g.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return c=await L(g.dek,r),c},l=async()=>{let g=await u.getIntegration(),y=await d(),h=g.config;return!h||Object.keys(h).length===0?{}:te(h,y)};return{get_dek:d,issue_new_dek:async()=>{let g=await u.getIntegration(),y=ee(),h={};if(g.dek){let C=await L(g.dek,r),b=g.config;b&&Object.keys(b).length>0&&(h=We(b,C,y))}let m=await ne(y,r);return await u.updateIntegration({config:h,dek:m}),c=y,y},...pr(l,async g=>{let y=await d(),h;try{h=await l()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,b),h={}}let m={...h};for(let[b,k]of Object.entries(g))k===null?delete m[b]:m[b]=k;let C=ue(m,y);await u.updateIntegration({config:C})},a)}}function x(e){let{authType:n,integrationName:t,tenantId:r,kek:i,database:o,extraAccountFields:a=[]}=e,s=[...E[n].account,...a],u=null,c=null,d=async()=>{if(c)return c;let k=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!k)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return c={id:k.id,config:Jn(k.config),dek:k.dek??null},c},l={kek:i,integrationName:t,tenantId:r,getIntegration:d,getAccount:async()=>{if(u)return u;let k=await d(),w=await o.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",k.id).executeTakeFirst();if(!w)throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`);return u={id:w.id,config:Jn(w.config),dek:w.dek??null},u},updateAccount:async k=>{let w=await l.getAccount();await o.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","=",w.id).execute(),u=null}},p=null,f=null,g=async()=>{if(p)return p;let k=await l.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return p=await L(k.dek,i),p},y=async()=>{if(f)return f;let k=await l.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return f=await L(k.dek,i),f},h=async()=>{let k=await l.getAccount(),w=await g(),T=k.config;return!T||Object.keys(T).length===0?{}:te(T,w)},m=async()=>{let k=await l.getIntegration(),w=await y(),T=k.config;return!T||Object.keys(T).length===0?{}:te(T,w)},b={get_dek:g,issue_new_dek:async()=>{let k=await l.getAccount(),w=ee(),T={};if(k.dek){let O=await L(k.dek,i),M=k.config;M&&Object.keys(M).length>0&&(T=We(M,O,w))}let D=await ne(w,i);return await l.updateAccount({config:T,dek:D}),p=w,w},...pr(h,async k=>{let w=await g(),T;try{T=await h()}catch(M){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,M),T={}}let D={...T};for(let[M,A]of Object.entries(k))A===null?delete D[M]:D[M]=A;let O=ue(D,w);await l.updateAccount({config:O})},s)};return n==="oauth_2"&&(b.get_integration_credentials=async()=>{let k=await m();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),b}async function gr(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 i=ee(),o=await ne(i,t);return await e.db.updateTable("corsair_integrations").set({dek:o,updated_at:new Date}).where("id","=",r.id).execute(),i}async function fr(e,n,t,r){let i=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!i)throw new Error(`Integration "${n}" not found.`);let o=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",i.id).executeTakeFirst();if(!o)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let a=ee(),s=await ne(a,r);return await e.db.updateTable("corsair_accounts").set({dek:s,updated_at:new Date}).where("id","=",o.id).execute(),a}var Mo=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function xe(e){return Mo.has(e)}function Ho(e,n){return xe(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function Fo(e){return!xe(e)}async function yr(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 Bo(e,n){let r=e.authConfig?.[n]?.integration??[];return[...E[n].integration,...r]}function Uo(e,n){let r=e.authConfig?.[n]?.account??[];return[...E[n].account,...r]}function No(e,n,t){let r=t.filter(s=>s.required&&!s.configured).map(s=>s.name),i=t.filter(s=>s.level==="integration"&&s.required&&!s.configured).map(s=>s.name),o=t.filter(s=>s.level==="account"&&s.required&&s.configured),a;return i.length>0?a="missing_integration":r.length===0?a="ready":o.length>0?a="partial":a="not_started",{plugin:e,authType:n,status:a,connected:a==="ready",fields:t,missingRequiredFields:r}}async function pn(e,n,t){let r=H(n);if(!r||!e.database||!e.kek)return null;let i=t.trim()||"default",o=n.authConfig,a=o?.[r]?.integration??[],s=o?.[r]?.account??[],u=I({authType:r,integrationName:n.id,kek:e.kek,database:e.database,extraIntegrationFields:a}),c=x({authType:r,integrationName:n.id,tenantId:i,kek:e.kek,database:e.database,extraAccountFields:s}),d=Bo(n,r),l=Uo(n,r),p=[];for(let f of d)p.push({name:f,level:"integration",required:Ho(r,f),configured:await yr(u,f)});for(let f of l)p.push({name:f,level:"account",required:Fo(f),configured:await yr(c,f)});return No(n.id,r,p)}async function je(e,n,t={}){let r=n.trim()||"default",i=t.pluginIds?.length?new Set(t.pluginIds):null,o=[];for(let a of e.plugins){if(i&&!i.has(a.id))continue;let s=await pn(e,a,r);s&&o.push(s)}return o}function gn(e){return e.status==="ready"?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}import*as Ke from"crypto";function z(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function zn(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 i=r;return n!==void 0&&typeof i.iat=="number"&&Date.now()-i.iat>n?null:i}return null}catch{return null}}function ce(e,n){let t=Ke.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var Vn=600*1e3;function fn(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),i=e.slice(t+1),o=Ke.createHmac("sha256",n).update(r).digest("base64url"),a=Buffer.from(i,"base64url"),s=Buffer.from(o,"base64url");return a.length!==s.length||!Ke.timingSafeEqual(a,s)?null:zn(r,{maxAgeMs:Vn})}var $o=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Ze(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:$o.has(n)}catch{return!1}}function Se(e){return Ze(e)?"client":"server"}function hr(e,n){return e==="client"||Ze(n)}function Re(e){if(!e.source)return null;let n=Ze(e.deliveryUrl);return e.source==="server"&&n?{error:'source "server" cannot be used with a loopback delivery URL \u2014 omit source to auto-detect or use "client"',status:400}:e.oauthMode==="managed"&&e.source==="client"&&!n?{error:'managed OAuth with source "client" requires a loopback delivery URL \u2014 omit source for production server delivery',status:400}:null}import{ZodBoolean as Wo,ZodDate as jo,ZodEnum as Ko,ZodNullable as Zo,ZodNumber as qo,ZodObject as Go,ZodOptional as Jo,ZodRecord as zo,ZodString as Vo,ZodType as Yo}from"zod";var Lo={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:{}}},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:{}}}},Yn=Lo;async function kr(e,n){let t=[],r=p=>{t.push(p),console.log(p)},i=p=>{t.push(p),console.warn(p)},o=n?.caller??"script",a=nr(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 s=Xo(e,a.plugins,n),u={...a,database:a.database},c=u.database.db;await ti(c,i);let d=await ri(c,u,s.tenantId,s.provisionAccounts,r);n?.credentials&&Object.keys(n.credentials).length>0&&await si(e,s,n.credentials,u,r,i);let l=await ui(d,s,r,o);if(n?.backfill){r("[corsair:setup] Starting backfill...");let p=Cr({plugins:a.plugins,database:c,kek:a.kek,multiTenancy:!0}).withTenant(s.tenantId);await ci(p,a.plugins,l,r,i),r("[corsair:setup] Backfill complete.")}return t.join(`
2
+ `)}function Qn(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...E[n][t],...r])}function Qo(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let i=n.find(s=>s.id===t);if(!i)continue;let o=H(i);if(!o)continue;let a=Qn(i,o,"account");for(let s of Object.keys(r))if(a.has(s))return!0}return!1}function Xo(e,n,t){let r=tr(e),i=t?.tenantId?.trim(),o=i!==void 0&&i.length>0;if(r&&t?.backfill&&!o)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(r&&Qo(t?.credentials,n)&&!o)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(o&&!i)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:r,tenantIdProvided:o,tenantId:o?i:"default",provisionAccounts:!r||o}}function br(e,n){return se(e)?n===0?!0:Object.values(e).every(t=>br(t,n-1)):!1}function ei(e){return br(e,4)}var ni={...or};function yn(e){if(e instanceof Go){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Yo?yn(r):"unknown";return n}return e instanceof Zo?`${yn(e.unwrap())} | null`:e instanceof Jo?`${yn(e.unwrap())} | undefined`:e instanceof Ko?e.options.join(" | "):e instanceof Vo?"string":e instanceof qo?"number":e instanceof Wo?"boolean":e instanceof jo?"date":e instanceof zo?"jsonb":"unknown"}async function ti(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(i=>i.name));for(let[i,o]of Object.entries(ni))r.has(i)||n(`[corsair:setup] Table "${i}" does not exist. Run your database migrations before calling setupCorsair.
3
+ Schema: ${JSON.stringify(yn(o),null,2)}`)}async function ri(e,n,t,r,i){let o=new Date,a=new Map;for(let s of n.plugins){let u=s.id,c=H(s),d=await e.selectFrom("corsair_integrations").selectAll().where("name","=",u).executeTakeFirst();if(!d){let y=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:y,name:u,config:{},created_at:o,updated_at:o}).execute(),d=await e.selectFrom("corsair_integrations").selectAll().where("id","=",y).executeTakeFirst(),i(`[corsair:setup] Created integration: ${u}`)}let l=c?s.authConfig?.[c]?.integration??[]:[],p=c?s.authConfig?.[c]?.account??[]:[],f=c&&d?I({authType:c,integrationName:u,kek:n.kek,database:n.database,extraIntegrationFields:l}):void 0;if(d&&!d.dek&&f&&(await f.issue_new_dek(),i(`[corsair:setup] Issued integration DEK: ${u}`)),!d||!c||!f)continue;let g;if(r){let y=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",d.id).executeTakeFirst();if(!y){let h=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:h,tenant_id:t,integration_id:d.id,config:{},created_at:o,updated_at:o}).execute(),y=await e.selectFrom("corsair_accounts").selectAll().where("id","=",h).executeTakeFirst(),i(`[corsair:setup] Created account: ${u}`)}g=y&&x({authType:c,integrationName:u,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:p}),y&&g&&!y.dek&&(await g.issue_new_dek(),i(`[corsair:setup] Issued account DEK: ${u}`))}a.set(u,{pluginId:u,authType:c,integration:f,account:g,integrationFields:[...E[c].integration,...l],accountFields:r?[...E[c].account,...p]:[]})}return a}function oi(e){if(!se(e))return;let n=e.keys;return se(n)?n:void 0}function ii(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function si(e,n,t,r,i,o){let a=oi(e),s=n.provisionAccounts?ii(e,n.tenantId):void 0;for(let[u,c]of Object.entries(t)){let d=r.plugins.find(m=>m.id===u);if(!d){o(`[corsair:setup] Unknown plugin '${u}' \u2014 skipping credentials.`);continue}let l=H(d);if(!l){o(`[corsair:setup] Plugin '${u}' has no auth type \u2014 skipping credentials.`);continue}let p=Qn(d,l,"integration"),f=Qn(d,l,"account"),g=a?.[u],y=s?.[u],h=se(y)?y.keys:void 0;for(let[m,C]of Object.entries(c))if(C){if(p.has(m)){if(n.multiTenant&&n.tenantIdProvided)throw new Error(`[corsair:setup] '${u}.${m}' 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 b=J(g,`set_${m}`);if(!b){o(`[corsair:setup] Cannot set integration field '${m}' for '${u}'.`);continue}await b(C),i(`[corsair:setup] Set ${u} integration.${m}`);continue}if(f.has(m)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${u}.${m}' on a multi-tenant instance`);let b=J(h,`set_${m}`);if(!b){o(`[corsair:setup] Cannot set account field '${m}' for '${u}'.`);continue}await b(C),i(`[corsair:setup] Set ${u} account.${m} (tenant=${n.tenantId})`);continue}o(`[corsair:setup] Unknown credential field '${m}' for plugin '${u}'.`)}}}var mr=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function ai(e,n,t,r,i,o,a,s,u){let c=[],d=[];for(let p of i){if(mr.has(p))continue;let f=J(t,`get_${p}`);if(!f)continue;let g=null;try{let y=await f();g=typeof y=="string"?y:null}catch{}g||c.push(p)}if(r&&o.length>0)for(let p of o){if(mr.has(p))continue;let f=J(r,`get_${p}`);if(!f)continue;let g=null;try{let y=await f();g=typeof y=="string"?y:null}catch{}g||d.push(p)}let l=c.length===0&&d.length===0;if(l)s(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else{let p=[...c,...d];if(u==="cli"){let f=p.map(g=>`${g}=VALUE`).join(" ");s(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
+ corsair setup --${e} ${f}`)}else{let f=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let g of c)f.push(` await corsair.keys.${e}.set_${g}(value)`);for(let g of d){let y=a.provisionAccounts?a.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(a.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;f.push(` await ${y}.keys.set_${g}(value)`)}s(f.join(`
5
+ `))}}return l}async function ui(e,n,t,r){let i=new Set;for(let o of e.values())await ai(o.pluginId,o.authType,o.integration,o.account,o.integrationFields,o.accountFields,n,t,r)&&i.add(o.pluginId);return i}async function ci(e,n,t,r,i){if(!ei(Yn)){i("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let o=Yn,a=new Set(n.map(s=>s.id));for(let[s,u]of Object.entries(o)){if(!a.has(s))continue;if(!t.has(s)){r(`[corsair:setup] Skipping backfill for '${s}' \u2014 auth not configured.`);continue}let c=se(e)?e[s]:void 0,d=se(c)?c.api:void 0;if(d)for(let[l,p]of Object.entries(u))for(let[f,g]of Object.entries(p)){r(`[corsair:setup] Backfilling ${s} \u203A ${l}.${f}...`);try{let y=se(d)?d[l]:void 0;await J(y,f)?.(g)}catch(y){i(`[corsair:setup] ${s} \u203A ${l}.${f} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Ie(e,n){if(!P(e).database)throw new Error("A database must be configured to provision Corsair for connect");await kr(e,{tenantId:n})}var li=new Set(["access_token","refresh_token","expires_at","scope"]);function di(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function pi(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!xe(t)&&!li.has(t)):n.filter(t=>!xe(t))}async function wr(e,n,t={}){let r=P(e),i=B(e),o=rn(i),a=[],s=t.pluginIds?new Set(t.pluginIds):null;for(let u of r.plugins){if(s&&!s.has(u.id))continue;let c=H(u);if(!c)continue;let d=di(c),l=t.providerNameOverrides?.[u.id]??ae(u.id),p=await pn(r,u,n),f=en(u,c),g=pi(c,f),y={plugin:u.id,providerName:l,authKind:d,alreadyConfigured:p?.connected??!1};if(g.length>0&&(y.credentialFields=g),d==="oauth"){let m=t.oauthModeOverrides?.[u.id]??(c==="managed"?"managed":"byo");if(y.oauthMode=m,!t.skipOAuthUrlGeneration)if(m==="managed")y.state=ce(z(u.id,n),r.kek);else try{let C=await Xn(e,u.id,{tenantId:n,redirectUri:o});y.oauthUrl=C.url,y.state=C.state}catch(C){y.setupError=C instanceof Error?C.message:`Could not prepare OAuth for ${u.id}`}}a.push(y)}return a}function Tr(e,n){let t=B(e);if(n){let r=Re({source:n,deliveryUrl:t.deliveryUrl});if(r)throw new Error(r.error);return n}return Se(t.deliveryUrl)}async function Pr(e,n){await Ie(e,n)}async function hn(e,n){let t=B(e);await Pr(e,n.tenantId);let r=n.plugin?[n.plugin]:void 0,i=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,o=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,a=await wr(e,n.tenantId,{pluginIds:r,oauthModeOverrides:i,providerNameOverrides:o});if(a.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");let s=Tr(e,n.source);return Ae({hub:t,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{tenantId:n.tenantId,deliveryUrl:t.deliveryUrl,source:s,plugins:a},parseResponse:on})}function vr(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function gi(e,n){return n&&!n.has(e.id)?!1:H(e)!==null}async function _e(e,n,t={}){let r=P(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,a=await je(r,i,{pluginIds:t.pluginIds}),s=new Map(a.map(c=>[c.plugin,c])),u=r.plugins.filter(c=>gi(c,o)).map(c=>{let d=H(c),l=s.get(c.id);return l?{plugin:c.id,providerName:ae(c.id),authKind:vr(d),status:l.status,connected:l.connected,fields:l.fields.map(p=>({name:p.name,level:p.level,required:p.required,configured:p.configured})),missingRequiredFields:l.missingRequiredFields}:{plugin:c.id,providerName:ae(c.id),authKind:vr(d),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:i,plugins:u}}var le=6e4,me=3e5;var V=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function mn(e,n){let t=P(e,()=>new V("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new V("no_database","Database not configured");let r=$(t,n.plugin,d=>new V("plugin_not_found",d)),i=H(r);if(!i)throw new V("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new V("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Ie(e,n.tenantId);let o=new Set(en(r,i)),s=r.authConfig?.[i]?.account??[],u=x({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:s}),c=0;for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!o.has(d))throw new V("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let p=J(u,`set_${d}`);if(!p)throw new V("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await p(l.trim()),c+=1}if(c===0)throw new V("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var kn=new Map;function fi(e){for(let[n,t]of kn)t<=e&&kn.delete(n)}function bn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return fi(r),kn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(kn.set(t,r+n),{ok:!0})}async function Cn(e,n,t){for(let r of e){if(r.id!==n)continue;let i=r.oauthWebhookTenantLinkResolver;return i?i(t):null}return null}var Ar=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function yi(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 hi(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 L(n.dek,e.kek),r=Ar(n.config),i={};Object.keys(r).length>0&&(i=te(r,t)),i[e.link.linkType]=e.link.externalId;let o=ue(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function Ee(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:a,extraAccountFields:s=[]}=e,{accountId:u}=await yi({database:n,pluginId:r,tenantId:i}),c=!1;if(a){let d=x({authType:a,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:s}),l=`set_${o.linkType}`,p=d[l];typeof p=="function"&&(await p(o.externalId),c=!0)}c||await hi({database:n,kek:t,accountId:u,link:o})}async function et(e){let{database:n,kek:t,pluginId:r,linkType:i,externalId:o}=e,a=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 s of a)if(s.dek)try{let u=await L(s.dek,t),d=Ar(s.config)[i];if(!d)continue;if(Le(d,u)===o)return s}catch{continue}return null}async function wn(e){return(await et(e))?.tenant_id??null}async function xr(e){return wn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var de=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function De(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:a,scope:s}=n;if(!i.trim())throw new de("no_access_token","Managed OAuth delivery missing access_token");let u=P(e,()=>new de("invalid_corsair_instance","Invalid corsair instance"));if(!u.database)throw new de("no_database","No database configured on corsair instance");let c=$(u,t,l=>new de("plugin_not_found",l));await Ie(e,r);let d=x({authType:"managed",integrationName:t,tenantId:r,kek:u.kek,database:u.database});await d.set_access_token(i),o&&await d.set_refresh_token(o),a&&await d.set_expires_at(String(Math.floor(Date.now()/1e3)+a)),s&&await d.set_scope(s);try{let l=await Cn(u.plugins,t,{access_token:i,refresh_token:o,scope:s});if(l)try{let p=c.authConfig?.managed?.account??[];await Ee({database:u.database,kek:u.kek,pluginId:t,tenantId:r,link:l,authType:"managed",extraAccountFields:p})}catch(p){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,p)}}catch(l){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,l)}return{plugin:t,tenantId:r}}import{createHmac as nt,randomUUID as mi,timingSafeEqual as Sr}from"crypto";function Rr(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Tn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=nt("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":mi()}}}function tt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Rr(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>3e5)return!1;let o=nt("sha256",n).update(e.body).digest("hex");try{return Sr(Buffer.from(o,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function Oe(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Rr(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)>3e5)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let o=nt("sha256",n).update(e.body).digest("hex");try{if(!Sr(Buffer.from(o,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function rt(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function ot(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function it(e){return e.status===0?`Could not reach delivery URL (${e.deliveryUrl}): ${e.ack.error??e.body}`:e.ack.error??e.body??`HTTP ${e.status}`}async function st(e){let{body:n,headers:t}=Tn(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),i=await r.text();return{ok:r.ok,status:r.status,body:i}}catch(r){return{ok:!1,status:0,body:r instanceof Error?r.message:"Delivery request failed"}}}function ki(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Ir(e,n,t=[]){for(let[r,i]of Object.entries(e))if(ki(i)){if(i.match(n))return{webhook:i,path:[...t,r]}}else if(i&&typeof i=="object"){let o=Ir(i,n,[...t,r]);if(o)return o}return null}function bi(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Ci(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 _r(e,n,t,r){let i=bi(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=Ci(i)||o);let s={headers:i,body:o,...r?{query:r}:{}},u=r?.tenantId||"default",c=e.withTenant?e.withTenant(u):e,d=nn;for(let l of d){let p=c[l];if(!p||!p.webhooks||p.pluginWebhookMatcher&&!p.pluginWebhookMatcher(s))continue;let f=Ir(p.webhooks,s);if(!f)continue;let g=f.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let h=await f.webhook.handler(y),m=!!Object.keys(h.returnToSender||{})?.length;return{plugin:l,action:g,body:o,response:m?{...h?.returnToSender,success:!0}:{success:!0},...h.responseHeaders&&{responseHeaders:h.responseHeaders}}}catch(h){return console.error(`Error executing webhook handler for ${l}.${g}:`,h),{plugin:l,action:g,body:o,response:{success:!1,error:h instanceof Error?h.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{randomBytes as vi}from"crypto";import{createHmac as wi,randomBytes as Ti,timingSafeEqual as Pi}from"crypto";function re(){return Ti(16).toString("base64url")}function qe(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return wi("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[i,o]=r;if(!i||!o)return null;let a=qe(i,t);try{if(!Pi(Buffer.from(o,"utf8"),Buffer.from(a,"utf8")))return null}catch{return null}let s;try{s=JSON.parse(Buffer.from(i,"base64url").toString("utf8"))}catch{return null}return s.exp*1e3<Date.now()?null:s}function Pn(e,n,t){let r=Math.floor(Date.now()/1e3),i={...e,iat:r,exp:t},o=Buffer.from(JSON.stringify(i)).toString("base64url"),a=qe(o,n);return`${o}.${a}`}function Ge(e,n,t){let r=Math.floor(Date.now()/1e3);return Pn(e,n,r+Math.floor(t/1e3))}function ke(e){return decodeURIComponent(e)}function at(e){return encodeURIComponent(e)}function Er(e){let n=e.trim();return n.length>0?n:null}function vn(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function An(e,n){if(!Er(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??vi(16).toString("base64url"),iat:t,exp:t+Math.floor(6e4/1e3)},i=Buffer.from(JSON.stringify(r)).toString("base64url"),o=qe(i,n);return`${i}.${o}`}function pe(e,n){return Er(n)?Y(e,n):null}function be(e){return e.deliveryMode==="connect.status"}function Ce(e){return e.deliveryMode==="auth.credentials"}function Je(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function ze(e){return e.deliveryMode==="oauth.tokens"}function xn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!be(e)&&!Ce(e)&&!Je(e)&&!ze(e)}function ut(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 Ai(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 wn({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function xi(e,n,t){let r=await Ai(e,n,t),i={...t.query??{},...r?{tenantId:r}:{}},o=await _r(e,t.headers,t.body,i);if(!o.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(o.response&&o.response.success===!1)return{status:"failed",retryable:!1,error:typeof o.response.error=="string"?o.response.error:"Webhook handler failed"};let a=o.response?.returnToSender,s=a&&typeof a=="object"&&typeof a.validationToken=="string"&&Object.keys(a).length===1?a.validationToken:a||(o.response?.data??o.response);return{status:"ok",webhookResponse:{status:o.response?.statusCode??200,body:s,headers:o.responseHeaders}}}async function Si(e,n){return await Ve(e,n),{status:"ok"}}async function Ri(e,n){return await De(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function lt(e,n,t){let r=await ct(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function ct(e,n,t){let r=P(e),i=n.token?.trim();if(!i)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let o=new Date().toISOString(),a=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",i).executeTakeFirst();return a?a.status!=="pending"?{status:"ok"}:a.expires_at<o?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",a.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","=",a.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Ii(e,n){try{return await mn(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function _i(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await _e(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function dt(e,n,t={}){let r=P(e),i=ut(n.headers,"x-corsair-signature"),o=ut(n.headers,"x-corsair-timestamp"),a=ut(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let u=Oe({body:n.body,signatureHeader:i,timestampHeader:o,signingSecret:t.signingSecret});if(!u.ok)return{status:"failed",retryable:!1,error:u.error};if(!a?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let c=bn(`nonce:${a.trim()}`,3e5);if(!c.ok)return{status:"failed",retryable:!1,error:c.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(s.type){case"webhook":return xi(e,r,s.payload);case"oauth.callback":return Si(e,s.payload);case"oauth.tokens":return Ri(e,s.payload);case"permission.approve":return ct(e,s.payload,"approved");case"permission.deny":return ct(e,s.payload,"denied");case"auth.credentials":return Ii(e,s.payload);case"connect.status":return _i(e,s.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${s.type}`}}}var Ei="corsair:client-bridge";function Dr(e){let n=JSON.stringify({type:Ei,requestId:e.requestId,ok:e.ok,body:e.body??null,error:e.error??null}),t=JSON.stringify(e.hubOrigin);return`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><script>
6
+ (function () {
7
+ var message = ${n};
8
+ var targetOrigin = ${t};
9
+ if (window.parent && window.parent !== window) {
10
+ window.parent.postMessage(message, targetOrigin);
11
+ }
12
+ })();
13
+ </script></body></html>`}var Di=[".corsair.dev"];function Oi(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function Mi(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Oi(n)?!0:Di.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Or(e){return!e||!Mi(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 Mr(e,n){if(!n)return e;let t=new Headers(e.headers);for(let[r,i]of Object.entries(n))t.set(r,i);return new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function Sn(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 pt(e,n){let t=B(e),i=new URL(n).searchParams.get("d");if(!i)return{type:"json",status:200,body:{status:"ok",message:"Corsair tunnel endpoint is active",timestamp:new Date().toISOString()}};let o=pe(i,t.signingSecret);if(!o)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let a=bn(`browser:${o.jti}`,6e4);if(!a.ok)return{type:"json",status:400,body:{error:a.error}};try{if(be(o)){if(!o.hubSuccessUrl)return{type:"json",status:400,body:{error:"Connect status delivery missing hubSuccessUrl"}};let s=o.tenantId?.trim()||"default",u=await _e(e,s,{pluginIds:o.statusPlugins});return{type:"redirect",url:Sn(o.hubSuccessUrl,{status:u})}}if(Ce(o))return o.hubSuccessUrl?o.credentials?(await mn(e,{plugin:o.plugin,tenantId:o.tenantId,credentials:o.credentials}),{type:"redirect",url:Sn(o.hubSuccessUrl,{connectedPlugin:o.plugin})}):{type:"redirect",url:Sn(o.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(Je(o)){if(!o.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await lt(e,o.permissionToken,o.deliveryMode==="permission.approve"?"approved":"denied")}else if(ze(o)){if(!o.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await De(e,{plugin:o.plugin,tenantId:o.tenantId,accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.expiresIn,scope:o.scope})}else{if(!xn(o)||!o.code||!o.state||!o.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await Ve(e,{code:o.code,state:o.state,redirectUri:o.redirectUri})}}catch(s){let u=s instanceof Error?s.message:"Hub delivery failed";return(be(o)||Ce(o))&&o.hubSuccessUrl?{type:"redirect",url:Sn(o.hubSuccessUrl,{error:u})}:(be(o)||Ce(o))&&o.hubOrigin&&o.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Dr({hubOrigin:o.hubOrigin,requestId:o.requestId,ok:!1,error:u})}:{type:"json",status:400,body:{error:u}}}return{type:"redirect",url:o.hubSuccessUrl}}async function gt(e,n){let t=B(e),r=await dt(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 i=r.webhookResponse;if(!i)return{type:"json",status:200,body:{status:"ok"}};let o=i.status??200,a=i.headers;return i.body&&typeof i.body=="object"&&!(i.body instanceof ArrayBuffer)?{type:"json",status:o,body:i.body,headers:a}:{type:"text",status:o,body:typeof i.body=="string"?i.body:i.body?JSON.stringify(i.body):null,headers:a}}function ft(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 yt(e,n){return n.method==="GET"?pt(e,n.url):gt(e,{headers:n.headers,body:n.body??""})}async function ht(e,n){try{let t=await yt(e,n);return ft(t)}catch(t){if(t instanceof he)return Response.json({error:t.message},{status:503});throw t}}async function Ye(e,n){let t=n.method.toUpperCase(),r=Or(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 i=await ht(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return Mr(i,r)}var oe=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 Hi=300;async function mt(e,n){let{keys:t,hub:r,plugin:i,tenantId:o}=e,a=n?.forceRefresh??!1,[s,u,c]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!s&&!c)throw new oe(i,"managed");let d=Math.floor(Date.now()/1e3);if(!a&&s&&u&&Number(u)>d+Hi)return{accessToken:s,expiresAt:Number(u),refreshed:!1};if(!c&&s&&!a)return{accessToken:s,expiresAt:u?Number(u):d+3600,refreshed:!1};let l=await Ae({hub:r,path:"/oauth/refresh",body:{plugin:i,tenantId:o},parseResponse:an}),p=l.expires_in?d+l.expires_in:u?Number(u):d+3600;return await t.set_access_token(l.access_token),await t.set_expires_at(String(p)),l.refresh_token&&await t.set_refresh_token(l.refresh_token),l.scope&&await t.set_scope(l.scope),{accessToken:l.access_token,expiresAt:p,refreshed:!0}}async function Hr(e,n){e._refreshAuth=async()=>(await mt(n,{forceRefresh:!0})).accessToken}async function Rn(e,n){return Ae({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:{permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,deliveryUrl:e.deliveryUrl,expiresAt:n.expiresAt},parseResponse:sn})}function In(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}function Fr(e){return{delivery:n=>Ye(e,n),deliveryOptions:n=>Ye(e,n)}}var Br=1200*1e3;function kt(){return re()}function bt(){return Br}function Ct(e,n){return Ge(e,n,Br)}function wt(e,n){return Y(e,n)}function Tt(e){return ke(e)}var Ur=600*1e3;function Pt(){return re()}function vt(){return Ur}function At(e,n){return Ge(e,n,Ur)}function xt(e,n){return Y(e,n)}function St(e){return at(e)}function Rt(e){return ke(e)}function It(){return re()}function _t(e,n,t){return Pn(e,n,Math.floor(t.getTime()/1e3))}function Et(e,n){return Y(e,n)}function Dt(e){return ke(e)}function _n(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(i,o){let a=t.length>1;throw new Error(`corsair.keys.${String(o)}: Cannot access keys because ${t.join(" and ")} ${a?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
14
+
15
+ To generate a KEK, run: openssl rand -base64 ${$e}`)}})}function Me(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}var Fi=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Nr(e,n,t,r,i){let o={pluginId:n,operation:t,input:r,originalError:e},a=Object.keys(i).find(c=>i[c]?.match(e,o));return await(i[a||"DEFAULT"]?.handler||Fi)(e,o)}import{randomBytes as Ui}from"crypto";import{v4 as Ni}from"uuid";var Ot="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 Ht(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function $r(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Mt(e){return In(e)}async function Ft(e,n){if(Ht(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?$r(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await Rn(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:Bi(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function Bi(e){try{return JSON.parse(e)}catch{return e}}async function En(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await Ft(e,n);return{...n,approvalUrl:r}}async function Bt(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:i,permissionToken:o,plugin:a,endpoint:s,args:u,tenantId:c,expiresAt:d,operationPath:l}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:o,id:i,plugin:a,endpoint:s,args:u});let f=await Ft({manual:t,hub:r},{id:i,token:o,plugin:a,endpoint:s,args:JSON.stringify(u),tenant_id:c,expires_at:d});return Ht(t)?f?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:f}):Mt(f):Ot:r?f?Mt(f):`Action '${l}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Ot}var $i={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 Li(e,n,t){return t!==void 0?t:$i[n][e]}function Ut(e){let n=/(\d+)(d|h|m|s)/g,t=0,r;for(;(r=n.exec(e))!==null;){let i=parseInt(r[1],10);switch(r[2]){case"d":t+=i*864e5;break;case"h":t+=i*36e5;break;case"m":t+=i*6e4;break;case"s":t+=i*1e3;break}}return t>0?t:600*1e3}function Wr(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 Lr(e,n,t){let r=Date.now()+t;for(;Date.now()<r;){let i=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!i)return{result:"blocked",reason:"pending"};if(i.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(i.status==="denied")return{result:"blocked",reason:"denied"};if(i.status==="expired"||i.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(o=>setTimeout(o,500))}return{result:"blocked",reason:"timeout"}}async function jr(e){let n=Li(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}'.`,`
16
+ Action: ${r}`,`
17
+ To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let i=JSON.stringify(e.args),o=new Date().toISOString(),a=e.tenantId??"default",s=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",i).where("tenant_id","=",a).where("expires_at",">",o).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(s){if(s.status==="approved"){let g=e.db,y=s.id;return{result:"allow",onComplete:async()=>{await g.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",y).execute()}}}return s.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
18
+ Action: ${r}`,`
19
+ Permission ID: ${s.id}`,`
20
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Lr(e.db,s.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:s.id,token:s.token,expiresAt:s.expires_at})}let u=Ni(),c=Ui(32).toString("hex"),d=e.timeoutMs??600*1e3,l=new Date(Date.now()+d).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:u,created_at:new Date,updated_at:new Date,token:c,plugin:e.pluginId,endpoint:e.endpointPath,args:i,tenant_id:a,status:"pending",expires_at:l}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
21
+ Action: ${r}`,`
22
+ Permission ID: ${u}`,`
23
+ Permission token: ${c}`,`
24
+ Expires at: ${l}`,`
25
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Lr(e.db,u,d):{result:"blocked",reason:"pending",id:u,token:c,expiresAt:l}}function Wi(e){return typeof e=="function"}function ji(e,n,t){let r=ce(z(e,n.tenantId??t??"default"),n.kek),i=new URL(n.baseUrl);i.searchParams.set("state",r);let o=i.toString(),a=n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:o,state:r}):`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${o}`;return new Error(a)}function Nt({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:i,errorHandlers:o,currentPath:a=[],keyBuilder:s,permissionsConfig:u,endpointMeta:c,database:d,permissionsOptions:l,tenantId:p,manualConfig:f,hubConfig:g}){for(let[y,h]of Object.entries(e)){let m=n?.[y];if(Wi(h)){let C=m,b=[...a,y].join("."),k=async(w={})=>{let T;if(u){let _=c?.[b],{result:ve,reason:q,onComplete:Ue,token:X,id:ye,expiresAt:N}=await jr({pluginId:i,endpointPath:b,args:w,mode:u.mode,override:u.overrides?.[b],riskLevel:_?.riskLevel??"write",meta:_,db:d,timeoutMs:l?Ut(l.timeout):void 0,tenantId:p,approvalMode:l?.mode});if(ve==="blocked"){let G;throw q==="denied"?G=`Action '${b}' was denied by the user. Await further instructions before proceeding.`:q==="policy"?G=`Action '${b}' is blocked by the permission policy. Update the corsair config to allow it.`:q==="timeout"?G=`Action '${b}' timed out waiting for approval.`:X&&ye?G=await Bt({permissionsOptions:l,manual:f,hub:g,permissionId:ye,permissionToken:X,plugin:i,endpoint:b,args:w,tenantId:p??"default",expiresAt:N??new Date(Date.now()+(l?Ut(l.timeout):600*1e3)).toISOString(),operationPath:b}):G=`Action '${b}' requires user approval before it can run.`,new Error(G)}T=Ue}let D=async(_,ve,q)=>{try{return await h(ve,q)}catch(Ue){if(Ue instanceof Error){let X=await Nr(Ue,i,b,typeof q=="object"&&q!==null?q:{args:q},o);if(_<(X.maxRetries||0)){let ye=_+1;console.log(`Retrying (${ye} / ${X.maxRetries})...`);let N;if(X.headersRetryAfterMs)N=X.headersRetryAfterMs;else switch(X.retryStrategy){case"exponential_backoff":N=Math.pow(2,ye-1)*1e3;break;case"exponential_backoff_jitter":let G=Math.pow(2,ye-1)*1e3,Po=(Math.random()-.5)*1e3;N=Math.max(0,G+Po);break;case"linear_1s":N=1e3;break;case"linear_2s":N=2e3;break;case"linear_3s":N=3e3;break;case"linear_4s":N=4e3;break;default:N=1e3;break}await new Promise(G=>setTimeout(G,N)),await D(ye,ve,q),console.log(`[corsair:${i}:${b}] Retry strategy:`,X)}}throw Ue}},O;try{O=s?await s(t,"endpoint"):void 0}catch(_){throw f&&Me(f)&&f.oauthConfig&&f.kek&&_ instanceof oe&&_.authType==="oauth_2"?ji(i,f,p):_}if(!C?.before&&!C?.after){let _=await D(0,{...t,key:O},w);return await T?.(),_}let M={...t,key:O},A=C.before?await C.before(M,w):{ctx:M,args:w,continue:!0,passToAfter:void 0};if(A.continue===!1)return;let Pe=await D(0,A.ctx,A.args);return await C.after?.(A.ctx,Pe,A.passToAfter),await T?.(),Pe};r[y]=k}else if(h&&typeof h=="object"){let C={};Nt({endpoints:h,hooks:m,ctx:t,tree:C,pluginId:i,errorHandlers:o,currentPath:[...a,y],keyBuilder:s,permissionsConfig:u,endpointMeta:c,database:d,permissionsOptions:l,tenantId:p,manualConfig:f,hubConfig:g}),r[y]=C}}}function Ki(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function $t({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:i}){for(let[o,a]of Object.entries(e)){let s=n?.[o];if(Ki(a)){let u=s,c=async d=>{let l=(f,g)=>a.handler(f,g),p=i?await i(t,"webhook"):void 0;return!u?.before&&!u?.after?l({...t,key:p},d):(async()=>{let f={...t,key:p},g=u.before?await u.before(f,d):{ctx:f,args:d,continue:!0,passToAfter:void 0};if(g.continue===!1)return;let y=await l(g.ctx,g.args);return y?.success===!0&&await u.after?.(g.ctx,y,g.passToAfter),y})()};r[o]={match:a.match,handler:c}}else if(a&&typeof a=="object"){let u={};$t({webhooks:a,hooks:s,ctx:t,webhooksTree:u,keyBuilder:i}),r[o]=u}}}function Zi(e,n,t){let r=null;return async()=>{if(r)return r;if(!e)throw new Error("Database not configured");let i=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!i)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);let o=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",i.id).executeTakeFirst();if(!o)throw new Error(`Account not found for tenant "${t}" and integration "${n}". Make sure to create the account first.`);return r=o.id,r}}function qi(e,n,t,r,i){return e?qn(e.db,n,t,r,i):{findByEntityId: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 Lt(e,n){let{database:t,tenantId:r,kek:i,rootErrorHandlers:o,permissionsOptions:a,manualConfig:s,hubConfig:u}=n,c={},d={};for(let l of e)c[l.id]={},d[l.id]={};for(let l of e){let p=l.schema,f=r??"default",g=Zi(t,l.id,f);if(p?.entities){let A={};for(let[Pe,_]of Object.entries(p.entities)){let ve=t?qn(t.db,g,Pe,p.version,_):qi(void 0,g,Pe,p.version,_);A[Pe]=ve}d[l.id].db=A,c[l.id].db=A}let y=l.options,h=l.authConfig,m;if(t&&i&&y?.authType){let A=h?.[y.authType]?.account??[];m=x({authType:y.authType,integrationName:l.id,tenantId:f,kek:i,database:t,extraAccountFields:A}),c[l.id].keys=m}let C={database:t,db:d[l.id]?.db??{},$getAccountId:g,...l.options?{options:l.options}:{},...m?{keys:m,authType:y?.authType}:{},tenantId:f,...u?{hub:u}:{}},b=l.endpoints??{},k=l.hooks,w={...o,...l.errorHandlers},T={},D=l.options?.permissions;Nt({endpoints:b,hooks:k,ctx:C,tree:T,pluginId:l.id,errorHandlers:w,currentPath:[],keyBuilder:l.keyBuilder,permissionsConfig:D,endpointMeta:l.endpointMeta,database:t,permissionsOptions:a,tenantId:r,manualConfig:s?{...s,oauthConfig:l.oauthConfig,kek:i,tenantId:f}:void 0,hubConfig:u}),Object.keys(T).length>0&&(c[l.id].api=T),C.endpoints=T;let O=l.webhooks??{},M=l.webhookHooks;if(Object.keys(O).length>0){let A={};$t({webhooks:O,hooks:M,ctx:C,webhooksTree:A,keyBuilder:l.keyBuilder}),c[l.id].webhooks=A,l.pluginWebhookMatcher&&(c[l.id].pluginWebhookMatcher=l.pluginWebhookMatcher),l.pluginTenantWebhookMatcher&&(c[l.id].pluginTenantWebhookMatcher=l.pluginTenantWebhookMatcher)}}return c}function Kr(e,n,t){let r={};for(let i of e){let o=i.options,a=i.authConfig;if(o?.authType){let s=a?.[o.authType]?.integration??[],u=I({authType:o.authType,integrationName:i.id,kek:t,database:n,extraIntegrationFields:s});r[i.id]=u}}return r}var Gi="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function Zr(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] ${Gi}`),t):n}import*as qr from"querystring";function He(e){let{oauthConfig:n,clientId:t,redirectUri:r,state:i}=e,o={...n.authParams,client_id:t,redirect_uri:r,response_type:"code",scope:n.scopes.join(" "),state:i};return`${n.authUrl}?${qr.stringify(o)}`}var W=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function Ji(e){let n=e.oauthConfig;if(!n)throw new W("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Wt(e,n){let t=P(e,()=>new W("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new W("no_database","No database configured on corsair instance");let r=t.manual?.redirectUri;if(!r)throw new W("no_redirect_uri","No redirectUri configured. Set manual.redirectUri in createCorsair().");let i=fn(n,t.kek);if(!i)throw new W("invalid_state","Invalid or tampered state parameter");let{plugin:o,tenantId:a}=i,s=$(t,o,p=>new W("plugin_not_found",p)),u=Ji(s),d=await I({authType:"oauth_2",integrationName:o,kek:t.kek,database:t.database}).get_client_id();if(!d)throw new W("client_id_not_configured",`client_id not configured for '${o}'`);let l=He({oauthConfig:u,clientId:d,redirectUri:r,state:n});return{plugin:o,tenantId:a,providerName:u.providerName,oauthUrl:l,state:n}}var v=class extends Error{status;code;extra;constructor(n,t,r,i={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=i}};function S(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function Gr(e){let n={error:e.code,message:e.message,...e.extra};return S(e.status,n)}function ge(e){return new v(404,"not_found",e)}function Q(e,n={}){return new v(400,"bad_request",e,n)}function Jr(e,n){return $(e,n,t=>ge(t))}async function zr(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=I({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),i=E[t].integration,o=r,a;try{a=await Promise.all(i.map(c=>o[`get_${c}`]()))}catch{a=i.map(()=>null)}let s=i.filter((c,d)=>a[d]==null),u;return t==="oauth_2"?u=!s.includes("client_id")&&!s.includes("client_secret"):u=s.length===0,{configured:u,missingFields:s}}async function Vr(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await zr(e,n);return{id:e.id,authType:t,configured:i,missingFields:o,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function Dn(){return{ok:!0}}async function On(e){return Promise.all(e.plugins.map(n=>Vr(n,e)))}async function Mn(e,n){let t=Jr(e,n);return Vr(t,e)}async function zi(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 Yr(e,n){let t=await zi(e,n),r=t.filter(i=>i.hasCredentials).map(i=>i.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function Hn(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 i=r.tenant_id;if(!i)continue;let o=n.get(i);o||(o={id:i,accounts:[],connectedPlugins:[]},n.set(i,o));let a=!!r.dek;o.accounts.push({integrationName:r.integrationName,hasCredentials:a}),a&&o.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function Fn(e,n){if(!n)throw Q("Tenant id must be a non-empty string");return Yr(e,n)}async function Bn(e,n){let t=n?.id?.trim();if(!t)throw Q("Tenant id is required",{missingFields:["id"]});return Yr(e,t)}async function Un(e,n){let t=n?.trim()||"default",r={},i=await je(e,t);for(let o of i)r[o.plugin]=gn(o);for(let o of e.plugins)o.id in r||(!o.options?.authType||!e.database||!e.kek?r[o.id]="missing_credentials":r[o.id]="not_connected");return r}async function jt(e,n){if(!e.database)throw ge(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ge(`Permission '${n}' not found`);return En(e,t)}function Vi(e){if(!e.oauthConfig)throw Q(`Plugin '${e.id}' has no oauthConfig`)}function Yi(e){if(!e.manual)throw new v(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function Kt(e){let n=Yi(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new v(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 Qi(e){let n=!!e.hub,t=Me(e.manual);if(!n&&!t)throw new v(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function Qr(e){if(!e.database||!e.kek)throw new v(500,"database_not_configured","A database and kek are required to issue connect links.")}async function Xi(e,n){let t=n?.plugin?.trim();if(!t)throw Q("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=Jr(e,t);Vi(i);let o=Kt(e);Qr(e);let a=await zr(i,e);if(!a.configured)throw new v(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:a.missingFields});let s=ce(z(t,r),e.kek),u;try{u=new URL(o.baseUrl)}catch{throw new v(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return u.searchParams.set("state",s),{connectUrl:u.toString(),expiresAt:new Date(Date.now()+Vn).toISOString()}}async function es(e,n,t){Qr(n);let r=t.tenantId?.trim()||"default",i=B(e);if(t.source){let c=Re({source:t.source,deliveryUrl:i.deliveryUrl,oauthMode:t.oauthMode});if(c)throw Q(c.error)}let o={tenantId:r,source:t.source??Se(i.deliveryUrl),oauthMode:t.oauthMode},a=t.plugin?.trim();a&&(o.plugin=a);let s=t.providerName?.trim();s&&(o.providerName=s);let u=await hn(e,o);return{connectUrl:u.connectUrl,expiresAt:u.expiresAt}}async function Nn(e,n,t){return Qi(n),n.hub?es(e,n,t):Xi(n,t)}async function $n(e,n,t){if(n.hub&&!Me(n.manual))throw new v(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw Q("state is required",{missingFields:["state"]});Kt(n);try{return await Wt(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw Q("Invalid or expired state");case"client_id_not_configured":throw new v(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new v(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function Ln(e,n,t){if(n.hub&&!Me(n.manual))throw new v(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),i=t?.state?.trim(),o=[];if(r||o.push("code"),i||o.push("state"),o.length)throw Q("Missing required fields",{missingFields:o});let a=Kt(n),{processOAuthCallback:s}=await import("./oauth.js");try{return await s(e,{code:r,state:i,redirectUri:a.redirectUri})}catch(u){if(u instanceof Error&&u.name==="OAuthCallbackError")switch(u.code){case"invalid_state":throw Q("Invalid or expired state");case"credentials_not_configured":throw new v(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new v(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function Zt(e,n){if(!e.database)throw ge("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ge("Permission not found");return En(e,t)}async function Xr(e,n){return"id"in n?jt(e,n.id):Zt(e,n.token)}var eo=[{method:"GET",pattern:"/ok",handler:async()=>S(200,Dn())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>S(200,await Hn(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>S(201,await Bn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>S(200,await Fn(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>S(200,await On(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>S(200,await Mn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>S(200,await Un(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>S(200,await jt(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?S(200,await Zt(e,t)):S(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>S(200,await Nn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>S(200,await $n(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>S(200,await Ln(e,n,t))}];(()=>{let e=new Set;for(let n of eo){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function ns(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let i={};for(let o=0;o<t.length;o++){let a=t[o],s=r[o];if(a.startsWith(":"))i[a.slice(1)]=decodeURIComponent(s);else if(a!==s)return null}return i}function ts(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 rs(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 v(400,"invalid_json","Request body is not valid JSON")}}var os="/api/corsair";function we(e,n={}){let t=n.basePath??os,r=P(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async i=>{try{let o=new URL(i.url),a=ts(o.pathname,t),s=i.method.toUpperCase(),u=Object.fromEntries(o.searchParams);for(let c of eo){if(c.method!==s)continue;let d=ns(c.pattern,a);if(!d)continue;let l=await rs(i);return await c.handler({corsair:e,internal:r,req:i,params:d,query:u,body:l})}throw ge(`No route for ${s} ${a}`)}catch(o){if(n.onError){let s=await n.onError(o,i);if(s)return s}if(o instanceof v)return Gr(o);let a=o instanceof Error?o.message:"Internal server error";return S(500,{error:"internal_error",message:a})}}}function is(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,i=`${t}://${n}${r}`,o=new Headers;for(let[u,c]of Object.entries(e.headers))if(c!=null)if(Array.isArray(c))for(let d of c)o.append(u,d);else o.set(u,c);let a=e.method!=="GET"&&e.method!=="HEAD",s={method:e.method,headers:o};return a&&e.body!==void 0&&(s.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),o.has("content-type")||o.set("content-type","application/json")),new Request(i,s)}async function ss(e,n){e.status(n.status),n.headers.forEach((r,i)=>e.setHeader(i,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function no(e,n){let t=we(e,n);return async(r,i,o)=>{try{let a=await t(is(r));await ss(i,a)}catch(a){o(a)}}}function to(e,n){let t=we(e,n);return r=>t(r.req.raw)}function ro(e,n){let t=we(e,n);return{GET:t,POST:t}}function oo(e){let n={[Qe]:e};return{ok:Dn,tenants:{list:()=>Hn(e),create:t=>Bn(e,t),get:t=>Fn(e,t)},plugins:{list:()=>On(e),get:t=>Mn(e,t)},connectionStatus:{get:t=>Un(e,t?.tenantId)},permissions:{get:t=>Xr(e,t)},connect:{createLink:t=>Nn(n,e,t),resolve:t=>$n(n,e,t),oauthCallback:t=>Ln(n,e,t)}}}async function io(e,n,t,r,i="pending"){if(!e)return null;try{let o=rr(),a=new Date;return await e.db.insertInto("corsair_events").values({id:o,created_at:a,updated_at:a,account_id:n,event_type:t,payload:r,status:i}).execute(),o}catch(o){return console.warn("Failed to log event:",o),null}}async function as(e,n,t,r="pending"){try{let i=await e.$getAccountId();return io(e.database,i,n,t,r)}catch(i){return console.warn("Failed to log event:",i),null}}import*as so from"https";import*as ao from"querystring";function Wn(e,n,t,r,i){let o=new URL(r.tokenUrl),a=r.tokenAuthMethod==="basic";return new Promise((s,u)=>{let c={code:e.trim(),redirect_uri:i,grant_type:"authorization_code"};a||(c.client_id=n,c.client_secret=t);let d=ao.stringify(c),l={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(d).toString()};a&&(l.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let p=so.request({hostname:o.hostname,...o.port?{port:Number(o.port)}:{},path:o.pathname+o.search,method:"POST",headers:l},f=>{let g="";f.on("data",y=>{g+=y}),f.on("end",()=>{if(f.statusCode!==200){u(new Error(`Token exchange failed (${f.statusCode}): ${g}`));return}try{s(JSON.parse(g))}catch{u(new Error(`Token endpoint returned non-JSON response: ${g}`))}})});p.on("error",f=>u(new Error(`Request failed: ${f.message}`))),p.write(d),p.end()})}var uo=" ";function K(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 j(e){return e.innerType??e.schema??e.out??e.in}function lo(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 j(e)}}function po(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function Kn(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function Fe(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 go(e,n){return e.description??n.description}function us(e){let n=e;for(;n;){let t=K(n),r=go(n,t);if(r)return r;let i=Z(t);if(Vt(i)||i==="ZodPipe"||i==="ZodEffects"||i==="ZodTransform"){n=lo(t,i);continue}break}}function Vt(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function F(e){let n=K(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??Fe(n)[0]??"unknown");case"ZodEnum":return Fe(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=j(n);return r?F(r):"unknown"}case"ZodNullable":{let r=j(n);return`${r?F(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=j(n);return r?F(r):"unknown"}case"ZodArray":{let r=po(n);if(!r)return"unknown[]";let i=K(r),o=Z(i)==="ZodUnion",a=F(r);return`${o?`(${a})`:a}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=Kn(e,n),i=Object.entries(r);return i.length===0?"{}":`{ ${i.map(([a,s])=>{let u=Z(K(s));return`${u==="ZodOptional"||u==="ZodNullable"?a+"?":a}: ${F(s)}`}).join(", ")} }`}case"ZodUnion":return Fe(n).map(r=>F(r)).join(" | ");case"ZodIntersection":return`${F(n.left)} & ${F(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=lo(n,t);return r?F(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function ie(e){let n=K(e),t=Z(n),r=go(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 i=n.value??Fe(n)[0],o=typeof i=="string"||typeof i=="number"||typeof i=="boolean"?i:String(i??"");return{kind:"literal",optional:!1,description:r,value:o}}case"ZodEnum":{let i=Fe(n).map(o=>String(o));return{kind:"string",optional:!1,description:r,enum:i}}case"ZodOptional":{let i=j(n),o=i?ie(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodNullable":{let i=j(n),o=i?ie(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodDefault":case"ZodCatch":{let i=j(n);return i?{...ie(i),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let i=po(n);return{kind:"array",optional:!1,description:r,items:i?ie(i):{kind:"unknown",optional:!1}}}case"ZodObject":{let i=Kn(e,n),o={};for(let[a,s]of Object.entries(i))o[a]=ie(s);return{kind:"object",optional:!1,description:r,fields:o}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let i=Fe(n);for(let o of i){let a=K(o);if(Z(a)==="ZodObject")return{...ie(o),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let i=j(n);return i?{...ie(i),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function Hl(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let i=t.slice(0,r),o=t.slice(r+1),a=e.find(d=>d.id===i);if(!a)return null;let s=o;s.startsWith("api.")&&(s=s.slice(4));let u=fe(a.endpointMeta,s),c=fe(a.endpointSchemas,s);return!u&&!c?null:{input:c?.input?ie(c.input):null,output:c?.output?ie(c.output):null,description:u?.description}}var Yt=["equals","contains","startsWith","endsWith","in"],cs=["equals","gt","gte","lt","lte","in"],ls=["equals"],ds=["equals","before","after","between"];function fo(e){let n=K(e);switch(Z(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=j(n);return r?fo(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Qt(e){let n=K(e),t=Z(n);if(Vt(t)){let o=j(n);return o?Qt(o):{}}if(t!=="ZodObject")return{};let r=Kn(e,n),i={};for(let[o,a]of Object.entries(r)){let s=fo(a);s==="string"?i[o]={type:"string",operators:Yt}:s==="number"?i[o]={type:"number",operators:cs}:s==="boolean"?i[o]={type:"boolean",operators:ls}:s==="date"&&(i[o]={type:"date",operators:ds})}return i}function yo(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function Gt(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];typeof i=="function"?t.push(o.join(".")):i!==null&&typeof i=="object"&&Gt(i,o,t)}}function Jt(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function zt(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];Jt(i)?t.push(o.join(".")):i!==null&&typeof i=="object"&&zt(i,o,t)}}function Xt(e,n){if(n.length===0)return null;let[t,...r]=n,i=Object.entries(e).find(([s])=>s.toLowerCase()===t);if(!i)return null;let[o,a]=i;if(r.length===0)return Jt(a)?[o]:null;if(a!==null&&typeof a=="object"&&!Jt(a)){let s=Xt(a,r);if(s!==null)return[o,...s]}return null}function ho(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let o=0;o<n.length;o++){let a=" ".repeat(o+2);t.push(`${a}${n[o]}: {`)}let r=" ".repeat(n.length+2),i=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${i}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let o=n.length-1;o>=0;o--){let a=" ".repeat(o+2);t.push(`${a}},`)}return t.push(" },"),t.push("})"),t.join(`
26
+ `)}var ps=new Set(nn);function Te(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let o=e.find(s=>s.id===r);if(!o)return ps.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:Te(e);if(t==="webhooks"){if(!o.webhooks)return[];let s=[];return zt(o.webhooks,[],s),s.map(u=>`${o.id}.webhooks.${u}`)}if(t==="db"){let s=o.schema?.entities;return s?Object.keys(s).map(u=>`${o.id}.db.${u}.search`):[]}if(!o.endpoints)return[];let a=[];return Gt(o.endpoints,[],a),a.map(s=>`${o.id}.api.${s}`)}let i={};if(t==="webhooks")for(let o of e){if(!o.webhooks)continue;let a=[];zt(o.webhooks,[],a),i[o.id]=a.map(s=>`${o.id}.webhooks.${s}`)}else if(t==="db")for(let o of e){let a=o.schema?.entities;a&&(i[o.id]=Object.keys(a).map(s=>`${o.id}.db.${s}.search`))}else for(let o of e){if(!o.endpoints)continue;let a=[];Gt(o.endpoints,[],a),i[o.id]=a.map(s=>`${o.id}.api.${s}`)}return i}function fe(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function gs(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let o=t.slice(n.length+1),a=o.startsWith(".")?o.slice(1):o;return a.startsWith("api.")&&(a=a.slice(4)),{shortPath:a,lookupKey:a}}let i=e.slice(n.length+1);return i.toLowerCase().startsWith("api.")&&(i=i.slice(4)),{shortPath:i,lookupKey:i.toLowerCase()}}function qt(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 Fl(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let i=t.slice(0,r),o=t.slice(r+1),a=e.find(s=>s.id===i);if(a){if(o.startsWith("db.")){let d=o.slice(3),l=d.lastIndexOf(".");if(l!==-1){let p=d.slice(0,l),f=d.slice(l+1),g=a.schema?.entities;if(f==="search"&&g){let y=yo(g,p);if(y){let[h,m]=y,C=Qt(m),b=[`Search ${i} ${h} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Yt.join(", ")}]`];for(let[k,w]of Object.entries(C))b.push(` ${k}?: ${w.type} [${w.operators.join(", ")}]`);return b.push("}"),b.join(`
30
+ `)}}}return qt(Te(e,{type:"db"}),"Path not found. Available db operations")}if(o.startsWith("webhooks.")){let d=o.slice(9);if(a.webhooks){let l=Xt(a.webhooks,d.split("."));if(l!==null){let p=l.join("."),f=fe(a.webhookSchemas,p.toLowerCase()),g=f?.response?F(f.response):null,y=[];return f?.description&&y.push(f.description),f?.payload&&y.push(`payload ${jn(Be(f.payload))}`),g&&y.push(`response: ${g}`),y.push(`usage:
31
+ ${ho(i,l)}`),y.join(`
32
+
33
+ `)}}return qt(Te(e,{type:"webhooks"}),"Path not found. Available webhooks")}let s=o;s.startsWith("api.")&&(s=s.slice(4));let u=fe(a.endpointMeta,s),c=fe(a.endpointSchemas,s);if(u||c){let d=[],l=[u?.riskLevel?`[${u.riskLevel}]`:"",u?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),p=[u?.description,l].filter(Boolean).join(" ");return p&&d.push(p),c?.input&&d.push(`input ${jn(Be(c.input))}`),c?.output&&d.push(`output ${jn(Be(c.output))}`),d.join(`
34
+
35
+ `)}}}return qt(Te(e),"Path not found. Available operations")}function co(e){let n=e;for(;;){let t=K(n),r=Z(t);if(Vt(r)){let i=j(t);if(!i)return n;n=i;continue}return n}}function Be(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=co(e),t=K(n);if(Z(t)==="ZodObject"){let i=Kn(n,t),o=[];for(let[a,s]of Object.entries(i)){let u=K(s),c=Z(u),d=c==="ZodOptional"||c==="ZodNullable",l=co(s),p=us(s);o.push({key:a,optional:d,type:F(l),...p!==void 0?{description:p}:{}})}return{kind:"object",fields:o}}return{kind:"inline",type:F(n)}}function jn(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=uo.repeat(n+1),r=uo.repeat(n);return`{
36
+ ${e.fields.map(o=>{let a=o.optional?`${o.key}?`:o.key,s=o.description?` // ${o.description}`:"";return`${t}${a}: ${o.type}${s}`}).join(`
37
+ `)}
38
+ ${r}}`}return"unknown"}function fs(e,n){let t=Te(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(d=>d.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let i=[];for(let d of t){let{shortPath:l,lookupKey:p}=gs(d,n),f=fe(r.endpointMeta,p),g=fe(r.endpointSchemas,p);!f&&!g||i.push({path:d,shortPath:l,description:f?.description,riskLevel:f?.riskLevel,irreversible:f?.irreversible,input:Be(g?.input),output:Be(g?.output)})}i.sort((d,l)=>d.path.localeCompare(l.path));let o=[],a=Te(e,{plugin:n,type:"webhooks"});if(Array.isArray(a)&&r.webhooks)for(let d of a){let p=d.toLowerCase().slice(n.length+1),f=p.startsWith(".")?p.slice(1):p;if(!f.startsWith("webhooks."))continue;let g=f.slice(9),y=Xt(r.webhooks,g.split("."));if(y===null)continue;let h=y.join("."),m=fe(r.webhookSchemas,h.toLowerCase()),C=m?.response?F(m.response):void 0;o.push({path:d,description:m?.description,payload:Be(m?.payload),responseType:C,usageExample:ho(n,y)})}o.sort((d,l)=>d.path.localeCompare(l.path));let s=[],u=Te(e,{plugin:n,type:"db"}),c=r.schema?.entities;if(Array.isArray(u)&&c)for(let d of u){let p=d.toLowerCase().slice(n.length+1),f=p.startsWith(".")?p.slice(1):p;if(!f.startsWith("db."))continue;let g=f.slice(3),y=g.lastIndexOf(".");if(y===-1)continue;let h=g.slice(0,y);if(g.slice(y+1)!=="search")continue;let C=yo(c,h);if(!C)continue;let[b,k]=C,w=Qt(k),T=Object.entries(w).map(([D,O])=>({field:D,type:O.type,operators:O.operators}));s.push({path:d,entityName:b,filters:[{field:"entity_id",type:"string",operators:Yt},...T]})}return s.sort((d,l)=>d.path.localeCompare(l.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:s}}}function mo(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function ys(e,n){let t=mo(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let i=r.pluginTenantWebhookMatcher(n);return i?{plugin:t,tenantMatch:i}:null}function hs(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function ko(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function bo(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 Xe(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function ms(e){return Xe(e.body)}function Co(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Zn(Array.isArray(r)?r:[r])}function wo(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let u of t){let c=Zn(Array.isArray(u)?u:[u]);if(c)return decodeURIComponent(c)}let r=Co({query:e.query},"validationToken");if(r)return r;let i=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let u of i){let c=n[u],d=Array.isArray(c)?c[0]:c;if(!(!d||typeof d!="string"))try{let p=(d.startsWith("http")?new URL(d):new URL(`https://example.invalid${d.startsWith("/")?d:`/${d}`}`)).searchParams.get("validationToken");if(p?.trim())return p.trim()}catch{continue}}let o=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,a=Xe(typeof o=="string"?(()=>{try{return JSON.parse(o)}catch{return o}})():o);return Zn([a?.validationToken])??null}function ks(e){if(wo(e))return!0;let n=Xe(e.body??e.payload);return ko(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Zn(e){for(let n of e){let t=bo(n);if(t)return t}}function bs(e){let t=Xe(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var Qe=Symbol.for("corsair:internal");function Cr(e){let n=e.database?er(e.database):void 0,t=n&&e.kek?Kr(e.plugins,n,e.kek):_n(!!n,!!e.kek),r=Zr(e),i={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?tn(e.hub):void 0},o=Wr(n),a=oo(i);if(e.multiTenancy)return Object.assign({withTenant:u=>{if(!u)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let c=Lt(e.plugins,{database:n,tenantId:u,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(c,{[Qe]:i})},keys:t,permissions:o,manage:a},{[Qe]:i});let s=Lt(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign({},s,{keys:t,permissions:o,manage:a,[Qe]:i})}var U=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function To(e){let n=e.oauthConfig;if(!n)throw new U("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Cs(e,n,t,r){let i=ir(e),o=await i.integrations.findByName(n);if(!o)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:t,integration_id:o.id}))return;let s=ee(),u=await ne(s,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:u})}async function Xn(e,n,t){let{tenantId:r,redirectUri:i}=t,o=P(e,()=>new U("invalid_corsair_instance","Invalid corsair instance"));if(!o.database)throw new Error("No database configured on corsair instance");let a=$(o,n,l=>new U("plugin_not_found",l)),s=To(a),c=await I({authType:"oauth_2",integrationName:n,kek:o.kek,database:o.database}).get_client_id();if(!c)throw new Error(`client_id not configured for '${n}'`);let d=ce(z(n,r),o.kek);return{url:He({oauthConfig:s,clientId:c,redirectUri:i,state:d}),state:d}}async function Ve(e,n){let{code:t,state:r,redirectUri:i}=n,o=P(e,()=>new U("invalid_corsair_instance","Invalid corsair instance")),a=fn(r,o.kek);if(!a)throw new U("invalid_state","Invalid or tampered state parameter");let{plugin:s,tenantId:u}=a;if(!o.database)throw new U("no_database","No database configured on corsair instance");let c=$(o,s,h=>new U("plugin_not_found",h)),d=To(c),l=I({authType:"oauth_2",integrationName:s,kek:o.kek,database:o.database}),p=await l.get_client_id(),f=await l.get_client_secret();if(!p||!f)throw new U("credentials_not_configured",`Credentials not configured for '${s}'`);await Cs(o.database,s,u,o.kek);let g=await Wn(t,p,f,d,i);if(!g.access_token)throw new U("no_access_token",`No access_token returned from ${d.providerName}`);let y=x({authType:"oauth_2",integrationName:s,tenantId:u,kek:o.kek,database:o.database});await y.set_access_token(g.access_token),g.refresh_token&&await y.set_refresh_token(g.refresh_token),g.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+g.expires_in));try{let h=await Cn(o.plugins,s,g);if(h)try{let m=c.authConfig?.oauth_2?.account??[];await Ee({database:o.database,kek:o.kek,pluginId:s,tenantId:u,link:h,authType:"oauth_2",extraAccountFields:m})}catch(m){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${s}' tenant '${u}':`,m)}}catch(h){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${s}' tenant '${u}':`,h)}return{plugin:s,tenantId:u}}export{sr as a,ae as b,Ne as c,he as d,tn as e,B as f,rn as g,on as h,sn as i,an as j,ar as k,un as l,ee as m,ne as n,L as o,Gn as p,Le as q,ue as r,te as s,We as t,I as u,x as v,gr as w,fr as x,z as y,zn as z,Ee as A,et as B,wn as C,xr as D,He as E,U as F,Xn as G,Ve as H,Ze as I,Se as J,hr as K,Re as L,kr as M,si as N,hn as O,_e as P,le as Q,me as R,de as S,De as T,Tn as U,tt as V,Oe as W,rt as X,ot as Y,it as Z,st as _,_r as $,re as aa,vn as ba,An as ca,pe as da,be as ea,Ce as fa,Je as ga,ze as ha,xn as ia,lt as ja,dt as ka,pt as la,gt as ma,ft as na,yt as oa,ht as pa,Ye as qa,oe as ra,mt as sa,Hr as ta,Rn as ua,In as va,Fr as wa,kt as xa,bt as ya,Ct as za,wt as Aa,Tt as Ba,Pt as Ca,vt as Da,At as Ea,xt as Fa,St as Ga,Rt as Ha,It as Ia,_t as Ja,Et as Ka,Dt as La,Wt as Ma,we as Na,no as Oa,to as Pa,ro as Qa,io as Ra,as as Sa,Wn as Ta,Hl as Ua,Te as Va,Fl as Wa,jn as Xa,fs as Ya,mo as Za,ys as _a,hs as $a,ko as ab,bo as bb,Xe as cb,ms as db,Co as eb,wo as fb,ks as gb,Zn as hb,bs as ib,Qe as jb,Cr as kb};
package/dist/core.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-SNBBST6f.js';
1
+ export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-BOgiPWN6.js';
2
2
  import { CorsairDatabase } from './db.js';
3
3
  import { A as AuthTypes, a as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './types-C2vFipdU.js';
4
4
  export { b as AccountFieldNames, f as AllProviders, e as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, c as BaseKeyManager, g as BaseProviders, k as Bivariant, d as IntegrationFieldNames, O as OAuth2IntegrationCredentials, h as PickAuth, P as PluginAuthConfig, j as ProviderDisplayNames, U as UnionToIntersection, i as formatProviderDisplayName } from './types-C2vFipdU.js';
5
- export { v as BeforeHookResult, B as BindEndpoints, N as BindWebhooks, h as BoundEndpointFn, i as BoundEndpointTree, Q as BoundWebhook, S as BoundWebhookTree, g as CorsairClient, j as CorsairContext, k as CorsairEndpoint, m as CorsairErrorHandler, c as CorsairIntegration, w as CorsairKeyBuilder, x as CorsairKeyBuilderBase, U as CorsairOAuthWebhookTenantLinkResolver, s as CorsairPermissionsNamespace, C as CorsairPlugin, y as CorsairPluginContext, e as CorsairSingleTenantClient, d as CorsairTenantWrapper, V as CorsairWebhook, X as CorsairWebhookHandler, Y as CorsairWebhookMatcher, Z as CorsairWebhookTenantMatcher, z as EndpointHooks, A as EndpointMetaEntry, E as EndpointPathsOf, D as EndpointRiskLevel, l as EndpointTree, t as EnforcePermissionOptions, u as EnforcePermissionResult, n as ErrorContext, o as ErrorHandler, p as ErrorHandlerAndMatchFunction, q as ErrorMatcher, K as KeyBuilderContext, O as OAuthConfig, P as PermissionMode, F as PermissionPolicy, G as PluginEndpointMeta, H as PluginPermissionsConfig, _ as RawWebhookRequest, I as RequiredPluginEndpointMeta, J as RequiredPluginEndpointSchemas, L as RequiredPluginWebhookSchemas, R as RetryStrategies, r as RetryStrategy, T as TokenResponse, M as WebhookHooks, $ as WebhookPathsOf, a0 as WebhookRequest, a1 as WebhookResponse, W as WebhookTenantMatch, a2 as WebhookTree, f as exchangeCodeForTokens } from './index-CnnnYiGH.js';
6
- 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-CMI2112T.js';
5
+ export { v as BeforeHookResult, B as BindEndpoints, N as BindWebhooks, h as BoundEndpointFn, i as BoundEndpointTree, Q as BoundWebhook, S as BoundWebhookTree, g as CorsairClient, j as CorsairContext, k as CorsairEndpoint, m as CorsairErrorHandler, c as CorsairIntegration, w as CorsairKeyBuilder, x as CorsairKeyBuilderBase, U as CorsairOAuthWebhookTenantLinkResolver, s as CorsairPermissionsNamespace, C as CorsairPlugin, y as CorsairPluginContext, e as CorsairSingleTenantClient, d as CorsairTenantWrapper, V as CorsairWebhook, X as CorsairWebhookHandler, Y as CorsairWebhookMatcher, Z as CorsairWebhookTenantMatcher, z as EndpointHooks, A as EndpointMetaEntry, E as EndpointPathsOf, D as EndpointRiskLevel, l as EndpointTree, t as EnforcePermissionOptions, u as EnforcePermissionResult, n as ErrorContext, o as ErrorHandler, p as ErrorHandlerAndMatchFunction, q as ErrorMatcher, K as KeyBuilderContext, O as OAuthConfig, P as PermissionMode, F as PermissionPolicy, G as PluginEndpointMeta, H as PluginPermissionsConfig, _ as RawWebhookRequest, I as RequiredPluginEndpointMeta, J as RequiredPluginEndpointSchemas, L as RequiredPluginWebhookSchemas, R as RetryStrategies, r as RetryStrategy, T as TokenResponse, M as WebhookHooks, $ as WebhookPathsOf, a0 as WebhookRequest, a1 as WebhookResponse, W as WebhookTenantMatch, a2 as WebhookTree, f as exchangeCodeForTokens } from './index-Cs2O9Pmx.js';
6
+ 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-CHQomRrU.js';
7
7
  import 'kysely';
8
8
  import 'zod';
9
9
  import 'pg';
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{$a as x,Q as p,Sa as r,Ta as s,Ua as t,Ya as u,Za as v,_a as w,a,ab as y,b,bb as z,cb as A,db as B,eb as C,fb as D,gb as E,hb as F,ib as G,jb as H,kb as I,lb as J,o as d,p as e,q as f,r as g,s as h,t as i,u as j,v as k,va as q,w as l,x as m,y as n,z as o}from"./chunk-2LV4I6JX.js";import{g as c}from"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,p as resolveConnectLink,A as toExternalId};
1
+ import{$a as y,Ma as q,Ra as r,Sa as s,Ta as t,Xa as u,Ya as v,Za as w,_a as x,a,ab as z,b,bb as A,cb as B,db as C,eb as D,fb as E,gb as F,hb as G,ib as H,jb as I,kb as J,m as d,n as e,o as f,p as g,q as h,r as i,ra as p,s as j,t as k,u as l,v as m,w as n,x as o}from"./chunk-PUAVA6PG.js";import{g as c}from"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{p as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,q as resolveConnectLink,A as toExternalId};
package/dist/hub.d.ts CHANGED
@@ -16,11 +16,21 @@ type ConnectPluginManifestEntry = {
16
16
  state?: string;
17
17
  setupError?: string;
18
18
  };
19
+ type ConnectAuthFieldStatus = {
20
+ name: string;
21
+ level: 'integration' | 'account';
22
+ required: boolean;
23
+ configured: boolean;
24
+ };
25
+ type ConnectAuthStatusLevel = 'ready' | 'partial' | 'not_started' | 'missing_integration';
19
26
  type ConnectStatusPluginEntry = {
20
27
  plugin: string;
21
28
  providerName: string;
22
29
  authKind: ConnectAuthKind;
30
+ status: ConnectAuthStatusLevel;
23
31
  connected: boolean;
32
+ fields: ConnectAuthFieldStatus[];
33
+ missingRequiredFields: string[];
24
34
  };
25
35
  type ConnectStatusResponse = {
26
36
  tenantId: string;
@@ -61,8 +71,6 @@ type ConnectSourceValidationError = {
61
71
  declare function isLoopbackDeliveryUrl(deliveryUrl: string): boolean;
62
72
  declare function resolveConnectSourceFromDeliveryUrl(deliveryUrl: string): HubConnectSource;
63
73
  declare function shouldUseBrowserDelivery(source: HubConnectSource, deliveryUrl: string): boolean;
64
- /** @deprecated Use {@link shouldUseBrowserDelivery} */
65
- declare const shouldUseBrowserConnectDelivery: typeof shouldUseBrowserDelivery;
66
74
  declare function validateExplicitConnectSource(input: {
67
75
  source?: HubConnectSource;
68
76
  deliveryUrl: string;
@@ -429,4 +437,4 @@ declare function decodePermissionTokenFromPath(encoded: string): string;
429
437
  */
430
438
  declare function createSignedTokenJti(): string;
431
439
 
432
- export { type ConnectAuthKind, type ConnectPluginManifestEntry, type ConnectSessionTokenPayload, type ConnectSourceValidationError, type ConnectStatusPluginEntry, type ConnectStatusResponse, type ConnectTokenPayload, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, HubConfig, HubConfigInput, HubConnectSessionInput, HubConnectSessionResult, HubConnectSource, type HubDeliveryRequest, type HubDeliveryResult, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, HubPermissionSessionInput, HubPermissionSessionResult, type ManagedAccessTokenResult, type ManagedAuthContext, ManagedOAuthDeliveryError, type PermissionTokenPayload, type ProcessManagedOAuthDeliveryOptions, type ProcessManagedOAuthDeliveryResult, type ServerDeliveryAckBody, type SignedDeliveryHeaders, type SignedEnvelopeDeliveryResult, TunnelType, attachManagedRefreshAuth, createConnectSessionJti, createConnectTokenJti, createHubConnectSession, createHubPermissionSession, createHubRouteHandlers, createPermissionSessionJti, createSignedTokenJti, decodeConnectSessionTokenFromPath, decodeConnectTokenFromPath, decodePermissionTokenFromPath, deliverSignedEnvelope, encodeConnectTokenForPath, formatHubApprovalMessage, formatServerDeliveryError, getConnectSessionExpiryMs, getConnectStatusForTenant, getConnectTokenExpiryMs, getHubConfig, getManagedAccessToken, handleHubDeliveryGet, handleHubDeliveryPost, handleHubDeliveryRequest, hubDeliveryToResponse, isLoopbackDeliveryUrl, isServerDeliveryAckSuccessful, normalizeHubConfig, parseConnectSessionResponse, parseConnectStatusResponse, parseHubApiErrorBody, parseOAuthRefreshResponse, parsePermissionSessionResponse, parseServerDeliveryAckBody, processManagedOAuthDelivery, resolveConnectSourceFromDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, shouldUseBrowserConnectDelivery, shouldUseBrowserDelivery, signConnectSessionToken, signConnectToken, signDeliveryEnvelope, signPermissionToken, validateExplicitConnectSource, verifyConnectSessionToken, verifyConnectToken, verifyDeliveryEnvelope, verifyPermissionToken, verifySignedTunnelDelivery };
440
+ export { type ConnectAuthFieldStatus, type ConnectAuthKind, type ConnectAuthStatusLevel, type ConnectPluginManifestEntry, type ConnectSessionTokenPayload, type ConnectSourceValidationError, type ConnectStatusPluginEntry, type ConnectStatusResponse, type ConnectTokenPayload, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, HubConfig, HubConfigInput, HubConnectSessionInput, HubConnectSessionResult, HubConnectSource, type HubDeliveryRequest, type HubDeliveryResult, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, HubPermissionSessionInput, HubPermissionSessionResult, type ManagedAccessTokenResult, type ManagedAuthContext, ManagedOAuthDeliveryError, type PermissionTokenPayload, type ProcessManagedOAuthDeliveryOptions, type ProcessManagedOAuthDeliveryResult, type ServerDeliveryAckBody, type SignedDeliveryHeaders, type SignedEnvelopeDeliveryResult, TunnelType, attachManagedRefreshAuth, createConnectSessionJti, createConnectTokenJti, createHubConnectSession, createHubPermissionSession, createHubRouteHandlers, createPermissionSessionJti, createSignedTokenJti, decodeConnectSessionTokenFromPath, decodeConnectTokenFromPath, decodePermissionTokenFromPath, deliverSignedEnvelope, encodeConnectTokenForPath, formatHubApprovalMessage, formatServerDeliveryError, getConnectSessionExpiryMs, getConnectStatusForTenant, getConnectTokenExpiryMs, getHubConfig, getManagedAccessToken, handleHubDeliveryGet, handleHubDeliveryPost, handleHubDeliveryRequest, hubDeliveryToResponse, isLoopbackDeliveryUrl, isServerDeliveryAckSuccessful, normalizeHubConfig, parseConnectSessionResponse, parseConnectStatusResponse, parseHubApiErrorBody, parseOAuthRefreshResponse, parsePermissionSessionResponse, parseServerDeliveryAckBody, processManagedOAuthDelivery, resolveConnectSourceFromDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, shouldUseBrowserDelivery, signConnectSessionToken, signConnectToken, signDeliveryEnvelope, signPermissionToken, validateExplicitConnectSource, verifyConnectSessionToken, verifyConnectToken, verifyDeliveryEnvelope, verifyPermissionToken, verifySignedTunnelDelivery };
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as A,Aa as T,Ba as U,Ca as V,Da as W,Ea as X,Fa as Y,Ga as Z,Ha as _,I as l,Ia as $,J as m,Ja as aa,K as n,Ka as ba,L as o,La as ca,M as p,Ma as da,Na as ea,P as q,R as r,S as s,T as t,U as u,V as v,W as w,X as x,Z as y,_ as z,aa as B,b as a,ba as C,c as b,ca as D,d as c,da as E,e as d,ea as F,f as e,fa as G,g as f,ga as H,h as g,ha as I,i as h,j as i,k as j,l as k,pa as J,qa as K,ra as L,sa as M,ta as N,ua as O,wa as P,xa as Q,ya as R,za as S}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{u as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,w as ManagedOAuthDeliveryError,v as SIGNED_TUNNEL_REPLAY_WINDOW_MS,Q as attachManagedRefreshAuth,G as buildBrowserDeliveryRedirectUrl,S as createConnectSessionJti,X as createConnectTokenJti,q as createHubConnectSession,r as createHubPermissionSession,R as createHubRouteHandlers,ba as createPermissionSessionJti,F as createSignedTokenJti,W as decodeConnectSessionTokenFromPath,aa as decodeConnectTokenFromPath,ea as decodePermissionTokenFromPath,E as deliverSignedEnvelope,$ as encodeConnectTokenForPath,s as formatHubApprovalMessage,a as formatProviderDisplayName,D as formatServerDeliveryError,T as getConnectSessionExpiryMs,t as getConnectStatusForTenant,Y as getConnectTokenExpiryMs,e as getHubConfig,P as getManagedAccessToken,J as handleHubDeliveryGet,K as handleHubDeliveryPost,M as handleHubDeliveryRequest,L as hubDeliveryToResponse,l as isLoopbackDeliveryUrl,C as isServerDeliveryAckSuccessful,d as normalizeHubConfig,g as parseConnectSessionResponse,j as parseConnectStatusResponse,k as parseHubApiErrorBody,i as parseOAuthRefreshResponse,h as parsePermissionSessionResponse,B as parseServerDeliveryAckBody,x as processManagedOAuthDelivery,m as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,N as respondToHubDelivery,O as respondToHubDeliveryFromRequest,o as shouldUseBrowserConnectDelivery,n as shouldUseBrowserDelivery,H as signBrowserDeliveryToken,U as signConnectSessionToken,Z as signConnectToken,y as signDeliveryEnvelope,ca as signPermissionToken,p as validateExplicitConnectSource,I as verifyBrowserDeliveryToken,V as verifyConnectSessionToken,_ as verifyConnectToken,z as verifyDeliveryEnvelope,da as verifyPermissionToken,A as verifySignedTunnelDelivery};
1
+ import{Aa as U,Ba as V,Ca as W,Da as X,Ea as Y,Fa as Z,Ga as _,Ha as $,I as l,Ia as aa,J as m,Ja as ba,K as n,Ka as ca,L as o,La as da,O as p,P as q,Q as r,R as s,S as t,T as u,U as v,V as w,W as x,X as y,Y as z,Z as A,_ as B,aa as C,b as a,ba as D,c as b,ca as E,d as c,da as F,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,la as G,ma as H,na as I,oa as J,pa as K,qa as L,sa as M,ta as N,ua as O,va as P,wa as Q,xa as R,ya as S,za as T}from"./chunk-PUAVA6PG.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{r as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,t as ManagedOAuthDeliveryError,s as SIGNED_TUNNEL_REPLAY_WINDOW_MS,N as attachManagedRefreshAuth,D as buildBrowserDeliveryRedirectUrl,R as createConnectSessionJti,W as createConnectTokenJti,p as createHubConnectSession,O as createHubPermissionSession,Q as createHubRouteHandlers,aa as createPermissionSessionJti,C as createSignedTokenJti,V as decodeConnectSessionTokenFromPath,$ as decodeConnectTokenFromPath,da as decodePermissionTokenFromPath,B as deliverSignedEnvelope,_ as encodeConnectTokenForPath,P as formatHubApprovalMessage,a as formatProviderDisplayName,A as formatServerDeliveryError,S as getConnectSessionExpiryMs,q as getConnectStatusForTenant,X as getConnectTokenExpiryMs,e as getHubConfig,M as getManagedAccessToken,G as handleHubDeliveryGet,H as handleHubDeliveryPost,J as handleHubDeliveryRequest,I as hubDeliveryToResponse,l as isLoopbackDeliveryUrl,z as isServerDeliveryAckSuccessful,d as normalizeHubConfig,g as parseConnectSessionResponse,j as parseConnectStatusResponse,k as parseHubApiErrorBody,i as parseOAuthRefreshResponse,h as parsePermissionSessionResponse,y as parseServerDeliveryAckBody,u as processManagedOAuthDelivery,m as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,K as respondToHubDelivery,L as respondToHubDeliveryFromRequest,n as shouldUseBrowserDelivery,E as signBrowserDeliveryToken,T as signConnectSessionToken,Y as signConnectToken,v as signDeliveryEnvelope,ba as signPermissionToken,o as validateExplicitConnectSource,F as verifyBrowserDeliveryToken,U as verifyConnectSessionToken,Z as verifyConnectToken,w as verifyDeliveryEnvelope,ca as verifyPermissionToken,x as verifySignedTunnelDelivery};
@@ -1,6 +1,6 @@
1
1
  import { CorsairDatabase } from './db.js';
2
2
  import { H as HubConfig } from './types-C2vFipdU.js';
3
- import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-CnnnYiGH.js';
3
+ import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-Cs2O9Pmx.js';
4
4
 
5
5
  declare const CORSAIR_INTERNAL: unique symbol;
6
6
  type CorsairInternalConfig = {
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { a3 as ManagementOk, a4 as Tenant, a5 as CreateTenantInput, a6 as PluginInfo, a7 as ConnectionStatus, a8 as PermissionLookupInput, a9 as PermissionRecord, aa as CreateConnectLinkInput, ab as ConnectLink, ac as ResolvedConnectLink, ad as OAuthCallbackInput, ae as OAuthCallbackResult, e as CorsairSingleTenantClient, C as CorsairPlugin, d as CorsairTenantWrapper, g as CorsairClient, s as CorsairPermissionsNamespace, S as BoundWebhookTree, _ as RawWebhookRequest, Z as CorsairWebhookTenantMatcher, a1 as WebhookResponse } from './index-CnnnYiGH.js';
2
- export { af as CorsairManageNamespace, b as CorsairManualConfig, a as CorsairPermissionsOptions, ag as PluginConnectionState } from './index-CnnnYiGH.js';
3
- export { c as createCorsair } from './index-SNBBST6f.js';
4
- import { F as FormFieldSchema, L as ListOperationsOptions } from './tenant-match-utils-CMI2112T.js';
5
- 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-CMI2112T.js';
1
+ import { a3 as ManagementOk, a4 as Tenant, a5 as CreateTenantInput, a6 as PluginInfo, a7 as ConnectionStatus, a8 as PermissionLookupInput, a9 as PermissionRecord, aa as CreateConnectLinkInput, ab as ConnectLink, ac as ResolvedConnectLink, ad as OAuthCallbackInput, ae as OAuthCallbackResult, e as CorsairSingleTenantClient, C as CorsairPlugin, d as CorsairTenantWrapper, g as CorsairClient, s as CorsairPermissionsNamespace, S as BoundWebhookTree, _ as RawWebhookRequest, Z as CorsairWebhookTenantMatcher, a1 as WebhookResponse } from './index-Cs2O9Pmx.js';
2
+ export { af as CorsairManageNamespace, b as CorsairManualConfig, a as CorsairPermissionsOptions, ag as PluginConnectionState } from './index-Cs2O9Pmx.js';
3
+ export { c as createCorsair } from './index-BOgiPWN6.js';
4
+ import { F as FormFieldSchema, L as ListOperationsOptions } from './tenant-match-utils-CHQomRrU.js';
5
+ 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-CHQomRrU.js';
6
6
  export { SetupCorsairOptions, setupCorsair } from './setup.js';
7
7
  export { O as OAuthCallbackTunnelPayload, P as ProcessCorsairOptions, c as ProcessCorsairRequest, T as TunnelAck, d as TunnelEnvelope, e as TunnelType, W as WebhookTunnelPayload, p as processCorsair } from './index-LpuBJQ1m.js';
8
8
  import { g as BaseProviders } from './types-C2vFipdU.js';
9
- export { R as ResolveAccountFromWebhookLinkInput, W as WebhookTenantLink, r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-_vxzYuKb.js';
9
+ export { R as ResolveAccountFromWebhookLinkInput, W as WebhookTenantLink, r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-Cg8-Zu9C.js';
10
10
  import 'zod';
11
11
  import './db.js';
12
12
  import 'kysely';
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{$a as M,A as P,B as x,C as b,D as I,N as R,Oa as L,Pa as A,Q as w,Qa as v,Ra as $,Va as d,Wa as g,Xa as C,Y as S,Ya as f,_a as E,ab as W,bb as F,cb as _,db as N,eb as D,ib as H,jb as j,kb as k,lb as J,oa as O,va as T}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";var u=class extends Error{status;code;extra;constructor(r,o,e,a={}){super(e),this.name="CorsairClientError",this.status=r,this.code=o,this.extra=a}};function U(n){return n.endsWith("/")?n.slice(0,-1):n}async function y(n){let r={};try{r=await n.json()}catch{}let o=typeof r.error=="string"?r.error:"request_failed",e=typeof r.message=="string"?r.message:`Request failed (${n.status})`,{error:a,message:c,...t}=r;return new u(n.status,o,e,t)}function q(n){let r=U(n.baseURL),o=n.fetch??((...t)=>globalThis.fetch(...t));async function e(t,s){let i=s&&Object.keys(s).length?`?${new URLSearchParams(s).toString()}`:"",p=await o(`${r}${t}${i}`,{method:"GET"});if(!p.ok)throw await y(p);return await p.json()}async function a(t,s){let i=await o(`${r}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw await y(i);return await i.json()}let c=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:t=>a("/tenants",t),get:t=>e(`/tenants/${c(t)}`)},plugins:{list:()=>e("/plugins"),get:t=>e(`/plugins/${c(t)}`)},connectionStatus:{get:t=>{let s={};return t?.tenantId&&(s.tenantId=t.tenantId),e("/connection-status",s)}},permissions:{get:t=>"id"in t?e(`/permissions/${c(t.id)}`):a("/permissions/lookup-by-token",{token:t.token})},connect:{createLink:t=>a("/connect/links",t),resolve:t=>e("/connect/resolve",{state:t}),oauthCallback:t=>a("/connect/oauth/callback",t)}}}function l(n){let r=n[k];if(!r)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return r.plugins}function B(n,r){let o=g(l(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
1
+ import{$ as w,$a as W,A as P,B as x,C as b,D as I,M as R,Ma as T,Na as L,Oa as A,Pa as v,Qa as $,Ua as d,Va as g,Wa as C,Xa as f,Za as E,_a as M,ab as F,bb as _,cb as N,db as D,hb as H,ib as j,jb as k,ka as S,kb as J,ra as O}from"./chunk-PUAVA6PG.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";var u=class extends Error{status;code;extra;constructor(r,o,e,a={}){super(e),this.name="CorsairClientError",this.status=r,this.code=o,this.extra=a}};function U(n){return n.endsWith("/")?n.slice(0,-1):n}async function y(n){let r={};try{r=await n.json()}catch{}let o=typeof r.error=="string"?r.error:"request_failed",e=typeof r.message=="string"?r.message:`Request failed (${n.status})`,{error:a,message:c,...t}=r;return new u(n.status,o,e,t)}function q(n){let r=U(n.baseURL),o=n.fetch??((...t)=>globalThis.fetch(...t));async function e(t,s){let i=s&&Object.keys(s).length?`?${new URLSearchParams(s).toString()}`:"",p=await o(`${r}${t}${i}`,{method:"GET"});if(!p.ok)throw await y(p);return await p.json()}async function a(t,s){let i=await o(`${r}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw await y(i);return await i.json()}let c=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:t=>a("/tenants",t),get:t=>e(`/tenants/${c(t)}`)},plugins:{list:()=>e("/plugins"),get:t=>e(`/plugins/${c(t)}`)},connectionStatus:{get:t=>{let s={};return t?.tenantId&&(s.tenantId=t.tenantId),e("/connection-status",s)}},permissions:{get:t=>"id"in t?e(`/permissions/${c(t.id)}`):a("/permissions/lookup-by-token",{token:t.token})},connect:{createLink:t=>a("/connect/links",t),resolve:t=>e("/connect/resolve",{state:t}),oauthCallback:t=>a("/connect/oauth/callback",t)}}}function l(n){let r=n[k];if(!r)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return r.plugins}function B(n,r){let o=g(l(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
2
2
  `):Object.values(o).flat().join(`
3
- `)}function G(n,r){return C(l(n),r)}function Y(n,r){return d(l(n),r)}var z=Symbol.for("corsair:internal");function K(n,r){let o=n;for(let e of r){if(!o||typeof o!="object")return null;o=o[e]}return typeof o=="function"?o:null}function h(n){return n[z]?.database}async function Q(n,r){let o=new Date().toISOString(),e=await n.permissions.find_by_token(r);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<o){let i=h(n);return i&&await i.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 a=e.tenant_id??"default",t=(n.withTenant?n.withTenant(a):n)[e.plugin];if(!t?.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 s=K(t.api,e.endpoint.split("."));if(!s)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 i=typeof e.args=="string"?JSON.parse(e.args):e.args,p=await s(i);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:p}}catch(i){let p=i instanceof Error?i.message:String(i),m=h(n);return m&&await m.db.updateTable("corsair_permissions").set({status:"failed",error:p,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:p}}}export{T as AuthMissingError,u as CorsairClientError,N as asRecord,W as collectPluginWebhookMatchers,J as createCorsair,q as createCorsairClient,j as decodePubSubData,Q as executePermission,H as firstString,f as formatDocSchemaShape,F as getHeader,G as getSchema,Y as getStructuredSchema,B as listOperations,L as managementHandler,E as matchWebhookPlugin,M as matchWebhookPluginAndTenant,O as processCorsair,S as processWebhook,D as readBodyRecord,x as resolveAccountFromWebhookLink,w as resolveConnectLink,I as resolveTenantFromWebhookLink,b as resolveTenantIdFromWebhookLink,P as setWebhookTenantLink,R as setupCorsair,A as toExpressHandler,_ as toExternalId,v as toHonoHandler,$ as toNextJsHandler};
3
+ `)}function G(n,r){return C(l(n),r)}function Y(n,r){return d(l(n),r)}var z=Symbol.for("corsair:internal");function K(n,r){let o=n;for(let e of r){if(!o||typeof o!="object")return null;o=o[e]}return typeof o=="function"?o:null}function h(n){return n[z]?.database}async function Q(n,r){let o=new Date().toISOString(),e=await n.permissions.find_by_token(r);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<o){let i=h(n);return i&&await i.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 a=e.tenant_id??"default",t=(n.withTenant?n.withTenant(a):n)[e.plugin];if(!t?.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 s=K(t.api,e.endpoint.split("."));if(!s)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 i=typeof e.args=="string"?JSON.parse(e.args):e.args,p=await s(i);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:p}}catch(i){let p=i instanceof Error?i.message:String(i),m=h(n);return m&&await m.db.updateTable("corsair_permissions").set({status:"failed",error:p,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:p}}}export{O as AuthMissingError,u as CorsairClientError,N as asRecord,W as collectPluginWebhookMatchers,J as createCorsair,q as createCorsairClient,j as decodePubSubData,Q as executePermission,H as firstString,f as formatDocSchemaShape,F as getHeader,G as getSchema,Y as getStructuredSchema,B as listOperations,L as managementHandler,E as matchWebhookPlugin,M as matchWebhookPluginAndTenant,S as processCorsair,w as processWebhook,D as readBodyRecord,x as resolveAccountFromWebhookLink,T as resolveConnectLink,I as resolveTenantFromWebhookLink,b as resolveTenantIdFromWebhookLink,P as setWebhookTenantLink,R as setupCorsair,A as toExpressHandler,_ as toExternalId,v as toHonoHandler,$ as toNextJsHandler};
package/dist/oauth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { O as OAuthConfig } from './index-CnnnYiGH.js';
1
+ import { O as OAuthConfig } from './index-Cs2O9Pmx.js';
2
2
  import 'zod';
3
3
  import './db.js';
4
4
  import 'kysely';
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{E as c,F as d,G as e,H as f,m as a,n as b}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.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};
1
+ import{E as c,F as d,G as e,H as f,y as a,z as b}from"./chunk-PUAVA6PG.js";import"./chunk-NZS35HPL.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};
package/dist/setup.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as CorsairInternalConfig } from './index-SNBBST6f.js';
1
+ import { a as CorsairInternalConfig } from './index-BOgiPWN6.js';
2
2
  import { CorsairDatabase } from './db.js';
3
- import { C as CorsairPlugin, e as CorsairSingleTenantClient, d as CorsairTenantWrapper } from './index-CnnnYiGH.js';
3
+ import { C as CorsairPlugin, e as CorsairSingleTenantClient, d as CorsairTenantWrapper } from './index-Cs2O9Pmx.js';
4
4
  import './types-C2vFipdU.js';
5
5
  import 'kysely';
6
6
  import 'zod';
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{N as a,O as b}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{M as a,N as b}from"./chunk-PUAVA6PG.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
@@ -1,5 +1,5 @@
1
1
  import { A as AuthTypes } from './types-C2vFipdU.js';
2
- import { W as WebhookTenantMatch } from './index-CnnnYiGH.js';
2
+ import { W as WebhookTenantMatch } from './index-Cs2O9Pmx.js';
3
3
  import { CorsairDatabase, CorsairAccount } from './db.js';
4
4
 
5
5
  type WebhookTenantLink = WebhookTenantMatch;
@@ -1,4 +1,4 @@
1
- import { D as EndpointRiskLevel, C as CorsairPlugin, Y as CorsairWebhookMatcher, Z as CorsairWebhookTenantMatcher, _ as RawWebhookRequest, W as WebhookTenantMatch } from './index-CnnnYiGH.js';
1
+ import { D as EndpointRiskLevel, C as CorsairPlugin, Y as CorsairWebhookMatcher, Z as CorsairWebhookTenantMatcher, _ as RawWebhookRequest, W as WebhookTenantMatch } from './index-Cs2O9Pmx.js';
2
2
  import { f as AllProviders } from './types-C2vFipdU.js';
3
3
 
4
4
  /**
package/dist/tunnel.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { B as BrowserDeliveryPayload } from './index-LpuBJQ1m.js';
2
2
  export { O as OAuthCallbackTunnelPayload, b as OAuthTokensTunnelPayload, P as ProcessCorsairOptions, c as ProcessCorsairRequest, T as TunnelAck, d as TunnelEnvelope, e as TunnelType, W as WebhookTunnelPayload, a as applyPermissionDecision, p as processCorsair } from './index-LpuBJQ1m.js';
3
- export { r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-_vxzYuKb.js';
3
+ export { r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-Cg8-Zu9C.js';
4
4
  export { v as verifyBrowserDeliveryToken } from './browser-delivery-CvBUoA96.js';
5
5
  import './types-C2vFipdU.js';
6
- import './index-CnnnYiGH.js';
6
+ import './index-Cs2O9Pmx.js';
7
7
  import 'zod';
8
8
  import './db.js';
9
9
  import 'kysely';
package/dist/tunnel.js CHANGED
@@ -1 +1 @@
1
- import{A as a,B as b,C as c,D as d,ha as e,ia as f,ja as g,ka as h,la as i,ma as j,na as k,oa as l}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{k as applyPermissionDecision,g as isAuthCredentialsBrowserDelivery,j as isByoOAuthBrowserDelivery,f as isConnectStatusBrowserDelivery,i as isManagedBrowserDelivery,h as isPermissionBrowserDelivery,l as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,e as verifyBrowserDeliveryToken};
1
+ import{A as a,B as b,C as c,D as d,da as e,ea as f,fa as g,ga as h,ha as i,ia as j,ja as k,ka as l}from"./chunk-PUAVA6PG.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{k as applyPermissionDecision,g as isAuthCredentialsBrowserDelivery,j as isByoOAuthBrowserDelivery,f as isConnectStatusBrowserDelivery,i as isManagedBrowserDelivery,h as isPermissionBrowserDelivery,l as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,e as verifyBrowserDeliveryToken};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.84",
3
+ "version": "0.1.87",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,38 +0,0 @@
1
- import{a as se,b as Xt,c as P,d as F,e as er,f as J,g as N,h as $,i as Xe,j as nr,k as Wn,l as tr,m as rr}from"./chunk-NZS35HPL.js";import{a as Qt}from"./chunk-IGGCNGU2.js";var en=["ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gitlab","gmail","googlecalendar","googledrive","googlesheets","grafana","hackernews","hubspot","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],or={ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",cursor:"Cursor",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledrive:"Google Drive",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",intercom:"Intercom",jira:"Jira",linear:"Linear",monday:"Monday",notion:"Notion",onedrive:"OneDrive",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",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"};function ye(e){let n=or[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var Ne="https://auth.corsair.dev";var me=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret, deliveryUrl } to createCorsair()."),this.name="HubNotConfiguredError"}};function nn(e){let n=(e.apiUrl?.trim()||Ne).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim(),i=e.deliveryUrl.trim();if(!t||!r||!i)throw new Error("Hub config requires non-empty projectApiKey, signingSecret, and deliveryUrl");return{apiUrl:n,projectApiKey:t,signingSecret:r,deliveryUrl:i,oauthCallbackUrl:e.oauthCallbackUrl?.trim()}}function wo(e){return e.apiUrl.trim().length>0&&e.deliveryUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function H(e){let n=P(e).hub;if(!n||!wo(n))throw new me;return n}function tn(e){return e.oauthCallbackUrl?e.oauthCallbackUrl:`${e.apiUrl.replace(/\/$/,"")}/oauth/callback`}function S(e){return typeof e=="string"&&e.length>0}function rn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!S(n.connectUrl)||!S(n.token)||!S(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};return S(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function on(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!S(n.approvalUrl)||!S(n.token)||!S(n.projectId)||!S(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 sn(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(!S(n.access_token))throw new Error("Hub token refresh returned no access_token");return{access_token:n.access_token,refresh_token:S(n.refresh_token)?n.refresh_token:void 0,expires_in:typeof n.expires_in=="number"?n.expires_in:void 0,scope:S(n.scope)?n.scope:void 0}}function ir(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!S(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 i=r;!S(i.plugin)||typeof i.connected!="boolean"||t.push({plugin:i.plugin,providerName:S(i.providerName)?i.providerName:i.plugin,authKind:i.authKind==="oauth"||i.authKind==="api_key"||i.authKind==="bot_token"?i.authKind:"api_key",connected:i.connected})}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}function Co(e){return e.replace(/\/$/,"")}async function To(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 Po(e,n,t){if(n===404&&t)return t;let r=an(e);return r||`Hub API returned HTTP ${n}`}async function xe(e){let n=Co(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.hub.projectApiKey}`},body:JSON.stringify(e.body)}),r=await To(t);if(!t.ok)throw new Error(Po(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import*as $e from"crypto";function z(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function jn(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 i=r;return n!==void 0&&typeof i.iat=="number"&&Date.now()-i.iat>n?null:i}return null}catch{return null}}function ae(e,n){let t=$e.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var Kn=600*1e3;function cn(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),i=e.slice(t+1),o=$e.createHmac("sha256",n).update(r).digest("base64url"),s=Buffer.from(i,"base64url"),a=Buffer.from(o,"base64url");return s.length!==a.length||!$e.timingSafeEqual(s,a)?null:jn(r,{maxAgeMs:Kn})}var vo=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Le(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:vo.has(n)}catch{return!1}}function Ae(e){return Le(e)?"client":"server"}function Zn(e,n){return e==="client"||Le(n)}var sr=Zn;function Re(e){if(!e.source)return null;let n=Le(e.deliveryUrl);return e.source==="server"&&n?{error:'source "server" cannot be used with a loopback delivery URL \u2014 omit source to auto-detect or use "client"',status:400}:e.oauthMode==="managed"&&e.source==="client"&&!n?{error:'managed OAuth with source "client" requires a loopback delivery URL \u2014 omit source for production server delivery',status:400}:null}import{ZodBoolean as Ao,ZodDate as Ro,ZodEnum as So,ZodNullable as Io,ZodNumber as Eo,ZodObject as _o,ZodOptional as Do,ZodRecord as Oo,ZodString as Mo,ZodType as Ho}from"zod";var xo={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:{}}},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:{}}}},qn=xo;async function cr(e,n){let t=[],r=g=>{t.push(g),console.log(g)},i=g=>{t.push(g),console.warn(g)},o=n?.caller??"script",s=Xt(e);if(!s)throw new Error("setupCorsair: invalid corsair instance");if(!s.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let a=Uo(e,s.plugins,n),c={...s,database:s.database},u=c.database.db;await $o(u,i);let d=await Lo(u,c,a.tenantId,a.provisionAccounts,r);n?.credentials&&Object.keys(n.credentials).length>0&&await Ko(e,a,n.credentials,c,r,i);let l=await qo(d,a,r,o);if(n?.backfill){r("[corsair:setup] Starting backfill...");let g=lr({plugins:s.plugins,database:u,kek:s.kek,multiTenancy:!0}).withTenant(a.tenantId);await Go(g,s.plugins,l,r,i),r("[corsair:setup] Backfill complete.")}return t.join(`
2
- `)}function Gn(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...N[n][t],...r])}function Bo(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let i=n.find(a=>a.id===t);if(!i)continue;let o=$(i);if(!o)continue;let s=Gn(i,o,"account");for(let a of Object.keys(r))if(s.has(a))return!0}return!1}function Uo(e,n,t){let r=er(e),i=t?.tenantId?.trim(),o=i!==void 0&&i.length>0;if(r&&t?.backfill&&!o)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(r&&Bo(t?.credentials,n)&&!o)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(o&&!i)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:r,tenantIdProvided:o,tenantId:o?i:"default",provisionAccounts:!r||o}}function ur(e,n){return se(e)?n===0?!0:Object.values(e).every(t=>ur(t,n-1)):!1}function Fo(e){return ur(e,4)}var No={...tr};function un(e){if(e instanceof _o){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Ho?un(r):"unknown";return n}return e instanceof Io?`${un(e.unwrap())} | null`:e instanceof Do?`${un(e.unwrap())} | undefined`:e instanceof So?e.options.join(" | "):e instanceof Mo?"string":e instanceof Eo?"number":e instanceof Ao?"boolean":e instanceof Ro?"date":e instanceof Oo?"jsonb":"unknown"}async function $o(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(i=>i.name));for(let[i,o]of Object.entries(No))r.has(i)||n(`[corsair:setup] Table "${i}" does not exist. Run your database migrations before calling setupCorsair.
3
- Schema: ${JSON.stringify(un(o),null,2)}`)}async function Lo(e,n,t,r,i){let o=new Date,s=new Map;for(let a of n.plugins){let c=a.id,u=$(a),d=await e.selectFrom("corsair_integrations").selectAll().where("name","=",c).executeTakeFirst();if(!d){let y=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:y,name:c,config:{},created_at:o,updated_at:o}).execute(),d=await e.selectFrom("corsair_integrations").selectAll().where("id","=",y).executeTakeFirst(),i(`[corsair:setup] Created integration: ${c}`)}let l=u?a.authConfig?.[u]?.integration??[]:[],g=u?a.authConfig?.[u]?.account??[]:[],f=u&&d?O({authType:u,integrationName:c,kek:n.kek,database:n.database,extraIntegrationFields:l}):void 0;if(d&&!d.dek&&f&&(await f.issue_new_dek(),i(`[corsair:setup] Issued integration DEK: ${c}`)),!d||!u||!f)continue;let p;if(r){let y=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",d.id).executeTakeFirst();if(!y){let m=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:m,tenant_id:t,integration_id:d.id,config:{},created_at:o,updated_at:o}).execute(),y=await e.selectFrom("corsair_accounts").selectAll().where("id","=",m).executeTakeFirst(),i(`[corsair:setup] Created account: ${c}`)}p=y&&I({authType:u,integrationName:c,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),y&&p&&!y.dek&&(await p.issue_new_dek(),i(`[corsair:setup] Issued account DEK: ${c}`))}s.set(c,{pluginId:c,authType:u,integration:f,account:p,integrationFields:[...N[u].integration,...l],accountFields:r?[...N[u].account,...g]:[]})}return s}function Wo(e){if(!se(e))return;let n=e.keys;return se(n)?n:void 0}function jo(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function Ko(e,n,t,r,i,o){let s=Wo(e),a=n.provisionAccounts?jo(e,n.tenantId):void 0;for(let[c,u]of Object.entries(t)){let d=r.plugins.find(h=>h.id===c);if(!d){o(`[corsair:setup] Unknown plugin '${c}' \u2014 skipping credentials.`);continue}let l=$(d);if(!l){o(`[corsair:setup] Plugin '${c}' has no auth type \u2014 skipping credentials.`);continue}let g=Gn(d,l,"integration"),f=Gn(d,l,"account"),p=s?.[c],y=a?.[c],m=se(y)?y.keys:void 0;for(let[h,C]of Object.entries(u))if(C){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 b=J(p,`set_${h}`);if(!b){o(`[corsair:setup] Cannot set integration field '${h}' for '${c}'.`);continue}await b(C),i(`[corsair:setup] Set ${c} integration.${h}`);continue}if(f.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 b=J(m,`set_${h}`);if(!b){o(`[corsair:setup] Cannot set account field '${h}' for '${c}'.`);continue}await b(C),i(`[corsair:setup] Set ${c} account.${h} (tenant=${n.tenantId})`);continue}o(`[corsair:setup] Unknown credential field '${h}' for plugin '${c}'.`)}}}var ar=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function Zo(e,n,t,r,i,o,s,a,c){let u=[],d=[];for(let g of i){if(ar.has(g))continue;let f=J(t,`get_${g}`);if(!f)continue;let p=null;try{let y=await f();p=typeof y=="string"?y:null}catch{}p||u.push(g)}if(r&&o.length>0)for(let g of o){if(ar.has(g))continue;let f=J(r,`get_${g}`);if(!f)continue;let p=null;try{let y=await f();p=typeof y=="string"?y:null}catch{}p||d.push(g)}let l=u.length===0&&d.length===0;if(l)a(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else{let g=[...u,...d];if(c==="cli"){let f=g.map(p=>`${p}=VALUE`).join(" ");a(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
- corsair setup --${e} ${f}`)}else{let f=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let p of u)f.push(` await corsair.keys.${e}.set_${p}(value)`);for(let p of d){let y=s.provisionAccounts?s.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(s.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;f.push(` await ${y}.keys.set_${p}(value)`)}a(f.join(`
5
- `))}}return l}async function qo(e,n,t,r){let i=new Set;for(let o of e.values())await Zo(o.pluginId,o.authType,o.integration,o.account,o.integrationFields,o.accountFields,n,t,r)&&i.add(o.pluginId);return i}async function Go(e,n,t,r,i){if(!Fo(qn)){i("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let o=qn,s=new Set(n.map(a=>a.id));for(let[a,c]of Object.entries(o)){if(!s.has(a))continue;if(!t.has(a)){r(`[corsair:setup] Skipping backfill for '${a}' \u2014 auth not configured.`);continue}let u=se(e)?e[a]:void 0,d=se(u)?u.api:void 0;if(d)for(let[l,g]of Object.entries(c))for(let[f,p]of Object.entries(g)){r(`[corsair:setup] Backfilling ${a} \u203A ${l}.${f}...`);try{let y=se(d)?d[l]:void 0;await J(y,f)?.(p)}catch(y){i(`[corsair:setup] ${a} \u203A ${l}.${f} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Se(e,n){if(!P(e).database)throw new Error("A database must be configured to provision Corsair for connect");await cr(e,{tenantId:n})}var Jo=new Set(["webhook_signature","expires_at","scope"]);function zo(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Vo(e){return e==="oauth_2"||e==="managed"?["access_token"]:e==="api_key"?["api_key"]:e==="bot_token"?["bot_token"]:[]}async function Yo(e,n,t,r){let i=Vo(t);if(i.length===0)return!0;let s=(typeof e.withTenant=="function"?e.withTenant(r):e)[n.id],a=s&&typeof s=="object"&&"keys"in s?s.keys:null;if(!a)return!1;for(let c of i){if((t==="oauth_2"||t==="managed")&&c==="refresh_token")continue;let u=J(a,`get_${c}`);if(!u)continue;let d=null;try{let l=await u();d=typeof l=="string"?l:null}catch{d=null}if(!d)return!1}return!0}function Qo(e,n){return e==="oauth_2"||e==="managed"?[]:n.filter(t=>!Jo.has(t))}async function dr(e,n,t={}){let r=P(e),i=H(e),o=tn(i),s=[],a=t.pluginIds?new Set(t.pluginIds):null;for(let c of r.plugins){if(a&&!a.has(c.id))continue;let u=$(c);if(!u)continue;let d=zo(u),l=t.providerNameOverrides?.[c.id]??ye(c.id),g=await Yo(e,c,u,n),f=Xe(c,u),p={plugin:c.id,providerName:l,authKind:d,alreadyConfigured:g};if(d==="oauth"){let m=t.oauthModeOverrides?.[c.id]??(u==="managed"?"managed":"byo");if(p.oauthMode=m,!t.skipOAuthUrlGeneration)if(m==="managed")p.state=ae(z(c.id,n),r.kek);else try{let h=await Jn(e,c.id,{tenantId:n,redirectUri:o});p.oauthUrl=h.url,p.state=h.state}catch(h){p.setupError=h instanceof Error?h.message:`Could not prepare OAuth for ${c.id}`}}else{let y=Qo(u,f);y.length>0&&(p.credentialFields=y)}s.push(p)}return s}function pr(e,n){let t=H(e);if(n){let r=Re({source:n,deliveryUrl:t.deliveryUrl});if(r)throw new Error(r.error);return n}return Ae(t.deliveryUrl)}async function gr(e,n){await Se(e,n)}async function ln(e,n){let t=H(e);await gr(e,n.tenantId);let r=n.plugin?[n.plugin]:void 0,i=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,o=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,s=await dr(e,n.tenantId,{pluginIds:r,oauthModeOverrides:i,providerNameOverrides:o});if(s.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");let a=pr(e,n.source);return xe({hub:t,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{tenantId:n.tenantId,deliveryUrl:t.deliveryUrl,source:a,plugins:s},parseResponse:rn})}import{createCipheriv as fr,createDecipheriv as yr,randomBytes as dn,scrypt as Xo}from"crypto";import{promisify as ei}from"util";var mr=ei(Xo),pn="aes-256-gcm",hr=12,gn=16,ni=16,We=32;function ee(){return dn(We).toString("base64")}async function ne(e,n){let t=dn(ni),r=await mr(n,t,We),i=dn(hr),o=fr(pn,r,i,{authTagLength:gn}),s=Buffer.concat([o.update(e,"utf8"),o.final()]),a=o.getAuthTag();return[t.toString("base64"),i.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function L(e,n){let[t,r,i,o]=e.split(":");if(!t||!r||!i||!o)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(i,"base64"),u=Buffer.from(o,"base64"),d=await mr(n,s,We),l=yr(pn,d,a,{authTagLength:gn});return l.setAuthTag(c),Buffer.concat([l.update(u),l.final()]).toString("utf8")}function zn(e,n){let t=Buffer.from(n,"base64"),r=dn(hr),i=fr(pn,t,r,{authTagLength:gn}),o=Buffer.concat([i.update(e,"utf8"),i.final()]),s=i.getAuthTag();return[r.toString("base64"),s.toString("base64"),o.toString("base64")].join(":")}function je(e,n){let[t,r,i]=e.split(":");if(!t||!r||!i)throw new Error("Invalid encrypted data format");let o=Buffer.from(n,"base64"),s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(i,"base64"),u=yr(pn,o,s,{authTagLength:gn});return u.setAuthTag(a),Buffer.concat([u.update(c),u.final()]).toString("utf8")}function ce(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=zn(i,n);return t}function te(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=je(i,n);return t}function Ke(e,n,t){let r=te(e,n);return ce(r,t)}function kr(e,n,t){let r={};for(let i of t)r[`get_${i}`]=async()=>(await e())[i]??null,r[`set_${i}`]=async o=>{let s=[null,void 0,""].includes(o)?null:o;await n({[i]:s})};return r}var Vn=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function O(e){let{authType:n,integrationName:t,kek:r,database:i,extraIntegrationFields:o=[]}=e,s=[...N[n].integration,...o],a=null,c={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let p=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!p)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:p.id,config:Vn(p.config),dek:p.dek??null},a},updateIntegration:async p=>{let y=await c.getIntegration();await i.db.updateTable("corsair_integrations").set({...p.config!==void 0?{config:p.config}:{},...p.dek!==void 0?{dek:p.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),a=null}},u=null,d=async()=>{if(u)return u;let p=await c.getIntegration();if(!p.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return u=await L(p.dek,r),u},l=async()=>{let p=await c.getIntegration(),y=await d(),m=p.config;return!m||Object.keys(m).length===0?{}:te(m,y)};return{get_dek:d,issue_new_dek:async()=>{let p=await c.getIntegration(),y=ee(),m={};if(p.dek){let C=await L(p.dek,r),b=p.config;b&&Object.keys(b).length>0&&(m=Ke(b,C,y))}let h=await ne(y,r);return await c.updateIntegration({config:m,dek:h}),u=y,y},...kr(l,async p=>{let y=await d(),m;try{m=await l()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,b),m={}}let h={...m};for(let[b,k]of Object.entries(p))k===null?delete h[b]:h[b]=k;let C=ce(h,y);await c.updateIntegration({config:C})},s)}}function I(e){let{authType:n,integrationName:t,tenantId:r,kek:i,database:o,extraAccountFields:s=[]}=e,a=[...N[n].account,...s],c=null,u=null,d=async()=>{if(u)return u;let k=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!k)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return u={id:k.id,config:Vn(k.config),dek:k.dek??null},u},l={kek:i,integrationName:t,tenantId:r,getIntegration:d,getAccount:async()=>{if(c)return c;let k=await d(),w=await o.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",k.id).executeTakeFirst();if(!w)throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`);return c={id:w.id,config:Vn(w.config),dek:w.dek??null},c},updateAccount:async k=>{let w=await l.getAccount();await o.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","=",w.id).execute(),c=null}},g=null,f=null,p=async()=>{if(g)return g;let k=await l.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return g=await L(k.dek,i),g},y=async()=>{if(f)return f;let k=await l.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return f=await L(k.dek,i),f},m=async()=>{let k=await l.getAccount(),w=await p(),T=k.config;return!T||Object.keys(T).length===0?{}:te(T,w)},h=async()=>{let k=await l.getIntegration(),w=await y(),T=k.config;return!T||Object.keys(T).length===0?{}:te(T,w)},b={get_dek:p,issue_new_dek:async()=>{let k=await l.getAccount(),w=ee(),T={};if(k.dek){let _=await L(k.dek,i),D=k.config;D&&Object.keys(D).length>0&&(T=Ke(D,_,w))}let E=await ne(w,i);return await l.updateAccount({config:T,dek:E}),g=w,w},...kr(m,async k=>{let w=await p(),T;try{T=await m()}catch(D){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,D),T={}}let E={...T};for(let[D,x]of Object.entries(k))x===null?delete E[D]:E[D]=x;let _=ce(E,w);await l.updateAccount({config:_})},a)};return n==="oauth_2"&&(b.get_integration_credentials=async()=>{let k=await h();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),b}async function br(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 i=ee(),o=await ne(i,t);return await e.db.updateTable("corsair_integrations").set({dek:o,updated_at:new Date}).where("id","=",r.id).execute(),i}async function wr(e,n,t,r){let i=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!i)throw new Error(`Integration "${n}" not found.`);let o=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",i.id).executeTakeFirst();if(!o)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let s=ee(),a=await ne(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",o.id).execute(),s}function Ie(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}import*as Cr from"querystring";function Ee(e){let{oauthConfig:n,clientId:t,redirectUri:r,state:i}=e,o={...n.authParams,client_id:t,redirect_uri:r,response_type:"code",scope:n.scopes.join(" "),state:i};return`${n.authUrl}?${Cr.stringify(o)}`}var W=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function ti(e){let n=e.oauthConfig;if(!n)throw new W("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Yn(e,n){let t=P(e,()=>new W("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new W("no_database","No database configured on corsair instance");let r=t.manual?.redirectUri;if(!r)throw new W("no_redirect_uri","No redirectUri configured. Set manual.redirectUri in createCorsair().");let i=cn(n,t.kek);if(!i)throw new W("invalid_state","Invalid or tampered state parameter");let{plugin:o,tenantId:s}=i,a=F(t,o,g=>new W("plugin_not_found",g)),c=ti(a),d=await O({authType:"oauth_2",integrationName:o,kek:t.kek,database:t.database}).get_client_id();if(!d)throw new W("client_id_not_configured",`client_id not configured for '${o}'`);let l=Ee({oauthConfig:c,clientId:d,redirectUri:r,state:n});return{plugin:o,tenantId:s,providerName:c.providerName,oauthUrl:l,state:n}}import{randomBytes as oi}from"crypto";import{v4 as ii}from"uuid";async function fn(e,n){return xe({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:{permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,deliveryUrl:e.deliveryUrl,expiresAt:n.expiresAt},parseResponse:on})}function yn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var Qn="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 et(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function Tr(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Xn(e){return yn(e)}async function nt(e,n){if(et(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?Tr(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await fn(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:ri(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function ri(e){try{return JSON.parse(e)}catch{return e}}async function mn(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await nt(e,n);return{...n,approvalUrl:r}}async function tt(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:i,permissionToken:o,plugin:s,endpoint:a,args:c,tenantId:u,expiresAt:d,operationPath:l}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:o,id:i,plugin:s,endpoint:a,args:c});let f=await nt({manual:t,hub:r},{id:i,token:o,plugin:s,endpoint:a,args:JSON.stringify(c),tenant_id:u,expires_at:d});return et(t)?f?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:f}):Xn(f):Qn:r?f?Xn(f):`Action '${l}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Qn}var si={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 ai(e,n,t){return t!==void 0?t:si[n][e]}function rt(e){let n=/(\d+)(d|h|m|s)/g,t=0,r;for(;(r=n.exec(e))!==null;){let i=parseInt(r[1],10);switch(r[2]){case"d":t+=i*864e5;break;case"h":t+=i*36e5;break;case"m":t+=i*6e4;break;case"s":t+=i*1e3;break}}return t>0?t:600*1e3}function vr(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 Pr(e,n,t){let r=Date.now()+t;for(;Date.now()<r;){let i=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!i)return{result:"blocked",reason:"pending"};if(i.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(i.status==="denied")return{result:"blocked",reason:"denied"};if(i.status==="expired"||i.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(o=>setTimeout(o,500))}return{result:"blocked",reason:"timeout"}}async function xr(e){let n=ai(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}'.`,`
6
- Action: ${r}`,`
7
- To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let i=JSON.stringify(e.args),o=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","=",i).where("tenant_id","=",s).where("expires_at",">",o).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(a){if(a.status==="approved"){let p=e.db,y=a.id;return{result:"allow",onComplete:async()=>{await p.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",y).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
8
- Action: ${r}`,`
9
- Permission ID: ${a.id}`,`
10
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Pr(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:a.id,token:a.token,expiresAt:a.expires_at})}let c=ii(),u=oi(32).toString("hex"),d=e.timeoutMs??600*1e3,l=new Date(Date.now()+d).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:c,created_at:new Date,updated_at:new Date,token:u,plugin:e.pluginId,endpoint:e.endpointPath,args:i,tenant_id:s,status:"pending",expires_at:l}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
11
- Action: ${r}`,`
12
- Permission ID: ${c}`,`
13
- Permission token: ${u}`,`
14
- Expires at: ${l}`,`
15
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Pr(e.db,c,d):{result:"blocked",reason:"pending",id:c,token:u,expiresAt:l}}var v=class extends Error{status;code;extra;constructor(n,t,r,i={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=i}};function A(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function Ar(e){let n={error:e.code,message:e.message,...e.extra};return A(e.status,n)}function ue(e){return new v(404,"not_found",e)}function V(e,n={}){return new v(400,"bad_request",e,n)}function Rr(e,n){return F(e,n,t=>ue(t))}async function ot(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=O({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),i=N[t].integration,o=r,s;try{s=await Promise.all(i.map(u=>o[`get_${u}`]()))}catch{s=i.map(()=>null)}let a=i.filter((u,d)=>s[d]==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 Sr(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await ot(e,n);return{id:e.id,authType:t,configured:i,missingFields:o,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function hn(){return{ok:!0}}async function kn(e){return Promise.all(e.plugins.map(n=>Sr(n,e)))}async function bn(e,n){let t=Rr(e,n);return Sr(t,e)}async function Ir(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 Er(e,n){let t=await Ir(e,n),r=t.filter(i=>i.hasCredentials).map(i=>i.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function wn(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 i=r.tenant_id;if(!i)continue;let o=n.get(i);o||(o={id:i,accounts:[],connectedPlugins:[]},n.set(i,o));let s=!!r.dek;o.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&o.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function Cn(e,n){if(!n)throw V("Tenant id must be a non-empty string");return Er(e,n)}async function Tn(e,n){let t=n?.id?.trim();if(!t)throw V("Tenant id is required",{missingFields:["id"]});return Er(e,t)}async function _e(e,n){let t=n?.trim()||"default",r={},i=e.database?await Ir(e,t):[],o=new Map(i.map(s=>[s.integrationName,s]));for(let s of e.plugins){if(!(await ot(s,e)).configured){r[s.id]="missing_credentials";continue}let c=o.get(s.id),u;c&&c.hasCredentials?u="connected":u="not_connected",r[s.id]=u}return r}async function it(e,n){if(!e.database)throw ue(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ue(`Permission '${n}' not found`);return mn(e,t)}function ci(e){if(!e.oauthConfig)throw V(`Plugin '${e.id}' has no oauthConfig`)}function ui(e){if(!e.manual)throw new v(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function st(e){let n=ui(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new v(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 li(e){let n=!!e.hub,t=Ie(e.manual);if(!n&&!t)throw new v(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function _r(e){if(!e.database||!e.kek)throw new v(500,"database_not_configured","A database and kek are required to issue connect links.")}async function di(e,n){let t=n?.plugin?.trim();if(!t)throw V("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=Rr(e,t);ci(i);let o=st(e);_r(e);let s=await ot(i,e);if(!s.configured)throw new v(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:s.missingFields});let a=ae(z(t,r),e.kek),c;try{c=new URL(o.baseUrl)}catch{throw new v(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()+Kn).toISOString()}}async function pi(e,n,t){_r(n);let r=t.tenantId?.trim()||"default",i=H(e);if(t.source){let u=Re({source:t.source,deliveryUrl:i.deliveryUrl,oauthMode:t.oauthMode});if(u)throw V(u.error)}let o={tenantId:r,source:t.source??Ae(i.deliveryUrl),oauthMode:t.oauthMode},s=t.plugin?.trim();s&&(o.plugin=s);let a=t.providerName?.trim();a&&(o.providerName=a);let c=await ln(e,o);return{connectUrl:c.connectUrl,expiresAt:c.expiresAt}}async function Pn(e,n,t){return li(n),n.hub?pi(e,n,t):di(n,t)}async function vn(e,n,t){if(n.hub&&!Ie(n.manual))throw new v(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw V("state is required",{missingFields:["state"]});st(n);try{return await Yn(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw V("Invalid or expired state");case"client_id_not_configured":throw new v(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new v(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function xn(e,n,t){if(n.hub&&!Ie(n.manual))throw new v(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),i=t?.state?.trim(),o=[];if(r||o.push("code"),i||o.push("state"),o.length)throw V("Missing required fields",{missingFields:o});let s=st(n),{processOAuthCallback:a}=await import("./oauth.js");try{return await a(e,{code:r,state:i,redirectUri:s.redirectUri})}catch(c){if(c instanceof Error&&c.name==="OAuthCallbackError")switch(c.code){case"invalid_state":throw V("Invalid or expired state");case"credentials_not_configured":throw new v(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new v(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function at(e,n){if(!e.database)throw ue("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ue("Permission not found");return mn(e,t)}async function Dr(e,n){return"id"in n?it(e,n.id):at(e,n.token)}function gi(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function fi(e,n){return n&&!n.has(e.id)?!1:$(e)!==null}async function De(e,n,t={}){let r=P(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,s=await _e(r,i),a=r.plugins.filter(c=>fi(c,o)).map(c=>{let u=$(c),d=s[c.id]??"not_connected";return{plugin:c.id,providerName:ye(c.id),authKind:gi(u),connected:d==="connected"}});return{tenantId:i,plugins:a}}var le=6e4,he=3e5;var Y=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function An(e,n){let t=P(e,()=>new Y("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Y("no_database","Database not configured");let r=F(t,n.plugin,d=>new Y("plugin_not_found",d)),i=$(r);if(!i)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new Y("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Se(e,n.tenantId);let o=new Set(Xe(r,i)),a=r.authConfig?.[i]?.account??[],c=I({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a}),u=0;for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!o.has(d))throw new Y("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let g=J(c,`set_${d}`);if(!g)throw new Y("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await g(l.trim()),u+=1}if(u===0)throw new Y("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var Rn=new Map;function yi(e){for(let[n,t]of Rn)t<=e&&Rn.delete(n)}function Sn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return yi(r),Rn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(Rn.set(t,r+n),{ok:!0})}async function In(e,n,t){for(let r of e){if(r.id!==n)continue;let i=r.oauthWebhookTenantLinkResolver;return i?i(t):null}return null}var Or=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function mi(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 hi(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 L(n.dek,e.kek),r=Or(n.config),i={};Object.keys(r).length>0&&(i=te(r,t)),i[e.link.linkType]=e.link.externalId;let o=ce(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function Oe(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await mi({database:n,pluginId:r,tenantId:i}),u=!1;if(s){let d=I({authType:s,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:a}),l=`set_${o.linkType}`,g=d[l];typeof g=="function"&&(await g(o.externalId),u=!0)}u||await hi({database:n,kek:t,accountId:c,link:o})}async function ct(e){let{database:n,kek:t,pluginId:r,linkType:i,externalId:o}=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 L(a.dek,t),d=Or(a.config)[i];if(!d)continue;if(je(d,c)===o)return a}catch{continue}return null}async function En(e){return(await ct(e))?.tenant_id??null}async function Mr(e){return En({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var de=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Me(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:s,scope:a}=n;if(!i.trim())throw new de("no_access_token","Managed OAuth delivery missing access_token");let c=P(e,()=>new de("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new de("no_database","No database configured on corsair instance");let u=F(c,t,l=>new de("plugin_not_found",l));await Se(e,r);let d=I({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await d.set_access_token(i),o&&await d.set_refresh_token(o),s&&await d.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await d.set_scope(a);try{let l=await In(c.plugins,t,{access_token:i,refresh_token:o,scope:a});if(l)try{let g=u.authConfig?.managed?.account??[];await Oe({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:l,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(l){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,l)}return{plugin:t,tenantId:r}}function ki(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Hr(e,n,t=[]){for(let[r,i]of Object.entries(e))if(ki(i)){if(i.match(n))return{webhook:i,path:[...t,r]}}else if(i&&typeof i=="object"){let o=Hr(i,n,[...t,r]);if(o)return o}return null}function bi(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function wi(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 Br(e,n,t,r){let i=bi(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=wi(i)||o);let a={headers:i,body:o,...r?{query:r}:{}},c=r?.tenantId||"default",u=e.withTenant?e.withTenant(c):e,d=en;for(let l of d){let g=u[l];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(a))continue;let f=Hr(g.webhooks,a);if(!f)continue;let p=f.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let m=await f.webhook.handler(y),h=!!Object.keys(m.returnToSender||{})?.length;return{plugin:l,action:p,body:o,response:h?{...m?.returnToSender,success:!0}:{success:!0},...m.responseHeaders&&{responseHeaders:m.responseHeaders}}}catch(m){return console.error(`Error executing webhook handler for ${l}.${p}:`,m),{plugin:l,action:p,body:o,response:{success:!1,error:m instanceof Error?m.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{createHmac as ut,randomUUID as Ci,timingSafeEqual as Ur}from"crypto";function Fr(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function _n(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=ut("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":Ci()}}}function lt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Fr(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>3e5)return!1;let o=ut("sha256",n).update(e.body).digest("hex");try{return Ur(Buffer.from(o,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function He(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Fr(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)>3e5)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let o=ut("sha256",n).update(e.body).digest("hex");try{if(!Ur(Buffer.from(o,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function dt(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function pt(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function gt(e){return e.status===0?`Could not reach delivery URL (${e.deliveryUrl}): ${e.ack.error??e.body}`:e.ack.error??e.body??`HTTP ${e.status}`}async function ft(e){let{body:n,headers:t}=_n(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),i=await r.text();return{ok:r.ok,status:r.status,body:i}}catch(r){return{ok:!1,status:0,body:r instanceof Error?r.message:"Delivery request failed"}}}import{randomBytes as xi}from"crypto";import{createHmac as Ti,randomBytes as Pi,timingSafeEqual as vi}from"crypto";function re(){return Pi(16).toString("base64url")}function Ze(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Ti("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[i,o]=r;if(!i||!o)return null;let s=Ze(i,t);try{if(!vi(Buffer.from(o,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(i,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function Dn(e,n,t){let r=Math.floor(Date.now()/1e3),i={...e,iat:r,exp:t},o=Buffer.from(JSON.stringify(i)).toString("base64url"),s=Ze(o,n);return`${o}.${s}`}function qe(e,n,t){let r=Math.floor(Date.now()/1e3);return Dn(e,n,r+Math.floor(t/1e3))}function ke(e){return decodeURIComponent(e)}function yt(e){return encodeURIComponent(e)}function Nr(e){let n=e.trim();return n.length>0?n:null}function On(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Mn(e,n){if(!Nr(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??xi(16).toString("base64url"),iat:t,exp:t+Math.floor(6e4/1e3)},i=Buffer.from(JSON.stringify(r)).toString("base64url"),o=Ze(i,n);return`${i}.${o}`}function pe(e,n){return Nr(n)?Q(e,n):null}function be(e){return e.deliveryMode==="connect.status"}function we(e){return e.deliveryMode==="auth.credentials"}function Ge(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function Je(e){return e.deliveryMode==="oauth.tokens"}function Hn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!be(e)&&!we(e)&&!Ge(e)&&!Je(e)}function mt(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 Ai(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 En({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function Ri(e,n,t){let r=await Ai(e,n,t),i={...t.query??{},...r?{tenantId:r}:{}},o=await Br(e,t.headers,t.body,i);if(!o.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(o.response&&o.response.success===!1)return{status:"failed",retryable:!1,error:typeof o.response.error=="string"?o.response.error:"Webhook handler failed"};let s=o.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(o.response?.data??o.response);return{status:"ok",webhookResponse:{status:o.response?.statusCode??200,body:a,headers:o.responseHeaders}}}async function Si(e,n){return await ze(e,n),{status:"ok"}}async function Ii(e,n){return await Me(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function kt(e,n,t){let r=await ht(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function ht(e,n,t){let r=P(e),i=n.token?.trim();if(!i)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let o=new Date().toISOString(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",i).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<o?(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 Ei(e,n){try{return await An(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function _i(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await De(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function bt(e,n,t={}){let r=P(e),i=mt(n.headers,"x-corsair-signature"),o=mt(n.headers,"x-corsair-timestamp"),s=mt(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let c=He({body:n.body,signatureHeader:i,timestampHeader:o,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 u=Sn(`nonce:${s.trim()}`,3e5);if(!u.ok)return{status:"failed",retryable:!1,error:u.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"}}switch(a.type){case"webhook":return Ri(e,r,a.payload);case"oauth.callback":return Si(e,a.payload);case"oauth.tokens":return Ii(e,a.payload);case"permission.approve":return ht(e,a.payload,"approved");case"permission.deny":return ht(e,a.payload,"denied");case"auth.credentials":return Ei(e,a.payload);case"connect.status":return _i(e,a.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${a.type}`}}}var Di="corsair:client-bridge";function $r(e){let n=JSON.stringify({type:Di,requestId:e.requestId,ok:e.ok,body:e.body??null,error:e.error??null}),t=JSON.stringify(e.hubOrigin);return`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><script>
16
- (function () {
17
- var message = ${n};
18
- var targetOrigin = ${t};
19
- if (window.parent && window.parent !== window) {
20
- window.parent.postMessage(message, targetOrigin);
21
- }
22
- })();
23
- </script></body></html>`}var Oi=[".corsair.dev"];function Mi(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function Hi(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Mi(n)?!0:Oi.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Lr(e){return!e||!Hi(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 Wr(e,n){if(!n)return e;let t=new Headers(e.headers);for(let[r,i]of Object.entries(n))t.set(r,i);return new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function Bn(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 wt(e,n){let t=H(e),i=new URL(n).searchParams.get("d");if(!i)return{type:"json",status:200,body:{status:"ok",message:"Corsair tunnel endpoint is active",timestamp:new Date().toISOString()}};let o=pe(i,t.signingSecret);if(!o)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let s=Sn(`browser:${o.jti}`,6e4);if(!s.ok)return{type:"json",status:400,body:{error:s.error}};try{if(be(o)){if(!o.hubSuccessUrl)return{type:"json",status:400,body:{error:"Connect status delivery missing hubSuccessUrl"}};let a=o.tenantId?.trim()||"default",c=await De(e,a,{pluginIds:o.statusPlugins});return{type:"redirect",url:Bn(o.hubSuccessUrl,{status:c})}}if(we(o))return o.hubSuccessUrl?o.credentials?(await An(e,{plugin:o.plugin,tenantId:o.tenantId,credentials:o.credentials}),{type:"redirect",url:Bn(o.hubSuccessUrl,{connectedPlugin:o.plugin})}):{type:"redirect",url:Bn(o.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(Ge(o)){if(!o.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await kt(e,o.permissionToken,o.deliveryMode==="permission.approve"?"approved":"denied")}else if(Je(o)){if(!o.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Me(e,{plugin:o.plugin,tenantId:o.tenantId,accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.expiresIn,scope:o.scope})}else{if(!Hn(o)||!o.code||!o.state||!o.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await ze(e,{code:o.code,state:o.state,redirectUri:o.redirectUri})}}catch(a){let c=a instanceof Error?a.message:"Hub delivery failed";return(be(o)||we(o))&&o.hubSuccessUrl?{type:"redirect",url:Bn(o.hubSuccessUrl,{error:c})}:(be(o)||we(o))&&o.hubOrigin&&o.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:$r({hubOrigin:o.hubOrigin,requestId:o.requestId,ok:!1,error:c})}:{type:"json",status:400,body:{error:c}}}return{type:"redirect",url:o.hubSuccessUrl}}async function Ct(e,n){let t=H(e),r=await bt(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 i=r.webhookResponse;if(!i)return{type:"json",status:200,body:{status:"ok"}};let o=i.status??200,s=i.headers;return i.body&&typeof i.body=="object"&&!(i.body instanceof ArrayBuffer)?{type:"json",status:o,body:i.body,headers:s}:{type:"text",status:o,body:typeof i.body=="string"?i.body:i.body?JSON.stringify(i.body):null,headers:s}}function Tt(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 Pt(e,n){return n.method==="GET"?wt(e,n.url):Ct(e,{headers:n.headers,body:n.body??""})}async function vt(e,n){try{let t=await Pt(e,n);return Tt(t)}catch(t){if(t instanceof me)return Response.json({error:t.message},{status:503});throw t}}async function Ve(e,n){let t=n.method.toUpperCase(),r=Lr(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 i=await vt(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return Wr(i,r)}var oe=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 Bi=300;async function xt(e,n){let{keys:t,hub:r,plugin:i,tenantId:o}=e,s=n?.forceRefresh??!1,[a,c,u]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!a&&!u)throw new oe(i,"managed");let d=Math.floor(Date.now()/1e3);if(!s&&a&&c&&Number(c)>d+Bi)return{accessToken:a,expiresAt:Number(c),refreshed:!1};if(!u&&a&&!s)return{accessToken:a,expiresAt:c?Number(c):d+3600,refreshed:!1};let l=await xe({hub:r,path:"/oauth/refresh",body:{plugin:i,tenantId:o},parseResponse:sn}),g=l.expires_in?d+l.expires_in:c?Number(c):d+3600;return await t.set_access_token(l.access_token),await t.set_expires_at(String(g)),l.refresh_token&&await t.set_refresh_token(l.refresh_token),l.scope&&await t.set_scope(l.scope),{accessToken:l.access_token,expiresAt:g,refreshed:!0}}async function jr(e,n){e._refreshAuth=async()=>(await xt(n,{forceRefresh:!0})).accessToken}function Kr(e){return{delivery:n=>Ve(e,n),deliveryOptions:n=>Ve(e,n)}}var Zr=1200*1e3;function At(){return re()}function Rt(){return Zr}function St(e,n){return qe(e,n,Zr)}function It(e,n){return Q(e,n)}function Et(e){return ke(e)}var qr=600*1e3;function _t(){return re()}function Dt(){return qr}function Ot(e,n){return qe(e,n,qr)}function Mt(e,n){return Q(e,n)}function Ht(e){return yt(e)}function Bt(e){return ke(e)}function Ut(){return re()}function Ft(e,n,t){return Dn(e,n,Math.floor(t.getTime()/1e3))}function Nt(e,n){return Q(e,n)}function $t(e){return ke(e)}function Un(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(i,o){let s=t.length>1;throw new Error(`corsair.keys.${String(o)}: 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 ${We}`)}})}var Ui=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Gr(e,n,t,r,i){let o={pluginId:n,operation:t,input:r,originalError:e},s=Object.keys(i).find(u=>i[u]?.match(e,o));return await(i[s||"DEFAULT"]?.handler||Ui)(e,o)}function Fi(e){return typeof e=="function"}function Ni(e,n,t){let r=ae(z(e,n.tenantId??t??"default"),n.kek),i=new URL(n.baseUrl);i.searchParams.set("state",r);let o=i.toString(),s=n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:o,state:r}):`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${o}`;return new Error(s)}function Lt({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:i,errorHandlers:o,currentPath:s=[],keyBuilder:a,permissionsConfig:c,endpointMeta:u,database:d,permissionsOptions:l,tenantId:g,manualConfig:f,hubConfig:p}){for(let[y,m]of Object.entries(e)){let h=n?.[y];if(Fi(m)){let C=h,b=[...s,y].join("."),k=async(w={})=>{let T;if(c){let R=u?.[b],{result:ve,reason:q,onComplete:Fe,token:X,id:fe,expiresAt:U}=await xr({pluginId:i,endpointPath:b,args:w,mode:c.mode,override:c.overrides?.[b],riskLevel:R?.riskLevel??"write",meta:R,db:d,timeoutMs:l?rt(l.timeout):void 0,tenantId:g,approvalMode:l?.mode});if(ve==="blocked"){let G;throw q==="denied"?G=`Action '${b}' was denied by the user. Await further instructions before proceeding.`:q==="policy"?G=`Action '${b}' is blocked by the permission policy. Update the corsair config to allow it.`:q==="timeout"?G=`Action '${b}' timed out waiting for approval.`:X&&fe?G=await tt({permissionsOptions:l,manual:f,hub:p,permissionId:fe,permissionToken:X,plugin:i,endpoint:b,args:w,tenantId:g??"default",expiresAt:U??new Date(Date.now()+(l?rt(l.timeout):600*1e3)).toISOString(),operationPath:b}):G=`Action '${b}' requires user approval before it can run.`,new Error(G)}T=Fe}let E=async(R,ve,q)=>{try{return await m(ve,q)}catch(Fe){if(Fe instanceof Error){let X=await Gr(Fe,i,b,typeof q=="object"&&q!==null?q:{args:q},o);if(R<(X.maxRetries||0)){let fe=R+1;console.log(`Retrying (${fe} / ${X.maxRetries})...`);let U;if(X.headersRetryAfterMs)U=X.headersRetryAfterMs;else switch(X.retryStrategy){case"exponential_backoff":U=Math.pow(2,fe-1)*1e3;break;case"exponential_backoff_jitter":let G=Math.pow(2,fe-1)*1e3,bo=(Math.random()-.5)*1e3;U=Math.max(0,G+bo);break;case"linear_1s":U=1e3;break;case"linear_2s":U=2e3;break;case"linear_3s":U=3e3;break;case"linear_4s":U=4e3;break;default:U=1e3;break}await new Promise(G=>setTimeout(G,U)),await E(fe,ve,q),console.log(`[corsair:${i}:${b}] Retry strategy:`,X)}}throw Fe}},_;try{_=a?await a(t,"endpoint"):void 0}catch(R){throw f&&Ie(f)&&f.oauthConfig&&f.kek&&R instanceof oe&&R.authType==="oauth_2"?Ni(i,f,g):R}if(!C?.before&&!C?.after){let R=await E(0,{...t,key:_},w);return await T?.(),R}let D={...t,key:_},x=C.before?await C.before(D,w):{ctx:D,args:w,continue:!0,passToAfter:void 0};if(x.continue===!1)return;let Pe=await E(0,x.ctx,x.args);return await C.after?.(x.ctx,Pe,x.passToAfter),await T?.(),Pe};r[y]=k}else if(m&&typeof m=="object"){let C={};Lt({endpoints:m,hooks:h,ctx:t,tree:C,pluginId:i,errorHandlers:o,currentPath:[...s,y],keyBuilder:a,permissionsConfig:c,endpointMeta:u,database:d,permissionsOptions:l,tenantId:g,manualConfig:f,hubConfig:p}),r[y]=C}}}function $i(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Wt({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:i}){for(let[o,s]of Object.entries(e)){let a=n?.[o];if($i(s)){let c=a,u=async d=>{let l=(f,p)=>s.handler(f,p),g=i?await i(t,"webhook"):void 0;return!c?.before&&!c?.after?l({...t,key:g},d):(async()=>{let f={...t,key:g},p=c.before?await c.before(f,d):{ctx:f,args:d,continue:!0,passToAfter:void 0};if(p.continue===!1)return;let y=await l(p.ctx,p.args);return y?.success===!0&&await c.after?.(p.ctx,y,p.passToAfter),y})()};r[o]={match:s.match,handler:u}}else if(s&&typeof s=="object"){let c={};Wt({webhooks:s,hooks:a,ctx:t,webhooksTree:c,keyBuilder:i}),r[o]=c}}}function Li(e,n,t){let r=null;return async()=>{if(r)return r;if(!e)throw new Error("Database not configured");let i=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!i)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);let o=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",i.id).executeTakeFirst();if(!o)throw new Error(`Account not found for tenant "${t}" and integration "${n}". Make sure to create the account first.`);return r=o.id,r}}function Wi(e,n,t,r,i){return e?Wn(e.db,n,t,r,i):{findByEntityId: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 jt(e,n){let{database:t,tenantId:r,kek:i,rootErrorHandlers:o,permissionsOptions:s,manualConfig:a,hubConfig:c}=n,u={},d={};for(let l of e)u[l.id]={},d[l.id]={};for(let l of e){let g=l.schema,f=r??"default",p=Li(t,l.id,f);if(g?.entities){let x={};for(let[Pe,R]of Object.entries(g.entities)){let ve=t?Wn(t.db,p,Pe,g.version,R):Wi(void 0,p,Pe,g.version,R);x[Pe]=ve}d[l.id].db=x,u[l.id].db=x}let y=l.options,m=l.authConfig,h;if(t&&i&&y?.authType){let x=m?.[y.authType]?.account??[];h=I({authType:y.authType,integrationName:l.id,tenantId:f,kek:i,database:t,extraAccountFields:x}),u[l.id].keys=h}let C={database:t,db:d[l.id]?.db??{},$getAccountId:p,...l.options?{options:l.options}:{},...h?{keys:h,authType:y?.authType}:{},tenantId:f,...c?{hub:c}:{}},b=l.endpoints??{},k=l.hooks,w={...o,...l.errorHandlers},T={},E=l.options?.permissions;Lt({endpoints:b,hooks:k,ctx:C,tree:T,pluginId:l.id,errorHandlers:w,currentPath:[],keyBuilder:l.keyBuilder,permissionsConfig:E,endpointMeta:l.endpointMeta,database:t,permissionsOptions:s,tenantId:r,manualConfig:a?{...a,oauthConfig:l.oauthConfig,kek:i,tenantId:f}:void 0,hubConfig:c}),Object.keys(T).length>0&&(u[l.id].api=T),C.endpoints=T;let _=l.webhooks??{},D=l.webhookHooks;if(Object.keys(_).length>0){let x={};Wt({webhooks:_,hooks:D,ctx:C,webhooksTree:x,keyBuilder:l.keyBuilder}),u[l.id].webhooks=x,l.pluginWebhookMatcher&&(u[l.id].pluginWebhookMatcher=l.pluginWebhookMatcher),l.pluginTenantWebhookMatcher&&(u[l.id].pluginTenantWebhookMatcher=l.pluginTenantWebhookMatcher)}}return u}function Jr(e,n,t){let r={};for(let i of e){let o=i.options,s=i.authConfig;if(o?.authType){let a=s?.[o.authType]?.integration??[],c=O({authType:o.authType,integrationName:i.id,kek:t,database:n,extraIntegrationFields:a});r[i.id]=c}}return r}var ji="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function zr(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] ${ji}`),t):n}var Vr=[{method:"GET",pattern:"/ok",handler:async()=>A(200,hn())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>A(200,await wn(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>A(201,await Tn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>A(200,await Cn(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>A(200,await kn(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>A(200,await bn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>A(200,await _e(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>A(200,await it(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?A(200,await at(e,t)):A(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>A(200,await Pn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>A(200,await vn(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>A(200,await xn(e,n,t))}];(()=>{let e=new Set;for(let n of Vr){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function Ki(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let i={};for(let o=0;o<t.length;o++){let s=t[o],a=r[o];if(s.startsWith(":"))i[s.slice(1)]=decodeURIComponent(a);else if(s!==a)return null}return i}function Zi(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 qi(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 v(400,"invalid_json","Request body is not valid JSON")}}var Gi="/api/corsair";function Ce(e,n={}){let t=n.basePath??Gi,r=P(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async i=>{try{let o=new URL(i.url),s=Zi(o.pathname,t),a=i.method.toUpperCase(),c=Object.fromEntries(o.searchParams);for(let u of Vr){if(u.method!==a)continue;let d=Ki(u.pattern,s);if(!d)continue;let l=await qi(i);return await u.handler({corsair:e,internal:r,req:i,params:d,query:c,body:l})}throw ue(`No route for ${a} ${s}`)}catch(o){if(n.onError){let a=await n.onError(o,i);if(a)return a}if(o instanceof v)return Ar(o);let s=o instanceof Error?o.message:"Internal server error";return A(500,{error:"internal_error",message:s})}}}function Ji(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,i=`${t}://${n}${r}`,o=new Headers;for(let[c,u]of Object.entries(e.headers))if(u!=null)if(Array.isArray(u))for(let d of u)o.append(c,d);else o.set(c,u);let s=e.method!=="GET"&&e.method!=="HEAD",a={method:e.method,headers:o};return s&&e.body!==void 0&&(a.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),o.has("content-type")||o.set("content-type","application/json")),new Request(i,a)}async function zi(e,n){e.status(n.status),n.headers.forEach((r,i)=>e.setHeader(i,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function Yr(e,n){let t=Ce(e,n);return async(r,i,o)=>{try{let s=await t(Ji(r));await zi(i,s)}catch(s){o(s)}}}function Qr(e,n){let t=Ce(e,n);return r=>t(r.req.raw)}function Xr(e,n){let t=Ce(e,n);return{GET:t,POST:t}}function eo(e){let n={[Ye]:e};return{ok:hn,tenants:{list:()=>wn(e),create:t=>Tn(e,t),get:t=>Cn(e,t)},plugins:{list:()=>kn(e),get:t=>bn(e,t)},connectionStatus:{get:t=>_e(e,t?.tenantId)},permissions:{get:t=>Dr(e,t)},connect:{createLink:t=>Pn(n,e,t),resolve:t=>vn(n,e,t),oauthCallback:t=>xn(n,e,t)}}}async function no(e,n,t,r,i="pending"){if(!e)return null;try{let o=nr(),s=new Date;return await e.db.insertInto("corsair_events").values({id:o,created_at:s,updated_at:s,account_id:n,event_type:t,payload:r,status:i}).execute(),o}catch(o){return console.warn("Failed to log event:",o),null}}async function Vi(e,n,t,r="pending"){try{let i=await e.$getAccountId();return no(e.database,i,n,t,r)}catch(i){return console.warn("Failed to log event:",i),null}}import*as to from"https";import*as ro from"querystring";function Fn(e,n,t,r,i){let o=new URL(r.tokenUrl),s=r.tokenAuthMethod==="basic";return new Promise((a,c)=>{let u={code:e.trim(),redirect_uri:i,grant_type:"authorization_code"};s||(u.client_id=n,u.client_secret=t);let d=ro.stringify(u),l={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(d).toString()};s&&(l.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=to.request({hostname:o.hostname,...o.port?{port:Number(o.port)}:{},path:o.pathname+o.search,method:"POST",headers:l},f=>{let p="";f.on("data",y=>{p+=y}),f.on("end",()=>{if(f.statusCode!==200){c(new Error(`Token exchange failed (${f.statusCode}): ${p}`));return}try{a(JSON.parse(p))}catch{c(new Error(`Token endpoint returned non-JSON response: ${p}`))}})});g.on("error",f=>c(new Error(`Request failed: ${f.message}`))),g.write(d),g.end()})}var oo=" ";function K(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 j(e){return e.innerType??e.schema??e.out??e.in}function so(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 j(e)}}function ao(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function $n(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function Be(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 co(e,n){return e.description??n.description}function Yi(e){let n=e;for(;n;){let t=K(n),r=co(n,t);if(r)return r;let i=Z(t);if(Jt(i)||i==="ZodPipe"||i==="ZodEffects"||i==="ZodTransform"){n=so(t,i);continue}break}}function Jt(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function M(e){let n=K(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??Be(n)[0]??"unknown");case"ZodEnum":return Be(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=j(n);return r?M(r):"unknown"}case"ZodNullable":{let r=j(n);return`${r?M(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=j(n);return r?M(r):"unknown"}case"ZodArray":{let r=ao(n);if(!r)return"unknown[]";let i=K(r),o=Z(i)==="ZodUnion",s=M(r);return`${o?`(${s})`:s}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=$n(e,n),i=Object.entries(r);return i.length===0?"{}":`{ ${i.map(([s,a])=>{let c=Z(K(a));return`${c==="ZodOptional"||c==="ZodNullable"?s+"?":s}: ${M(a)}`}).join(", ")} }`}case"ZodUnion":return Be(n).map(r=>M(r)).join(" | ");case"ZodIntersection":return`${M(n.left)} & ${M(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=so(n,t);return r?M(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function ie(e){let n=K(e),t=Z(n),r=co(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 i=n.value??Be(n)[0],o=typeof i=="string"||typeof i=="number"||typeof i=="boolean"?i:String(i??"");return{kind:"literal",optional:!1,description:r,value:o}}case"ZodEnum":{let i=Be(n).map(o=>String(o));return{kind:"string",optional:!1,description:r,enum:i}}case"ZodOptional":{let i=j(n),o=i?ie(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodNullable":{let i=j(n),o=i?ie(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodDefault":case"ZodCatch":{let i=j(n);return i?{...ie(i),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let i=ao(n);return{kind:"array",optional:!1,description:r,items:i?ie(i):{kind:"unknown",optional:!1}}}case"ZodObject":{let i=$n(e,n),o={};for(let[s,a]of Object.entries(i))o[s]=ie(a);return{kind:"object",optional:!1,description:r,fields:o}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let i=Be(n);for(let o of i){let s=K(o);if(Z(s)==="ZodObject")return{...ie(o),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let i=j(n);return i?{...ie(i),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function hl(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let i=t.slice(0,r),o=t.slice(r+1),s=e.find(d=>d.id===i);if(!s)return null;let a=o;a.startsWith("api.")&&(a=a.slice(4));let c=ge(s.endpointMeta,a),u=ge(s.endpointSchemas,a);return!c&&!u?null:{input:u?.input?ie(u.input):null,output:u?.output?ie(u.output):null,description:c?.description}}var zt=["equals","contains","startsWith","endsWith","in"],Qi=["equals","gt","gte","lt","lte","in"],Xi=["equals"],es=["equals","before","after","between"];function uo(e){let n=K(e);switch(Z(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=j(n);return r?uo(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Vt(e){let n=K(e),t=Z(n);if(Jt(t)){let o=j(n);return o?Vt(o):{}}if(t!=="ZodObject")return{};let r=$n(e,n),i={};for(let[o,s]of Object.entries(r)){let a=uo(s);a==="string"?i[o]={type:"string",operators:zt}:a==="number"?i[o]={type:"number",operators:Qi}:a==="boolean"?i[o]={type:"boolean",operators:Xi}:a==="date"&&(i[o]={type:"date",operators:es})}return i}function lo(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function Zt(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];typeof i=="function"?t.push(o.join(".")):i!==null&&typeof i=="object"&&Zt(i,o,t)}}function qt(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Gt(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];qt(i)?t.push(o.join(".")):i!==null&&typeof i=="object"&&Gt(i,o,t)}}function Yt(e,n){if(n.length===0)return null;let[t,...r]=n,i=Object.entries(e).find(([a])=>a.toLowerCase()===t);if(!i)return null;let[o,s]=i;if(r.length===0)return qt(s)?[o]:null;if(s!==null&&typeof s=="object"&&!qt(s)){let a=Yt(s,r);if(a!==null)return[o,...a]}return null}function po(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let o=0;o<n.length;o++){let s=" ".repeat(o+2);t.push(`${s}${n[o]}: {`)}let r=" ".repeat(n.length+2),i=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${i}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let o=n.length-1;o>=0;o--){let s=" ".repeat(o+2);t.push(`${s}},`)}return t.push(" },"),t.push("})"),t.join(`
26
- `)}var ns=new Set(en);function Te(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let o=e.find(a=>a.id===r);if(!o)return ns.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:Te(e);if(t==="webhooks"){if(!o.webhooks)return[];let a=[];return Gt(o.webhooks,[],a),a.map(c=>`${o.id}.webhooks.${c}`)}if(t==="db"){let a=o.schema?.entities;return a?Object.keys(a).map(c=>`${o.id}.db.${c}.search`):[]}if(!o.endpoints)return[];let s=[];return Zt(o.endpoints,[],s),s.map(a=>`${o.id}.api.${a}`)}let i={};if(t==="webhooks")for(let o of e){if(!o.webhooks)continue;let s=[];Gt(o.webhooks,[],s),i[o.id]=s.map(a=>`${o.id}.webhooks.${a}`)}else if(t==="db")for(let o of e){let s=o.schema?.entities;s&&(i[o.id]=Object.keys(s).map(a=>`${o.id}.db.${a}.search`))}else for(let o of e){if(!o.endpoints)continue;let s=[];Zt(o.endpoints,[],s),i[o.id]=s.map(a=>`${o.id}.api.${a}`)}return i}function ge(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function ts(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let o=t.slice(n.length+1),s=o.startsWith(".")?o.slice(1):o;return s.startsWith("api.")&&(s=s.slice(4)),{shortPath:s,lookupKey:s}}let i=e.slice(n.length+1);return i.toLowerCase().startsWith("api.")&&(i=i.slice(4)),{shortPath:i,lookupKey:i.toLowerCase()}}function Kt(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 kl(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let i=t.slice(0,r),o=t.slice(r+1),s=e.find(a=>a.id===i);if(s){if(o.startsWith("db.")){let d=o.slice(3),l=d.lastIndexOf(".");if(l!==-1){let g=d.slice(0,l),f=d.slice(l+1),p=s.schema?.entities;if(f==="search"&&p){let y=lo(p,g);if(y){let[m,h]=y,C=Vt(h),b=[`Search ${i} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${zt.join(", ")}]`];for(let[k,w]of Object.entries(C))b.push(` ${k}?: ${w.type} [${w.operators.join(", ")}]`);return b.push("}"),b.join(`
30
- `)}}}return Kt(Te(e,{type:"db"}),"Path not found. Available db operations")}if(o.startsWith("webhooks.")){let d=o.slice(9);if(s.webhooks){let l=Yt(s.webhooks,d.split("."));if(l!==null){let g=l.join("."),f=ge(s.webhookSchemas,g.toLowerCase()),p=f?.response?M(f.response):null,y=[];return f?.description&&y.push(f.description),f?.payload&&y.push(`payload ${Nn(Ue(f.payload))}`),p&&y.push(`response: ${p}`),y.push(`usage:
31
- ${po(i,l)}`),y.join(`
32
-
33
- `)}}return Kt(Te(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=o;a.startsWith("api.")&&(a=a.slice(4));let c=ge(s.endpointMeta,a),u=ge(s.endpointSchemas,a);if(c||u){let d=[],l=[c?.riskLevel?`[${c.riskLevel}]`:"",c?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),g=[c?.description,l].filter(Boolean).join(" ");return g&&d.push(g),u?.input&&d.push(`input ${Nn(Ue(u.input))}`),u?.output&&d.push(`output ${Nn(Ue(u.output))}`),d.join(`
34
-
35
- `)}}}return Kt(Te(e),"Path not found. Available operations")}function io(e){let n=e;for(;;){let t=K(n),r=Z(t);if(Jt(r)){let i=j(t);if(!i)return n;n=i;continue}return n}}function Ue(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=io(e),t=K(n);if(Z(t)==="ZodObject"){let i=$n(n,t),o=[];for(let[s,a]of Object.entries(i)){let c=K(a),u=Z(c),d=u==="ZodOptional"||u==="ZodNullable",l=io(a),g=Yi(a);o.push({key:s,optional:d,type:M(l),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:o}}return{kind:"inline",type:M(n)}}function Nn(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=oo.repeat(n+1),r=oo.repeat(n);return`{
36
- ${e.fields.map(o=>{let s=o.optional?`${o.key}?`:o.key,a=o.description?` // ${o.description}`:"";return`${t}${s}: ${o.type}${a}`}).join(`
37
- `)}
38
- ${r}}`}return"unknown"}function rs(e,n){let t=Te(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(d=>d.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let i=[];for(let d of t){let{shortPath:l,lookupKey:g}=ts(d,n),f=ge(r.endpointMeta,g),p=ge(r.endpointSchemas,g);!f&&!p||i.push({path:d,shortPath:l,description:f?.description,riskLevel:f?.riskLevel,irreversible:f?.irreversible,input:Ue(p?.input),output:Ue(p?.output)})}i.sort((d,l)=>d.path.localeCompare(l.path));let o=[],s=Te(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let d of s){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("webhooks."))continue;let p=f.slice(9),y=Yt(r.webhooks,p.split("."));if(y===null)continue;let m=y.join("."),h=ge(r.webhookSchemas,m.toLowerCase()),C=h?.response?M(h.response):void 0;o.push({path:d,description:h?.description,payload:Ue(h?.payload),responseType:C,usageExample:po(n,y)})}o.sort((d,l)=>d.path.localeCompare(l.path));let a=[],c=Te(e,{plugin:n,type:"db"}),u=r.schema?.entities;if(Array.isArray(c)&&u)for(let d of c){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("db."))continue;let p=f.slice(3),y=p.lastIndexOf(".");if(y===-1)continue;let m=p.slice(0,y);if(p.slice(y+1)!=="search")continue;let C=lo(u,m);if(!C)continue;let[b,k]=C,w=Vt(k),T=Object.entries(w).map(([E,_])=>({field:E,type:_.type,operators:_.operators}));a.push({path:d,entityName:b,filters:[{field:"entity_id",type:"string",operators:zt},...T]})}return a.sort((d,l)=>d.path.localeCompare(l.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:a}}}function go(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function os(e,n){let t=go(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let i=r.pluginTenantWebhookMatcher(n);return i?{plugin:t,tenantMatch:i}:null}function is(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function fo(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function yo(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 Qe(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function ss(e){return Qe(e.body)}function mo(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Ln(Array.isArray(r)?r:[r])}function ho(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let c of t){let u=Ln(Array.isArray(c)?c:[c]);if(u)return decodeURIComponent(u)}let r=mo({query:e.query},"validationToken");if(r)return r;let i=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let c of i){let u=n[c],d=Array.isArray(u)?u[0]:u;if(!(!d||typeof d!="string"))try{let g=(d.startsWith("http")?new URL(d):new URL(`https://example.invalid${d.startsWith("/")?d:`/${d}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let o=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,s=Qe(typeof o=="string"?(()=>{try{return JSON.parse(o)}catch{return o}})():o);return Ln([s?.validationToken])??null}function as(e){if(ho(e))return!0;let n=Qe(e.body??e.payload);return fo(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Ln(e){for(let n of e){let t=yo(n);if(t)return t}}function cs(e){let t=Qe(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var Ye=Symbol.for("corsair:internal");function lr(e){let n=e.database?Qt(e.database):void 0,t=n&&e.kek?Jr(e.plugins,n,e.kek):Un(!!n,!!e.kek),r=zr(e),i={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?nn(e.hub):void 0},o=vr(n),s=eo(i);if(e.multiTenancy)return Object.assign({withTenant:c=>{if(!c)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let u=jt(e.plugins,{database:n,tenantId:c,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(u,{[Ye]:i})},keys:t,permissions:o,manage:s},{[Ye]:i});let a=jt(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign({},a,{keys:t,permissions:o,manage:s,[Ye]:i})}var B=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function ko(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 us(e,n,t,r){let i=rr(e),o=await i.integrations.findByName(n);if(!o)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:t,integration_id:o.id}))return;let a=ee(),c=await ne(a,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:c})}async function Jn(e,n,t){let{tenantId:r,redirectUri:i}=t,o=P(e,()=>new B("invalid_corsair_instance","Invalid corsair instance"));if(!o.database)throw new Error("No database configured on corsair instance");let s=F(o,n,l=>new B("plugin_not_found",l)),a=ko(s),u=await O({authType:"oauth_2",integrationName:n,kek:o.kek,database:o.database}).get_client_id();if(!u)throw new Error(`client_id not configured for '${n}'`);let d=ae(z(n,r),o.kek);return{url:Ee({oauthConfig:a,clientId:u,redirectUri:i,state:d}),state:d}}async function ze(e,n){let{code:t,state:r,redirectUri:i}=n,o=P(e,()=>new B("invalid_corsair_instance","Invalid corsair instance")),s=cn(r,o.kek);if(!s)throw new B("invalid_state","Invalid or tampered state parameter");let{plugin:a,tenantId:c}=s;if(!o.database)throw new B("no_database","No database configured on corsair instance");let u=F(o,a,m=>new B("plugin_not_found",m)),d=ko(u),l=O({authType:"oauth_2",integrationName:a,kek:o.kek,database:o.database}),g=await l.get_client_id(),f=await l.get_client_secret();if(!g||!f)throw new B("credentials_not_configured",`Credentials not configured for '${a}'`);await us(o.database,a,c,o.kek);let p=await Fn(t,g,f,d,i);if(!p.access_token)throw new B("no_access_token",`No access_token returned from ${d.providerName}`);let y=I({authType:"oauth_2",integrationName:a,tenantId:c,kek:o.kek,database:o.database});await y.set_access_token(p.access_token),p.refresh_token&&await y.set_refresh_token(p.refresh_token),p.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+p.expires_in));try{let m=await In(o.plugins,a,p);if(m)try{let h=u.authConfig?.oauth_2?.account??[];await Oe({database:o.database,kek:o.kek,pluginId:a,tenantId:c,link:m,authType:"oauth_2",extraAccountFields:h})}catch(h){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${a}' tenant '${c}':`,h)}}catch(m){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${a}' tenant '${c}':`,m)}return{plugin:a,tenantId:c}}export{or as a,ye as b,Ne as c,me as d,nn as e,H as f,tn as g,rn as h,on as i,sn as j,ir as k,an as l,z as m,jn as n,ee as o,ne as p,L as q,zn as r,je as s,ce as t,te as u,Ke as v,O as w,I as x,br as y,wr as z,Oe as A,ct as B,En as C,Mr as D,Ee as E,B as F,Jn as G,ze as H,Le as I,Ae as J,Zn as K,sr as L,Re as M,cr as N,Ko as O,ln as P,Yn as Q,fn as R,yn as S,De as T,le as U,he as V,de as W,Me as X,Br as Y,_n as Z,lt as _,He as $,dt as aa,pt as ba,gt as ca,ft as da,re as ea,On as fa,Mn as ga,pe as ha,be as ia,we as ja,Ge as ka,Je as la,Hn as ma,kt as na,bt as oa,wt as pa,Ct as qa,Tt as ra,Pt as sa,vt as ta,Ve as ua,oe as va,xt as wa,jr as xa,Kr as ya,At as za,Rt as Aa,St as Ba,It as Ca,Et as Da,_t as Ea,Dt as Fa,Ot as Ga,Mt as Ha,Ht as Ia,Bt as Ja,Ut as Ka,Ft as La,Nt as Ma,$t as Na,Ce as Oa,Yr as Pa,Qr as Qa,Xr as Ra,no as Sa,Vi as Ta,Fn as Ua,hl as Va,Te as Wa,kl as Xa,Nn as Ya,rs as Za,go as _a,os as $a,is as ab,fo as bb,yo as cb,Qe as db,ss as eb,mo as fb,ho as gb,as as hb,Ln as ib,cs as jb,Ye as kb,lr as lb};
@@ -299,6 +299,204 @@ type EnforcePermissionResult = {
299
299
  onComplete?: () => Promise<void>;
300
300
  };
301
301
 
302
+ type TokenResponse = {
303
+ access_token?: string;
304
+ refresh_token?: string;
305
+ expires_in?: number;
306
+ token_type?: string;
307
+ [key: string]: unknown;
308
+ };
309
+ /**
310
+ * Exchanges an OAuth authorization code for access/refresh tokens.
311
+ * Supports both 'body' (default) and 'basic' token auth methods.
312
+ */
313
+ declare function exchangeCodeForTokens(code: string, clientId: string, clientSecret: string, oauthConfig: OAuthConfig, redirectUri: string): Promise<TokenResponse>;
314
+
315
+ /**
316
+ * Raw incoming webhook data for matching (before full parsing).
317
+ * Used by matcher functions to determine if a webhook should be handled.
318
+ */
319
+ type RawWebhookRequest = {
320
+ /** HTTP headers from the webhook request */
321
+ headers: Record<string, string | string[] | undefined>;
322
+ /** Raw request body (string or already parsed object) */
323
+ body: unknown;
324
+ /** Query string parameters when available (e.g. Microsoft Graph validationToken). */
325
+ query?: Record<string, string | string[] | undefined>;
326
+ };
327
+ /**
328
+ * Raw incoming webhook request data after initial processing.
329
+ * Contains the parsed payload, headers, and optional raw body string.
330
+ * @template TPayload - The type of the parsed webhook payload
331
+ */
332
+ type WebhookRequest<TPayload = unknown> = {
333
+ /** Parsed payload from the webhook request body */
334
+ payload: TPayload;
335
+ /** HTTP headers from the webhook request */
336
+ headers: Record<string, string | string[] | undefined>;
337
+ /** Raw request body string (for signature verification) */
338
+ rawBody?: string;
339
+ /** Query string parameters when available. */
340
+ query?: Record<string, string | string[] | undefined>;
341
+ };
342
+ /**
343
+ * Response from a webhook handler that can include acknowledgment data.
344
+ * @template TData - The type of data to return in the response
345
+ */
346
+ type WebhookResponse<TData = unknown> = {
347
+ /** Whether the webhook was processed successfully */
348
+ success: boolean;
349
+ /** The entity relevant to the webhook (note that this is corsair_entities.id) */
350
+ corsairEntityId?: string;
351
+ /** Return this object to the sender. Defaults to empty. Usually only necessary for webhook confirmation / challenge. */
352
+ returnToSender?: Record<string, string>;
353
+ /** Optional data to return in the HTTP response */
354
+ data?: TData;
355
+ /** Optional error message if processing failed */
356
+ error?: string;
357
+ /** HTTP status code to return (defaults to 200 on success, 500 on error) */
358
+ statusCode?: number;
359
+ /** HTTP response headers to set on the outgoing response. Used for header-based handshakes (e.g. Asana X-Hook-Secret). */
360
+ responseHeaders?: Record<string, string>;
361
+ };
362
+ /**
363
+ * A webhook matcher function that synchronously determines if a raw webhook
364
+ * request should be handled by this webhook.
365
+ * @param request - The raw webhook request data
366
+ * @returns True if this webhook should handle the request
367
+ */
368
+ type CorsairWebhookMatcher = (request: RawWebhookRequest) => boolean;
369
+ /**
370
+ * Identifies which external credential key should be used to resolve a tenant
371
+ * for an incoming webhook. The `linkType` names the field stored on
372
+ * `corsair_accounts` (for example `team_id`, `installation_id`).
373
+ */
374
+ type WebhookTenantMatch = {
375
+ linkType: string;
376
+ externalId: string;
377
+ };
378
+ /**
379
+ * Extracts the tenant lookup key from a webhook after the plugin has been
380
+ * identified. Return null when the payload does not contain a resolvable id
381
+ * (for example URL verification challenges).
382
+ */
383
+ type CorsairWebhookTenantMatcher = (request: RawWebhookRequest) => WebhookTenantMatch | null;
384
+ /**
385
+ * Resolves the webhook tenant link field after OAuth completes.
386
+ * Return null when the provider does not expose a stable external id.
387
+ */
388
+ type CorsairOAuthWebhookTenantLinkResolver = (tokens: TokenResponse) => WebhookTenantMatch | null | Promise<WebhookTenantMatch | null>;
389
+ /**
390
+ * Bivariance hack for webhook function types to ensure proper type inference.
391
+ * @template Args - The function arguments
392
+ * @template R - The function return type
393
+ */
394
+ type Bivariant<Args extends unknown[], R> = {
395
+ bivarianceHack(...args: Args): R;
396
+ }['bivarianceHack'];
397
+ /**
398
+ * A webhook handler function definition that processes incoming webhooks.
399
+ * Takes context + webhook request, returns a webhook response.
400
+ * @template Ctx - The context type passed to the handler
401
+ * @template TPayload - The type of the webhook payload
402
+ * @template TResponseData - The type of data returned in the response
403
+ */
404
+ type CorsairWebhookHandler<Ctx extends CorsairContext = CorsairContext, TPayload = unknown, TResponseData = unknown> = Bivariant<[
405
+ ctx: Ctx,
406
+ request: WebhookRequest<TPayload>
407
+ ], Promise<WebhookResponse<TResponseData>>>;
408
+ /**
409
+ * A complete webhook definition with both matcher and handler.
410
+ * The matcher synchronously determines if this webhook handles the incoming request.
411
+ * The handler processes the webhook after matching.
412
+ * @template Ctx - The context type passed to the handler
413
+ * @template TPayload - The type of the webhook payload
414
+ * @template TResponseData - The type of data returned in the response
415
+ */
416
+ type CorsairWebhook<Ctx extends CorsairContext = CorsairContext, TPayload = unknown, TResponseData = unknown> = {
417
+ /** Synchronously determines if this webhook handles the incoming request */
418
+ match: CorsairWebhookMatcher;
419
+ /** Handles the webhook request after matching */
420
+ handler: CorsairWebhookHandler<Ctx, TPayload, TResponseData>;
421
+ };
422
+ /**
423
+ * A tree of webhooks that can be nested arbitrarily deep.
424
+ * Similar to EndpointTree but for webhook handlers.
425
+ *
426
+ * @example
427
+ * ```ts
428
+ * // Flat structure
429
+ * webhooks: {
430
+ * issueCreated: { match: (req) => ..., handler: async (ctx, req) => ... },
431
+ * issueClosed: { match: (req) => ..., handler: async (ctx, req) => ... },
432
+ * }
433
+ *
434
+ * // Nested structure
435
+ * webhooks: {
436
+ * issues: {
437
+ * created: { match: (req) => ..., handler: async (ctx, req) => ... },
438
+ * updated: { match: (req) => ..., handler: async (ctx, req) => ... },
439
+ * },
440
+ * pull_requests: {
441
+ * opened: { match: (req) => ..., handler: async (ctx, req) => ... },
442
+ * },
443
+ * }
444
+ * ```
445
+ */
446
+ type WebhookTree = {
447
+ [key: string]: CorsairWebhook | WebhookTree;
448
+ };
449
+ /**
450
+ * A bound webhook - the user-facing API after context is applied.
451
+ * Contains both the matcher (unchanged) and the bound handler.
452
+ * @template TPayload - The type of the webhook payload
453
+ * @template TResponseData - The type of data returned in the response
454
+ */
455
+ type BoundWebhook<TPayload = unknown, TResponseData = unknown> = {
456
+ /** Synchronously determines if this webhook handles the incoming request */
457
+ match: CorsairWebhookMatcher;
458
+ /** Handles the webhook request (context already applied) */
459
+ handler: (request: WebhookRequest<TPayload>) => Promise<WebhookResponse<TResponseData>>;
460
+ };
461
+ /**
462
+ * A tree of bound webhooks (context already applied).
463
+ * This is what the end user interacts with after client initialization.
464
+ */
465
+ type BoundWebhookTree = {
466
+ [key: string]: BoundWebhook<any, any> | BoundWebhookTree;
467
+ };
468
+ /**
469
+ * Recursively transforms webhook definitions to their bound (context-free) signatures.
470
+ * Handles both flat and nested webhook structures.
471
+ * @template T - The webhook tree to bind
472
+ */
473
+ type BindWebhooks<T extends WebhookTree> = {
474
+ [K in keyof T]: T[K] extends CorsairWebhook<any, infer P, infer R> ? BoundWebhook<P, R> : T[K] extends WebhookTree ? BindWebhooks<T[K]> : never;
475
+ };
476
+ /**
477
+ * Derives all dot-notation webhook paths from a WebhookTree as a string literal union.
478
+ * Used to provide compile-time validation for webhook schema registry keys.
479
+ * Passing an invalid path to any config that accepts WebhookPathsOf<T> is a type error.
480
+ *
481
+ * Design note: Same recursive constraint relaxation as EndpointPathsOf — see that type
482
+ * for a full explanation of why we use `extends object` rather than `extends WebhookTree`
483
+ * on the recursive call. We also check `{ match: any; handler: any }` before `object`
484
+ * because webhook leaves are objects themselves.
485
+ *
486
+ * @example
487
+ * Given: `{ messages: { message: { match: fn, handler: fn } }, channels: { created: { match: fn, handler: fn } } }`
488
+ * Result: `'messages.message' | 'channels.created'`
489
+ *
490
+ * @template T - The webhook tree to extract paths from (unconstrained to allow recursion through as-const types)
491
+ * @template Prefix - Internal accumulator for the current path prefix (do not supply manually)
492
+ */
493
+ type WebhookPathsOf<T, Prefix extends string = ''> = {
494
+ [K in keyof T & string]: T[K] extends {
495
+ match: any;
496
+ handler: any;
497
+ } ? Prefix extends '' ? K : `${Prefix}.${K}` : T[K] extends object ? WebhookPathsOf<T[K], Prefix extends '' ? K : `${Prefix}.${K}`> : never;
498
+ }[keyof T & string];
499
+
302
500
  /**
303
501
  * Extracts typed entity clients from a plugin schema.
304
502
  * Each entity type becomes a `PluginEntityClient<DataSchema>`.
@@ -992,202 +1190,4 @@ type CorsairDeprecatedApprovalConfig = {
992
1190
  approval?: CorsairPermissionsOptions;
993
1191
  };
994
1192
 
995
- type TokenResponse = {
996
- access_token?: string;
997
- refresh_token?: string;
998
- expires_in?: number;
999
- token_type?: string;
1000
- [key: string]: unknown;
1001
- };
1002
- /**
1003
- * Exchanges an OAuth authorization code for access/refresh tokens.
1004
- * Supports both 'body' (default) and 'basic' token auth methods.
1005
- */
1006
- declare function exchangeCodeForTokens(code: string, clientId: string, clientSecret: string, oauthConfig: OAuthConfig, redirectUri: string): Promise<TokenResponse>;
1007
-
1008
- /**
1009
- * Raw incoming webhook data for matching (before full parsing).
1010
- * Used by matcher functions to determine if a webhook should be handled.
1011
- */
1012
- type RawWebhookRequest = {
1013
- /** HTTP headers from the webhook request */
1014
- headers: Record<string, string | string[] | undefined>;
1015
- /** Raw request body (string or already parsed object) */
1016
- body: unknown;
1017
- /** Query string parameters when available (e.g. Microsoft Graph validationToken). */
1018
- query?: Record<string, string | string[] | undefined>;
1019
- };
1020
- /**
1021
- * Raw incoming webhook request data after initial processing.
1022
- * Contains the parsed payload, headers, and optional raw body string.
1023
- * @template TPayload - The type of the parsed webhook payload
1024
- */
1025
- type WebhookRequest<TPayload = unknown> = {
1026
- /** Parsed payload from the webhook request body */
1027
- payload: TPayload;
1028
- /** HTTP headers from the webhook request */
1029
- headers: Record<string, string | string[] | undefined>;
1030
- /** Raw request body string (for signature verification) */
1031
- rawBody?: string;
1032
- /** Query string parameters when available. */
1033
- query?: Record<string, string | string[] | undefined>;
1034
- };
1035
- /**
1036
- * Response from a webhook handler that can include acknowledgment data.
1037
- * @template TData - The type of data to return in the response
1038
- */
1039
- type WebhookResponse<TData = unknown> = {
1040
- /** Whether the webhook was processed successfully */
1041
- success: boolean;
1042
- /** The entity relevant to the webhook (note that this is corsair_entities.id) */
1043
- corsairEntityId?: string;
1044
- /** Return this object to the sender. Defaults to empty. Usually only necessary for webhook confirmation / challenge. */
1045
- returnToSender?: Record<string, string>;
1046
- /** Optional data to return in the HTTP response */
1047
- data?: TData;
1048
- /** Optional error message if processing failed */
1049
- error?: string;
1050
- /** HTTP status code to return (defaults to 200 on success, 500 on error) */
1051
- statusCode?: number;
1052
- /** HTTP response headers to set on the outgoing response. Used for header-based handshakes (e.g. Asana X-Hook-Secret). */
1053
- responseHeaders?: Record<string, string>;
1054
- };
1055
- /**
1056
- * A webhook matcher function that synchronously determines if a raw webhook
1057
- * request should be handled by this webhook.
1058
- * @param request - The raw webhook request data
1059
- * @returns True if this webhook should handle the request
1060
- */
1061
- type CorsairWebhookMatcher = (request: RawWebhookRequest) => boolean;
1062
- /**
1063
- * Identifies which external credential key should be used to resolve a tenant
1064
- * for an incoming webhook. The `linkType` names the field stored on
1065
- * `corsair_accounts` (for example `team_id`, `installation_id`).
1066
- */
1067
- type WebhookTenantMatch = {
1068
- linkType: string;
1069
- externalId: string;
1070
- };
1071
- /**
1072
- * Extracts the tenant lookup key from a webhook after the plugin has been
1073
- * identified. Return null when the payload does not contain a resolvable id
1074
- * (for example URL verification challenges).
1075
- */
1076
- type CorsairWebhookTenantMatcher = (request: RawWebhookRequest) => WebhookTenantMatch | null;
1077
- /**
1078
- * Resolves the webhook tenant link field after OAuth completes.
1079
- * Return null when the provider does not expose a stable external id.
1080
- */
1081
- type CorsairOAuthWebhookTenantLinkResolver = (tokens: TokenResponse) => WebhookTenantMatch | null | Promise<WebhookTenantMatch | null>;
1082
- /**
1083
- * Bivariance hack for webhook function types to ensure proper type inference.
1084
- * @template Args - The function arguments
1085
- * @template R - The function return type
1086
- */
1087
- type Bivariant<Args extends unknown[], R> = {
1088
- bivarianceHack(...args: Args): R;
1089
- }['bivarianceHack'];
1090
- /**
1091
- * A webhook handler function definition that processes incoming webhooks.
1092
- * Takes context + webhook request, returns a webhook response.
1093
- * @template Ctx - The context type passed to the handler
1094
- * @template TPayload - The type of the webhook payload
1095
- * @template TResponseData - The type of data returned in the response
1096
- */
1097
- type CorsairWebhookHandler<Ctx extends CorsairContext = CorsairContext, TPayload = unknown, TResponseData = unknown> = Bivariant<[
1098
- ctx: Ctx,
1099
- request: WebhookRequest<TPayload>
1100
- ], Promise<WebhookResponse<TResponseData>>>;
1101
- /**
1102
- * A complete webhook definition with both matcher and handler.
1103
- * The matcher synchronously determines if this webhook handles the incoming request.
1104
- * The handler processes the webhook after matching.
1105
- * @template Ctx - The context type passed to the handler
1106
- * @template TPayload - The type of the webhook payload
1107
- * @template TResponseData - The type of data returned in the response
1108
- */
1109
- type CorsairWebhook<Ctx extends CorsairContext = CorsairContext, TPayload = unknown, TResponseData = unknown> = {
1110
- /** Synchronously determines if this webhook handles the incoming request */
1111
- match: CorsairWebhookMatcher;
1112
- /** Handles the webhook request after matching */
1113
- handler: CorsairWebhookHandler<Ctx, TPayload, TResponseData>;
1114
- };
1115
- /**
1116
- * A tree of webhooks that can be nested arbitrarily deep.
1117
- * Similar to EndpointTree but for webhook handlers.
1118
- *
1119
- * @example
1120
- * ```ts
1121
- * // Flat structure
1122
- * webhooks: {
1123
- * issueCreated: { match: (req) => ..., handler: async (ctx, req) => ... },
1124
- * issueClosed: { match: (req) => ..., handler: async (ctx, req) => ... },
1125
- * }
1126
- *
1127
- * // Nested structure
1128
- * webhooks: {
1129
- * issues: {
1130
- * created: { match: (req) => ..., handler: async (ctx, req) => ... },
1131
- * updated: { match: (req) => ..., handler: async (ctx, req) => ... },
1132
- * },
1133
- * pull_requests: {
1134
- * opened: { match: (req) => ..., handler: async (ctx, req) => ... },
1135
- * },
1136
- * }
1137
- * ```
1138
- */
1139
- type WebhookTree = {
1140
- [key: string]: CorsairWebhook | WebhookTree;
1141
- };
1142
- /**
1143
- * A bound webhook - the user-facing API after context is applied.
1144
- * Contains both the matcher (unchanged) and the bound handler.
1145
- * @template TPayload - The type of the webhook payload
1146
- * @template TResponseData - The type of data returned in the response
1147
- */
1148
- type BoundWebhook<TPayload = unknown, TResponseData = unknown> = {
1149
- /** Synchronously determines if this webhook handles the incoming request */
1150
- match: CorsairWebhookMatcher;
1151
- /** Handles the webhook request (context already applied) */
1152
- handler: (request: WebhookRequest<TPayload>) => Promise<WebhookResponse<TResponseData>>;
1153
- };
1154
- /**
1155
- * A tree of bound webhooks (context already applied).
1156
- * This is what the end user interacts with after client initialization.
1157
- */
1158
- type BoundWebhookTree = {
1159
- [key: string]: BoundWebhook<any, any> | BoundWebhookTree;
1160
- };
1161
- /**
1162
- * Recursively transforms webhook definitions to their bound (context-free) signatures.
1163
- * Handles both flat and nested webhook structures.
1164
- * @template T - The webhook tree to bind
1165
- */
1166
- type BindWebhooks<T extends WebhookTree> = {
1167
- [K in keyof T]: T[K] extends CorsairWebhook<any, infer P, infer R> ? BoundWebhook<P, R> : T[K] extends WebhookTree ? BindWebhooks<T[K]> : never;
1168
- };
1169
- /**
1170
- * Derives all dot-notation webhook paths from a WebhookTree as a string literal union.
1171
- * Used to provide compile-time validation for webhook schema registry keys.
1172
- * Passing an invalid path to any config that accepts WebhookPathsOf<T> is a type error.
1173
- *
1174
- * Design note: Same recursive constraint relaxation as EndpointPathsOf — see that type
1175
- * for a full explanation of why we use `extends object` rather than `extends WebhookTree`
1176
- * on the recursive call. We also check `{ match: any; handler: any }` before `object`
1177
- * because webhook leaves are objects themselves.
1178
- *
1179
- * @example
1180
- * Given: `{ messages: { message: { match: fn, handler: fn } }, channels: { created: { match: fn, handler: fn } } }`
1181
- * Result: `'messages.message' | 'channels.created'`
1182
- *
1183
- * @template T - The webhook tree to extract paths from (unconstrained to allow recursion through as-const types)
1184
- * @template Prefix - Internal accumulator for the current path prefix (do not supply manually)
1185
- */
1186
- type WebhookPathsOf<T, Prefix extends string = ''> = {
1187
- [K in keyof T & string]: T[K] extends {
1188
- match: any;
1189
- handler: any;
1190
- } ? Prefix extends '' ? K : `${Prefix}.${K}` : T[K] extends object ? WebhookPathsOf<T[K], Prefix extends '' ? K : `${Prefix}.${K}`> : never;
1191
- }[keyof T & string];
1192
-
1193
1193
  export { type WebhookPathsOf as $, type EndpointMetaEntry as A, type BindEndpoints as B, type CorsairPlugin as C, type EndpointRiskLevel as D, type EndpointPathsOf as E, type PermissionPolicy as F, type PluginEndpointMeta as G, type PluginPermissionsConfig as H, type RequiredPluginEndpointMeta as I, type RequiredPluginEndpointSchemas as J, type KeyBuilderContext as K, type RequiredPluginWebhookSchemas as L, type WebhookHooks as M, type BindWebhooks as N, type OAuthConfig as O, type PermissionMode as P, type BoundWebhook as Q, type RetryStrategies as R, type BoundWebhookTree as S, type TokenResponse as T, type CorsairOAuthWebhookTenantLinkResolver as U, type CorsairWebhook as V, type WebhookTenantMatch as W, type CorsairWebhookHandler as X, type CorsairWebhookMatcher as Y, type CorsairWebhookTenantMatcher as Z, type RawWebhookRequest as _, type CorsairPermissionsOptions as a, type WebhookRequest as a0, type WebhookResponse as a1, type WebhookTree as a2, type ManagementOk as a3, type Tenant as a4, type CreateTenantInput as a5, type PluginInfo as a6, type ConnectionStatus as a7, type PermissionLookupInput as a8, type PermissionRecord as a9, type CreateConnectLinkInput as aa, type ConnectLink as ab, type ResolvedConnectLink as ac, type OAuthCallbackInput as ad, type OAuthCallbackResult as ae, type CorsairManageNamespace as af, type PluginConnectionState as ag, type CorsairManualConfig as b, type CorsairIntegration as c, type CorsairTenantWrapper as d, type CorsairSingleTenantClient as e, exchangeCodeForTokens as f, type CorsairClient as g, type BoundEndpointFn as h, type BoundEndpointTree as i, type CorsairContext as j, type CorsairEndpoint as k, type EndpointTree as l, type CorsairErrorHandler as m, type ErrorContext as n, type ErrorHandler as o, type ErrorHandlerAndMatchFunction as p, type ErrorMatcher as q, type RetryStrategy as r, type CorsairPermissionsNamespace as s, type EnforcePermissionOptions as t, type EnforcePermissionResult as u, type BeforeHookResult as v, type CorsairKeyBuilder as w, type CorsairKeyBuilderBase as x, type CorsairPluginContext as y, type EndpointHooks as z };