corsair 0.1.93 → 0.1.94

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 ie,b as or,c as T,d as N,e as ir,f as J,g as E,h as H,i as Xe,j as sr,k as qn,l as ar,m as ur}from"./chunk-FLNFC4KL.js";import{a as rr}from"./chunk-IGGCNGU2.js";var en=["agentql","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"],cr={agentql:"AgentQL",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 se(e){let n=cr[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var $e="https://auth.corsair.dev";var ye=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret } to createCorsair()."),this.name="HubNotConfiguredError"}};function nn(e){let n=(e.apiUrl?.trim()||$e).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim();if(!t||!r)throw new Error("Hub config requires non-empty projectApiKey and signingSecret");return{apiUrl:n,projectApiKey:t,signingSecret:r,oauthCallbackUrl:e.oauthCallbackUrl?.trim().replace(/\/$/,"")}}function Ho(e){return e.apiUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function $(e){let n=T(e).hub;if(!n||!Ho(n))throw new ye;return n}function lr(e){return e.replace(/\/$/,"")}function tn(e){return e.oauthCallbackUrl?lr(e.oauthCallbackUrl.trim()):`${lr(e.apiUrl)}/oauth/callback`}function xe(e){if(e.startsWith("ck_dev_"))return"development";if(e.startsWith("ck_prod_"))return"production";throw new Error("Hub API key must start with ck_dev_ (development) or ck_prod_ (production)")}function v(e){return typeof e=="string"&&e.length>0}function Fo(e){return e==="pending"||e==="connected"||e==="failed"}function Uo(e){return e==="oauth"||e==="api_key"||e==="bot_token"}function rn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!v(n.connectUrl)||!v(n.token)||!v(n.projectId))throw new Error("Hub API returned an incomplete connect session (expected connectUrl, token, and projectId)");let t={connectUrl:n.connectUrl,token:n.token,projectId:n.projectId,environmentId:v(n.environmentId)?n.environmentId:n.projectId};return v(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function on(e){if(!Array.isArray(e))throw new Error("Hub API returned an invalid connections response (expected array)");let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;!v(r.tenantId)||!v(r.plugin)||!Fo(r.status)||!Uo(r.authKind)||n.push({tenantId:r.tenantId,plugin:r.plugin,status:r.status,authKind:r.authKind,connectedAt:v(r.connectedAt)?r.connectedAt:null,expiresAt:v(r.expiresAt)?r.expiresAt:null})}return n}function sn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!v(n.approvalUrl)||!v(n.token)||!v(n.projectId)||!v(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(v(n.access_token))return{access_token:n.access_token,refresh_token:v(n.refresh_token)?n.refresh_token:void 0,expires_in:(()=>{if(typeof n.expires_in=="number")return n.expires_in;if(typeof n.expires_in=="string"&&n.expires_in.trim().length>0){let t=Number(n.expires_in);return Number.isFinite(t)?t:void 0}})(),scope:v(n.scope)?n.scope:void 0};throw new Error(v(n.error)?v(n.error_description)?n.error_description:n.error:"Hub token refresh returned no access_token")}function Bo(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function No(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;v(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 $o(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 dr(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!v(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(!v(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=No(i.fields),s=Bo(i.missingRequiredFields),u=$o(i.status,i.connected,a,s);t.push({plugin:i.plugin,providerName:v(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 pr(e){return e.replace(/\/$/,"")}async function gr(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 fr(e,n,t){if(n===404&&t)return t;let r=un(e);return r||`Hub API returned HTTP ${n}`}async function Re(e){let n=pr(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 gr(t);if(!t.ok)throw new Error(fr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function yr(e){let n=pr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`}}),r=await gr(t);if(!t.ok)throw new Error(fr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as hr,createDecipheriv as mr,randomBytes as cn,scrypt as Lo}from"crypto";import{promisify as Wo}from"util";var kr=Wo(Lo),ln="aes-256-gcm",br=12,dn=16,jo=16,Le=32;function Q(){return cn(Le).toString("base64")}async function X(e,n){let t=cn(jo),r=await kr(n,t,Le),i=cn(br),o=hr(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"),l=Buffer.from(o,"base64"),d=await kr(n,a,Le),c=mr(ln,d,s,{authTagLength:dn});return c.setAuthTag(u),Buffer.concat([c.update(l),c.final()]).toString("utf8")}function Gn(e,n){let t=Buffer.from(n,"base64"),r=cn(br),i=hr(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 We(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"),l=mr(ln,o,a,{authTagLength:dn});return l.setAuthTag(s),Buffer.concat([l.update(u),l.final()]).toString("utf8")}function ae(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=Gn(i,n);return t}function ee(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=We(i,n);return t}function je(e,n,t){let r=ee(e,n);return ae(r,t)}function Cr(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 f=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!f)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return s={id:f.id,config:Jn(f.config),dek:f.dek??null},s},updateIntegration:async f=>{let y=await u.getIntegration();await i.db.updateTable("corsair_integrations").set({...f.config!==void 0?{config:f.config}:{},...f.dek!==void 0?{dek:f.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),s=null}},l=null,d=async()=>{if(l)return l;let f=await u.getIntegration();if(!f.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return l=await L(f.dek,r),l},c=async()=>{let f=await u.getIntegration(),y=await d(),h=f.config;return!h||Object.keys(h).length===0?{}:ee(h,y)};return{get_dek:d,issue_new_dek:async()=>{let f=await u.getIntegration(),y=Q(),h={};if(f.dek){let C=await L(f.dek,r),b=f.config;b&&Object.keys(b).length>0&&(h=je(b,C,y))}let m=await X(y,r);return await u.updateIntegration({config:h,dek:m}),l=y,y},...Cr(c,async f=>{let y=await d(),h;try{h=await c()}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(f))k===null?delete m[b]:m[b]=k;let C=ae(m,y);await u.updateIntegration({config:C})},a)}}function S(e){let{authType:n,integrationName:t,tenantId:r,kek:i,database:o,extraAccountFields:a=[]}=e,s=[...E[n].account,...a],u=null,l=null,d=async()=>{if(l)return l;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 l={id:k.id,config:Jn(k.config),dek:k.dek??null},l},c={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 c.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,g=null,f=async()=>{if(p)return p;let k=await c.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(g)return g;let k=await c.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return g=await L(k.dek,i),g},h=async()=>{let k=await c.getAccount(),w=await f(),P=k.config;return!P||Object.keys(P).length===0?{}:ee(P,w)},m=async()=>{let k=await c.getIntegration(),w=await y(),P=k.config;return!P||Object.keys(P).length===0?{}:ee(P,w)},b={get_dek:f,issue_new_dek:async()=>{let k=await c.getAccount(),w=Q(),P={};if(k.dek){let O=await L(k.dek,i),M=k.config;M&&Object.keys(M).length>0&&(P=je(M,O,w))}let D=await X(w,i);return await c.updateAccount({config:P,dek:D}),p=w,w},...Cr(h,async k=>{let w=await f(),P;try{P=await h()}catch(M){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,M),P={}}let D={...P};for(let[M,x]of Object.entries(k))x===null?delete D[M]:D[M]=x;let O=ae(D,w);await c.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 wr(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=Q(),o=await X(i,t);return await e.db.updateTable("corsair_integrations").set({dek:o,updated_at:new Date}).where("id","=",r.id).execute(),i}async function Pr(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=Q(),s=await X(a,r);return await e.db.updateTable("corsair_accounts").set({dek:s,updated_at:new Date}).where("id","=",o.id).execute(),a}var Ko=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function Se(e){return Ko.has(e)}function Zo(e,n){return Se(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function qo(e){return!Se(e)}function Go(e){switch(e){case"oauth_2":case"managed":return["access_token","refresh_token"];case"api_key":return["api_key"];case"bot_token":return["bot_token"]}}function Jo(e,n){return Go(e).every(r=>n.find(o=>o.level==="account"&&o.name===r)?.configured??!1)}async function Tr(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 zo(e,n){let r=e.authConfig?.[n]?.integration??[];return[...E[n].integration,...r]}function Vo(e,n){let r=e.authConfig?.[n]?.account??[];return[...E[n].account,...r]}function Yo(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:Jo(n,t),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}),l=S({authType:r,integrationName:n.id,tenantId:i,kek:e.kek,database:e.database,extraAccountFields:s}),d=zo(n,r),c=Vo(n,r),p=[];for(let g of d)p.push({name:g,level:"integration",required:Zo(r,g),configured:await Tr(u,g)});for(let g of c)p.push({name:g,level:"account",required:qo(g),configured:await Tr(l,g)});return Yo(n.id,r,p)}async function Ke(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.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}import{ZodBoolean as Xo,ZodDate as ei,ZodEnum as ni,ZodNullable as ti,ZodNumber as ri,ZodObject as oi,ZodOptional as ii,ZodRecord as si,ZodString as ai,ZodType as ui}from"zod";var Qo={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:{}}}},zn=Qo;async function Ar(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=or(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=li(e,a.plugins,n),u={...a,database:a.database},l=u.database.db;await gi(l,i);let d=await fi(l,u,s.tenantId,s.provisionAccounts,r);n?.credentials&&Object.keys(n.credentials).length>0&&await mi(e,s,n.credentials,u,r,i);let c=await bi(d,s,r,o);if(n?.backfill){r("[corsair:setup] Starting backfill...");let p=Rr({plugins:a.plugins,database:l,kek:a.kek,multiTenancy:!0}).withTenant(s.tenantId);await Ci(p,a.plugins,c,r,i),r("[corsair:setup] Backfill complete.")}return t.join(`
2
+ `)}function Vn(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...E[n][t],...r])}function ci(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=Vn(i,o,"account");for(let s of Object.keys(r))if(a.has(s))return!0}return!1}function li(e,n,t){let r=ir(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&&ci(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 xr(e,n){return ie(e)?n===0?!0:Object.values(e).every(t=>xr(t,n-1)):!1}function di(e){return xr(e,4)}var pi={...ar};function fn(e){if(e instanceof oi){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof ui?fn(r):"unknown";return n}return e instanceof ti?`${fn(e.unwrap())} | null`:e instanceof ii?`${fn(e.unwrap())} | undefined`:e instanceof ni?e.options.join(" | "):e instanceof ai?"string":e instanceof ri?"number":e instanceof Xo?"boolean":e instanceof ei?"date":e instanceof si?"jsonb":"unknown"}async function gi(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(i=>i.name));for(let[i,o]of Object.entries(pi))r.has(i)||n(`[corsair:setup] Table "${i}" does not exist. Run your database migrations before calling setupCorsair.
3
+ Schema: ${JSON.stringify(fn(o),null,2)}`)}async function fi(e,n,t,r,i){let o=new Date,a=new Map;for(let s of n.plugins){let u=s.id,l=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 c=l?s.authConfig?.[l]?.integration??[]:[],p=l?s.authConfig?.[l]?.account??[]:[],g=l&&d?I({authType:l,integrationName:u,kek:n.kek,database:n.database,extraIntegrationFields:c}):void 0;if(d&&!d.dek&&g&&(await g.issue_new_dek(),i(`[corsair:setup] Issued integration DEK: ${u}`)),!d||!l||!g)continue;let f;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}`)}f=y&&S({authType:l,integrationName:u,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:p}),y&&f&&!y.dek&&(await f.issue_new_dek(),i(`[corsair:setup] Issued account DEK: ${u}`))}a.set(u,{pluginId:u,authType:l,integration:g,account:f,integrationFields:[...E[l].integration,...c],accountFields:r?[...E[l].account,...p]:[]})}return a}function yi(e){if(!ie(e))return;let n=e.keys;return ie(n)?n:void 0}function hi(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function mi(e,n,t,r,i,o){let a=yi(e),s=n.provisionAccounts?hi(e,n.tenantId):void 0;for(let[u,l]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 c=H(d);if(!c){o(`[corsair:setup] Plugin '${u}' has no auth type \u2014 skipping credentials.`);continue}let p=Vn(d,c,"integration"),g=Vn(d,c,"account"),f=a?.[u],y=s?.[u],h=ie(y)?y.keys:void 0;for(let[m,C]of Object.entries(l))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(f,`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(g.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 vr=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function ki(e,n,t,r,i,o,a,s,u){let l=[],d=[];for(let p of i){if(vr.has(p))continue;let g=J(t,`get_${p}`);if(!g)continue;let f=null;try{let y=await g();f=typeof y=="string"?y:null}catch{}f||l.push(p)}if(r&&o.length>0)for(let p of o){if(vr.has(p))continue;let g=J(r,`get_${p}`);if(!g)continue;let f=null;try{let y=await g();f=typeof y=="string"?y:null}catch{}f||d.push(p)}let c=l.length===0&&d.length===0;if(c)s(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else if(n==="managed")s(`[corsair:setup] '${e}' (managed) is not connected yet. Use Connect in your app \u2014 Corsair Hub delivers OAuth tokens after authorization.`);else{let p=[...l,...d];if(u==="cli"){let g=p.map(f=>`${f}=VALUE`).join(" ");s(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
+ corsair setup --${e} ${g}`)}else{let g=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let f of l)g.push(` await corsair.keys.${e}.set_${f}(value)`);for(let f of d){let y=a.provisionAccounts?a.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(a.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;g.push(` await ${y}.keys.set_${f}(value)`)}s(g.join(`
5
+ `))}}return c}async function bi(e,n,t,r){let i=new Set;for(let o of e.values())await ki(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(!di(zn)){i("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let o=zn,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 l=ie(e)?e[s]:void 0,d=ie(l)?l.api:void 0;if(d)for(let[c,p]of Object.entries(u))for(let[g,f]of Object.entries(p)){r(`[corsair:setup] Backfilling ${s} \u203A ${c}.${g}...`);try{let y=ie(d)?d[c]:void 0;await J(y,g)?.(f)}catch(y){i(`[corsair:setup] ${s} \u203A ${c}.${g} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Ie(e,n){if(!T(e).database)throw new Error("A database must be configured to provision Corsair for connect");await Ar(e,{tenantId:n})}var wi=new Set(["access_token","refresh_token","expires_at","scope"]);function Pi(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Ti(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!Se(t)&&!wi.has(t)):n.filter(t=>!Se(t))}async function Sr(e,n,t={}){let r=T(e),i=$(e),o=tn(i),a=[],s=t.pluginIds?new Set(t.pluginIds):null;for(let u of r.plugins){if(s&&!s.has(u.id))continue;let l=H(u);if(!l)continue;let d=Pi(l),c=t.providerNameOverrides?.[u.id]??se(u.id),p=await pn(r,u,n),g=Xe(u,l),f=Ti(l,g),y={plugin:u.id,providerName:c,authKind:d,alreadyConfigured:p?.connected??!1};if(f.length>0&&(y.credentialFields=f),d==="oauth"){let m=t.oauthModeOverrides?.[u.id]??(l==="managed"?"managed":"byo");if(y.oauthMode=m,!t.skipOAuthUrlGeneration&&m!=="managed")try{let C=await Yn(e,u.id,{tenantId:n,redirectUri:o,hubConnect:!0});y.oauthUrl=C.url}catch(C){y.setupError=C instanceof Error?C.message:`Could not prepare OAuth for ${u.id}`}}a.push(y)}return a}async function Ir(e,n){await Ie(e,n)}var vi="3000",Ai="/api/corsair";function Qn(e){return e.replace(/\/$/,"")}function xi(e,n){return`${Qn(e)}${n}`}function _r(e){return e.startsWith("http")?e:`https://${e}`}function _e(e){let n=e?.deliveryUrl?.trim();if(n)return Qn(n);let t=e?.deliveryPath?.trim()||Ai,r=t.startsWith("/")?t:`/${t}`,i=process.env.CORSAIR_DELIVERY_URL?.trim();if(i)return Qn(_r(i));let o=process.env.APP_URL?.trim()||process.env.NEXT_PUBLIC_APP_URL?.trim()||process.env.VERCEL_URL?.trim();return o?xi(_r(o),r):`http://localhost:${process.env.PORT?.trim()||vi}${r}`}async function yn(e,n){let t=$(e),r=xe(t.projectApiKey);await Ir(e,n.tenantId);let i=n.plugin?[n.plugin]:void 0,o=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,a=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,s=await Sr(e,n.tenantId,{pluginIds:i,oauthModeOverrides:o,providerNameOverrides:a});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 u={tenantId:n.tenantId,plugins:s};return r==="development"&&(u.deliveryUrl=_e({deliveryUrl:n.deliveryUrl})),Re({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:u,parseResponse:rn})}function Er(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Ri(e,n){return n&&!n.has(e.id)?!1:H(e)!==null}async function Ee(e,n,t={}){let r=T(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,a=await Ke(r,i,{pluginIds:t.pluginIds}),s=new Map(a.map(l=>[l.plugin,l])),u=r.plugins.filter(l=>Ri(l,o)).map(l=>{let d=H(l),c=s.get(l.id);return c?{plugin:l.id,providerName:se(l.id),authKind:Er(d),status:c.status,connected:c.connected,fields:c.fields.map(p=>({name:p.name,level:p.level,required:p.required,configured:p.configured})),missingRequiredFields:c.missingRequiredFields}:{plugin:l.id,providerName:se(l.id),authKind:Er(d),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:i,plugins:u}}async function Dr(e,n){let t=$(e);return yr({hub:t,path:`/projects/${encodeURIComponent(n.projectId)}/connections`,notFoundMessage:"Hub REST API not found at /projects/:id/connections. Check HUB_API_URL and ensure the Hub API is deployed.",parseResponse:on})}var Si=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Xn(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Si.has(n)}catch{return!1}}function et(e){return e==="development"?"browser":"server"}function Or(e){return et(e)==="browser"}function Mr(e){return Xn(e)?"Production delivery URL must be a public URL, not localhost":null}var ue=6e4,he=3e5;var z=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function hn(e,n){let t=T(e,()=>new z("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new z("no_database","Database not configured");let r=N(t,n.plugin,d=>new z("plugin_not_found",d)),i=H(r);if(!i)throw new z("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new z("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Ie(e,n.tenantId);let o=new Set(Xe(r,i)),s=r.authConfig?.[i]?.account??[],u=S({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:s}),l=0;for(let[d,c]of Object.entries(n.credentials)){if(!c.trim())continue;if(!o.has(d))throw new z("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let p=J(u,`set_${d}`);if(!p)throw new z("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await p(c.trim()),l+=1}if(l===0)throw new z("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var mn=new Map;function Ii(e){for(let[n,t]of mn)t<=e&&mn.delete(n)}function kn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return Ii(r),mn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(mn.set(t,r+n),{ok:!0})}async function bn(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 Hr=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function _i(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 Ei(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=Hr(n.config),i={};Object.keys(r).length>0&&(i=ee(r,t)),i[e.link.linkType]=e.link.externalId;let o=ae(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function De(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:a,extraAccountFields:s=[]}=e,{accountId:u}=await _i({database:n,pluginId:r,tenantId:i}),l=!1;if(a){let d=S({authType:a,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:s}),c=`set_${o.linkType}`,p=d[c];typeof p=="function"&&(await p(o.externalId),l=!0)}l||await Ei({database:n,kek:t,accountId:u,link:o})}async function nt(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=Hr(s.config)[i];if(!d)continue;if(We(d,u)===o)return s}catch{continue}return null}async function Cn(e){return(await nt(e))?.tenant_id??null}async function Fr(e){return Cn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var ce=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Oe(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:a,scope:s}=n;if(!i.trim())throw new ce("no_access_token","Managed OAuth delivery missing access_token");let u=T(e,()=>new ce("invalid_corsair_instance","Invalid corsair instance"));if(!u.database)throw new ce("no_database","No database configured on corsair instance");let l=N(u,t,c=>new ce("plugin_not_found",c));await Ie(e,r);let d=S({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 c=await bn(u.plugins,t,{access_token:i,refresh_token:o,scope:s});if(c)try{let p=l.authConfig?.managed?.account??[];await De({database:u.database,kek:u.kek,pluginId:t,tenantId:r,link:c,authType:"managed",extraAccountFields:p})}catch(p){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,p)}}catch(c){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,c)}return{plugin:t,tenantId:r}}import{createHmac as tt,randomUUID as Di,timingSafeEqual as Ur}from"crypto";function Br(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function wn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=tt("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":Di()}}}function rt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Br(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=tt("sha256",n).update(e.body).digest("hex");try{return Ur(Buffer.from(o,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function Me(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Br(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=tt("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 ot(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function it(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function st(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 at(e){let{body:n,headers:t}=wn(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 Oi(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Nr(e,n,t=[]){for(let[r,i]of Object.entries(e))if(Oi(i)){if(i.match(n))return{webhook:i,path:[...t,r]}}else if(i&&typeof i=="object"){let o=Nr(i,n,[...t,r]);if(o)return o}return null}function Mi(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Hi(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=Mi(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=Hi(i)||o);let s={headers:i,body:o,...r?{query:r}:{}},u=r?.tenantId||"default",l=e.withTenant?e.withTenant(u):e,d=en;for(let c of d){let p=l[c];if(!p||!p.webhooks||p.pluginWebhookMatcher&&!p.pluginWebhookMatcher(s))continue;let g=Nr(p.webhooks,s);if(!g)continue;let f=g.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let h=await g.webhook.handler(y),m=!!Object.keys(h.returnToSender||{})?.length;return{plugin:c,action:f,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 ${c}.${f}:`,h),{plugin:c,action:f,body:o,response:{success:!1,error:h instanceof Error?h.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{randomBytes as Ni}from"crypto";import{createHmac as Fi,randomBytes as Ui,timingSafeEqual as Bi}from"crypto";function ne(){return Ui(16).toString("base64url")}function Ze(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Fi("sha256",t).update(e).digest("base64url")}function V(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=Ze(i,t);try{if(!Bi(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=Ze(o,n);return`${o}.${a}`}function qe(e,n,t){let r=Math.floor(Date.now()/1e3);return Pn(e,n,r+Math.floor(t/1e3))}function me(e){return decodeURIComponent(e)}function ut(e){return encodeURIComponent(e)}function Lr(e){let n=e.trim();return n.length>0?n:null}function Tn(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function vn(e,n){if(!Lr(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??Ni(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 le(e,n){return Lr(n)?V(e,n):null}function ke(e){return e.deliveryMode==="connect.status"}function be(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 An(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!ke(e)&&!be(e)&&!Ge(e)&&!Je(e)}function ct(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 $i(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 Cn({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function Li(e,n,t){let r=await $i(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 Wi(e,n){return await ze(e,n),{status:"ok"}}async function ji(e,n){return await Oe(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function dt(e,n,t){let r=await lt(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function lt(e,n,t){let r=T(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 Ki(e,n){try{return await hn(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function Zi(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await Ee(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function pt(e,n,t={}){let r=T(e),i=ct(n.headers,"x-corsair-signature"),o=ct(n.headers,"x-corsair-timestamp"),a=ct(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let u=Me({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 l=kn(`nonce:${a.trim()}`,3e5);if(!l.ok)return{status:"failed",retryable:!1,error:l.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(s.type){case"webhook":return Li(e,r,s.payload);case"oauth.callback":return Wi(e,s.payload);case"oauth.tokens":return ji(e,s.payload);case"permission.approve":return lt(e,s.payload,"approved");case"permission.deny":return lt(e,s.payload,"denied");case"auth.credentials":return Ki(e,s.payload);case"connect.status":return Zi(e,s.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${s.type}`}}}var qi="corsair:client-bridge";function Wr(e){let n=JSON.stringify({type:qi,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 Gi=[".corsair.dev"];function Ji(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function zi(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Ji(n)?!0:Gi.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function jr(e){return!e||!zi(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 Kr(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 xn(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 gt(e,n){let t=$(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=le(i,t.signingSecret);if(!o)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let a=kn(`browser:${o.jti}`,6e4);if(!a.ok)return{type:"json",status:400,body:{error:a.error}};try{if(ke(o)){if(!o.hubSuccessUrl)return{type:"json",status:400,body:{error:"Connect status delivery missing hubSuccessUrl"}};let s=o.tenantId?.trim()||"default",u=await Ee(e,s,{pluginIds:o.statusPlugins});return{type:"redirect",url:xn(o.hubSuccessUrl,{status:u})}}if(be(o))return o.hubSuccessUrl?o.credentials?(await hn(e,{plugin:o.plugin,tenantId:o.tenantId,credentials:o.credentials}),{type:"redirect",url:xn(o.hubSuccessUrl,{connectedPlugin:o.plugin})}):{type:"redirect",url:xn(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 dt(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 Oe(e,{plugin:o.plugin,tenantId:o.tenantId,accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.expiresIn,scope:o.scope})}else{if(!An(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(s){let u=s instanceof Error?s.message:"Hub delivery failed";return(ke(o)||be(o))&&o.hubSuccessUrl?{type:"redirect",url:xn(o.hubSuccessUrl,{error:u})}:(ke(o)||be(o))&&o.hubOrigin&&o.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Wr({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 ft(e,n){let t=$(e),r=await pt(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 yt(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 ht(e,n){return n.method==="GET"?gt(e,n.url):ft(e,{headers:n.headers,body:n.body??""})}async function mt(e,n){try{let t=await ht(e,n);return yt(t)}catch(t){if(t instanceof ye)return Response.json({error:t.message},{status:503});throw t}}async function Ce(e,n){let t=n.method.toUpperCase(),r=jr(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 mt(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return Kr(i,r)}var te=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 Zr=300;async function kt(e,n){let{keys:t,hub:r,plugin:i,tenantId:o}=e,a=n?.forceRefresh??!1,[s,u,l]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!s&&!l)throw new te(i,"managed");let d=Math.floor(Date.now()/1e3);if(!a&&s&&u&&Number(u)>d+Zr)return{accessToken:s,expiresAt:Number(u),refreshed:!1};if(!l&&s&&!a){let g=u?Number(u):null;if(g===null||g>d+Zr)return{accessToken:s,expiresAt:g??d+3600,refreshed:!1}}let c=await Re({hub:r,path:"/oauth/refresh",body:{plugin:i,tenantId:o},parseResponse:an}),p=c.expires_in?d+c.expires_in:u?Number(u):d+3600;return await t.set_access_token(c.access_token),await t.set_expires_at(String(p)),c.refresh_token&&await t.set_refresh_token(c.refresh_token),c.scope&&await t.set_scope(c.scope),{accessToken:c.access_token,expiresAt:p,refreshed:!0}}async function qr(e,n){e._refreshAuth=async()=>(await kt(n,{forceRefresh:!0})).accessToken}async function Rn(e,n){let t=xe(e.projectApiKey),r={permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,expiresAt:n.expiresAt};return t==="development"&&(r.deliveryUrl=_e({deliveryUrl:n.deliveryUrl})),Re({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:sn})}function Sn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}function Gr(e){return{delivery:n=>Ce(e,n),deliveryOptions:n=>Ce(e,n)}}var Jr=1200*1e3;function bt(){return ne()}function Ct(){return Jr}function wt(e,n){return qe(e,n,Jr)}function Pt(e,n){return V(e,n)}function Tt(e){return me(e)}var zr=600*1e3;function vt(){return ne()}function At(){return zr}function xt(e,n){return qe(e,n,zr)}function Rt(e,n){return V(e,n)}function St(e){return ut(e)}function It(e){return me(e)}function _t(){return ne()}function Et(e,n,t){return Pn(e,n,Math.floor(t.getTime()/1e3))}function Dt(e,n){return V(e,n)}function Ot(e){return me(e)}function In(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 ${Le}`)}})}import*as Ve from"crypto";function de(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function Mt(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 He(e,n){let t=Ve.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var Ht=600*1e3;function _n(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),i=e.slice(t+1),o=Ve.createHmac("sha256",n).update(r).digest("base64url"),a=Buffer.from(i,"base64url"),s=Buffer.from(o,"base64url");return a.length!==s.length||!Ve.timingSafeEqual(a,s)?null:Mt(r,{maxAgeMs:Ht})}function Fe(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}var Vi=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Vr(e,n,t,r,i){let o={pluginId:n,operation:t,input:r,originalError:e},a=Object.keys(i).find(l=>i[l]?.match(e,o));return await(i[a||"DEFAULT"]?.handler||Vi)(e,o)}import{randomBytes as Qi}from"crypto";import{v4 as Xi}from"uuid";var Ft="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 Bt(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function Yr(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Ut(e){return Sn(e)}async function Nt(e,n){if(Bt(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?Yr(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:Yi(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function Yi(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 Nt(e,n);return{...n,approvalUrl:r}}async function $t(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:i,permissionToken:o,plugin:a,endpoint:s,args:u,tenantId:l,expiresAt:d,operationPath:c}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:o,id:i,plugin:a,endpoint:s,args:u});let g=await Nt({manual:t,hub:r},{id:i,token:o,plugin:a,endpoint:s,args:JSON.stringify(u),tenant_id:l,expires_at:d});return Bt(t)?g?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:g}):Ut(g):Ft:r?g?Ut(g):`Action '${c}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Ft}var es={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 ns(e,n,t){return t!==void 0?t:es[n][e]}function Lt(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 Xr(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 Qr(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 eo(e){let n=ns(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 f=e.db,y=s.id;return{result:"allow",onComplete:async()=>{await f.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"?Qr(e.db,s.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:s.id,token:s.token,expiresAt:s.expires_at})}let u=Xi(),l=Qi(32).toString("hex"),d=e.timeoutMs??600*1e3,c=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:l,plugin:e.pluginId,endpoint:e.endpointPath,args:i,tenant_id:a,status:"pending",expires_at:c}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
21
+ Action: ${r}`,`
22
+ Permission ID: ${u}`,`
23
+ Permission token: ${l}`,`
24
+ Expires at: ${c}`,`
25
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Qr(e.db,u,d):{result:"blocked",reason:"pending",id:u,token:l,expiresAt:c}}function ts(e){return typeof e=="function"}function rs(e,n,t){let r=He(de(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 Wt({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:i,errorHandlers:o,currentPath:a=[],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:d,permissionsOptions:c,tenantId:p,manualConfig:g,hubConfig:f}){for(let[y,h]of Object.entries(e)){let m=n?.[y];if(ts(h)){let C=m,b=[...a,y].join("."),k=async(w={})=>{let P;if(u){let _=l?.[b],{result:Ae,reason:q,onComplete:Ne,token:Y,id:fe,expiresAt:B}=await eo({pluginId:i,endpointPath:b,args:w,mode:u.mode,override:u.overrides?.[b],riskLevel:_?.riskLevel??"write",meta:_,db:d,timeoutMs:c?Lt(c.timeout):void 0,tenantId:p,approvalMode:c?.mode});if(Ae==="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.`:Y&&fe?G=await $t({permissionsOptions:c,manual:g,hub:f,permissionId:fe,permissionToken:Y,plugin:i,endpoint:b,args:w,tenantId:p??"default",expiresAt:B??new Date(Date.now()+(c?Lt(c.timeout):600*1e3)).toISOString(),operationPath:b}):G=`Action '${b}' requires user approval before it can run.`,new Error(G)}P=Ne}let D=async(_,Ae,q)=>{try{return await h(Ae,q)}catch(Ne){if(Ne instanceof Error){let Y=await Vr(Ne,i,b,typeof q=="object"&&q!==null?q:{args:q},o);if(_<(Y.maxRetries||0)){let fe=_+1;console.log(`Retrying (${fe} / ${Y.maxRetries})...`);let B;if(Y.headersRetryAfterMs)B=Y.headersRetryAfterMs;else switch(Y.retryStrategy){case"exponential_backoff":B=Math.pow(2,fe-1)*1e3;break;case"exponential_backoff_jitter":let G=Math.pow(2,fe-1)*1e3,Mo=(Math.random()-.5)*1e3;B=Math.max(0,G+Mo);break;case"linear_1s":B=1e3;break;case"linear_2s":B=2e3;break;case"linear_3s":B=3e3;break;case"linear_4s":B=4e3;break;default:B=1e3;break}await new Promise(G=>setTimeout(G,B)),await D(fe,Ae,q),console.log(`[corsair:${i}:${b}] Retry strategy:`,Y)}}throw Ne}},O;try{O=s?await s(t,"endpoint"):void 0}catch(_){throw g&&Fe(g)&&g.oauthConfig&&g.kek&&_ instanceof te&&_.authType==="oauth_2"?rs(i,g,p):_}if(!C?.before&&!C?.after){let _=await D(0,{...t,key:O},w);return await P?.(),_}let M={...t,key:O},x=C.before?await C.before(M,w):{ctx:M,args:w,continue:!0,passToAfter:void 0};if(x.continue===!1)return;let ve=await D(0,x.ctx,x.args);return await C.after?.(x.ctx,ve,x.passToAfter),await P?.(),ve};r[y]=k}else if(h&&typeof h=="object"){let C={};Wt({endpoints:h,hooks:m,ctx:t,tree:C,pluginId:i,errorHandlers:o,currentPath:[...a,y],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:d,permissionsOptions:c,tenantId:p,manualConfig:g,hubConfig:f}),r[y]=C}}}function os(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function jt({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:i}){for(let[o,a]of Object.entries(e)){let s=n?.[o];if(os(a)){let u=s,l=async d=>{let c=(g,f)=>a.handler(g,f),p=i?await i(t,"webhook"):void 0;return!u?.before&&!u?.after?c({...t,key:p},d):(async()=>{let g={...t,key:p},f=u.before?await u.before(g,d):{ctx:g,args:d,continue:!0,passToAfter:void 0};if(f.continue===!1)return;let y=await c(f.ctx,f.args);return y?.success===!0&&await u.after?.(f.ctx,y,f.passToAfter),y})()};r[o]={match:a.match,handler:l}}else if(a&&typeof a=="object"){let u={};jt({webhooks:a,hooks:s,ctx:t,webhooksTree:u,keyBuilder:i}),r[o]=u}}}function is(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 ss(e,n,t,r,i){return e?qn(e.db,n,t,r,i):{findByEntityId:async()=>null,existsByEntityId:async()=>!1,findIdByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function Kt(e,n){let{database:t,tenantId:r,kek:i,rootErrorHandlers:o,permissionsOptions:a,manualConfig:s,hubConfig:u}=n,l={},d={};for(let c of e)l[c.id]={},d[c.id]={};for(let c of e){let p=c.schema,g=r??"default",f=is(t,c.id,g);if(p?.entities){let x={};for(let[ve,_]of Object.entries(p.entities)){let Ae=t?qn(t.db,f,ve,p.version,_):ss(void 0,f,ve,p.version,_);x[ve]=Ae}d[c.id].db=x,l[c.id].db=x}let y=c.options,h=c.authConfig,m;if(t&&i&&y?.authType){let x=h?.[y.authType]?.account??[];m=S({authType:y.authType,integrationName:c.id,tenantId:g,kek:i,database:t,extraAccountFields:x}),l[c.id].keys=m}let C={database:t,db:d[c.id]?.db??{},$getAccountId:f,...c.options?{options:c.options}:{},...m?{keys:m,authType:y?.authType}:{},tenantId:g,...u?{hub:u}:{}},b=c.endpoints??{},k=c.hooks,w={...o,...c.errorHandlers},P={},D=c.options?.permissions;Wt({endpoints:b,hooks:k,ctx:C,tree:P,pluginId:c.id,errorHandlers:w,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:D,endpointMeta:c.endpointMeta,database:t,permissionsOptions:a,tenantId:r,manualConfig:s?{...s,oauthConfig:c.oauthConfig,kek:i,tenantId:g}:void 0,hubConfig:u}),Object.keys(P).length>0&&(l[c.id].api=P),C.endpoints=P;let O=c.webhooks??{},M=c.webhookHooks;if(Object.keys(O).length>0){let x={};jt({webhooks:O,hooks:M,ctx:C,webhooksTree:x,keyBuilder:c.keyBuilder}),l[c.id].webhooks=x,c.pluginWebhookMatcher&&(l[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher),c.pluginTenantWebhookMatcher&&(l[c.id].pluginTenantWebhookMatcher=c.pluginTenantWebhookMatcher)}}return l}function no(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 as="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function to(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] ${as}`),t):n}import*as ro from"querystring";function we(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}?${ro.stringify(o)}`}var W=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function us(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 Zt(e,n){let t=T(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=_n(n,t.kek);if(!i)throw new W("invalid_state","Invalid or tampered state parameter");let{plugin:o,tenantId:a}=i,s=N(t,o,p=>new W("plugin_not_found",p)),u=us(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 c=we({oauthConfig:u,clientId:d,redirectUri:r,state:n});return{plugin:o,tenantId:a,providerName:u.providerName,oauthUrl:c,state:n}}var A=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 R(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function oo(e){let n={error:e.code,message:e.message,...e.extra};return R(e.status,n)}function pe(e){return new A(404,"not_found",e)}function re(e,n={}){return new A(400,"bad_request",e,n)}function io(e,n){return N(e,n,t=>pe(t))}async function so(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(l=>o[`get_${l}`]()))}catch{a=i.map(()=>null)}let s=i.filter((l,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 ao(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await so(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=>ao(n,e)))}async function Mn(e,n){let t=io(e,n);return ao(t,e)}async function cs(e,n){return e.database?(await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.id as accountId","a.dek as dek","i.name as integrationName"]).where("a.tenant_id","=",n).execute()).map(r=>({integrationName:r.integrationName,hasCredentials:!!r.dek})):[]}async function uo(e,n){let t=await cs(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 re("Tenant id must be a non-empty string");return uo(e,n)}async function Un(e,n){let t=n?.id?.trim();if(!t)throw re("Tenant id is required",{missingFields:["id"]});return uo(e,t)}async function Bn(e,n){let t=n?.trim()||"default",r={},i=await Ke(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 qt(e,n){if(!e.database)throw pe(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw pe(`Permission '${n}' not found`);return En(e,t)}function ls(e){if(!e.oauthConfig)throw re(`Plugin '${e.id}' has no oauthConfig`)}function ds(e){if(!e.manual)throw new A(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function Gt(e){let n=ds(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new A(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 ps(e){let n=!!e.hub,t=Fe(e.manual);if(!n&&!t)throw new A(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function co(e){if(!e.database||!e.kek)throw new A(500,"database_not_configured","A database and kek are required to issue connect links.")}async function gs(e,n){let t=n?.plugin?.trim();if(!t)throw re("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=io(e,t);ls(i);let o=Gt(e);co(e);let a=await so(i,e);if(!a.configured)throw new A(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:a.missingFields});let s=He(de(t,r),e.kek),u;try{u=new URL(o.baseUrl)}catch{throw new A(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()+Ht).toISOString()}}async function fs(e,n,t){co(n);let i={tenantId:t.tenantId?.trim()||"default",oauthMode:t.oauthMode},o=t.plugin?.trim();o&&(i.plugin=o);let a=t.providerName?.trim();a&&(i.providerName=a);let s=await yn(e,i);return{connectUrl:s.connectUrl,expiresAt:s.expiresAt}}async function Nn(e,n,t){return ps(n),n.hub?fs(e,n,t):gs(n,t)}async function $n(e,n,t){if(n.hub&&!Fe(n.manual))throw new A(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw re("state is required",{missingFields:["state"]});Gt(n);try{return await Zt(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw re("Invalid or expired state");case"client_id_not_configured":throw new A(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new A(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function Ln(e,n,t){if(n.hub&&!Fe(n.manual))throw new A(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 re("Missing required fields",{missingFields:o});let a=Gt(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 re("Invalid or expired state");case"credentials_not_configured":throw new A(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new A(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function Jt(e,n){if(!e.database)throw pe("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw pe("Permission not found");return En(e,t)}async function lo(e,n){return"id"in n?qt(e,n.id):Jt(e,n.token)}var po=[{method:"GET",pattern:"/ok",handler:async()=>R(200,Dn())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>R(200,await Hn(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>R(201,await Un(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>R(200,await Fn(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>R(200,await On(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>R(200,await Mn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>R(200,await Bn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>R(200,await qt(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?R(200,await Jt(e,t)):R(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>R(200,await Nn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>R(200,await $n(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>R(200,await Ln(e,n,t))}];(()=>{let e=new Set;for(let n of po){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function ys(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 hs(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 ms(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 A(400,"invalid_json","Request body is not valid JSON")}}var ks="/api/corsair";function Pe(e,n={}){let t=n.basePath??ks,r=T(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async i=>{try{let o=new URL(i.url),a=hs(o.pathname,t),s=i.method.toUpperCase();if(s==="OPTIONS"||a==="/"||a==="")return await Ce(e,i);if(s!=="GET"&&s!=="POST")return R(405,{error:"method_not_allowed",message:`Method ${s} not allowed`});let u=Object.fromEntries(o.searchParams);for(let l of po){if(l.method!==s)continue;let d=ys(l.pattern,a);if(!d)continue;let c=await ms(i);return await l.handler({corsair:e,internal:r,req:i,params:d,query:u,body:c})}throw pe(`No route for ${s} ${a}`)}catch(o){if(n.onError){let s=await n.onError(o,i);if(s)return s}if(o instanceof A)return oo(o);let a=o instanceof Error?o.message:"Internal server error";return R(500,{error:"internal_error",message:a})}}}function bs(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,l]of Object.entries(e.headers))if(l!=null)if(Array.isArray(l))for(let d of l)o.append(u,d);else o.set(u,l);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 Cs(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 go(e,n){let t=Pe(e,n);return async(r,i,o)=>{try{let a=await t(bs(r));await Cs(i,a)}catch(a){o(a)}}}function fo(e,n){let t=Pe(e,n);return r=>t(r.req.raw)}function yo(e,n){let t=Pe(e,n);return{GET:t,POST:t,OPTIONS:t}}function ho(e){let n={[Ye]:e};return{ok:Dn,tenants:{list:()=>Hn(e),create:t=>Un(e,t),get:t=>Fn(e,t)},plugins:{list:()=>On(e),get:t=>Mn(e,t)},connectionStatus:{get:t=>Bn(e,t?.tenantId)},permissions:{get:t=>lo(e,t)},connect:{createLink:t=>Nn(n,e,t),resolve:t=>$n(n,e,t),oauthCallback:t=>Ln(n,e,t)}}}async function mo(e,n,t,r,i="pending"){if(!e)return null;try{let o=sr(),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 ws(e,n,t,r="pending"){try{let i=await e.$getAccountId();return mo(e.database,i,n,t,r)}catch(i){return console.warn("Failed to log event:",i),null}}import*as ko from"https";import*as bo 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 l={code:e.trim(),redirect_uri:i,grant_type:"authorization_code"};a||(l.client_id=n,l.client_secret=t);let d=bo.stringify(l),c={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(d).toString()};a&&(c.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let p=ko.request({hostname:o.hostname,...o.port?{port:Number(o.port)}:{},path:o.pathname+o.search,method:"POST",headers:c},g=>{let f="";g.on("data",y=>{f+=y}),g.on("end",()=>{if(g.statusCode!==200){u(new Error(`Token exchange failed (${g.statusCode}): ${f}`));return}try{s(JSON.parse(f))}catch{u(new Error(`Token endpoint returned non-JSON response: ${f}`))}})});p.on("error",g=>u(new Error(`Request failed: ${g.message}`))),p.write(d),p.end()})}var Co=" ";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 Po(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 To(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 Ue(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 vo(e,n){return e.description??n.description}function Ps(e){let n=e;for(;n;){let t=K(n),r=vo(n,t);if(r)return r;let i=Z(t);if(Xt(i)||i==="ZodPipe"||i==="ZodEffects"||i==="ZodTransform"){n=Po(t,i);continue}break}}function Xt(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??Ue(n)[0]??"unknown");case"ZodEnum":return Ue(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=To(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 Ue(n).map(r=>F(r)).join(" | ");case"ZodIntersection":return`${F(n.left)} & ${F(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=Po(n,t);return r?F(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function oe(e){let n=K(e),t=Z(n),r=vo(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??Ue(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=Ue(n).map(o=>String(o));return{kind:"string",optional:!1,description:r,enum:i}}case"ZodOptional":{let i=j(n),o=i?oe(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodNullable":{let i=j(n),o=i?oe(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodDefault":case"ZodCatch":{let i=j(n);return i?{...oe(i),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let i=To(n);return{kind:"array",optional:!1,description:r,items:i?oe(i):{kind:"unknown",optional:!1}}}case"ZodObject":{let i=Kn(e,n),o={};for(let[a,s]of Object.entries(i))o[a]=oe(s);return{kind:"object",optional:!1,description:r,fields:o}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let i=Ue(n);for(let o of i){let a=K(o);if(Z(a)==="ZodObject")return{...oe(o),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let i=j(n);return i?{...oe(i),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function td(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=ge(a.endpointMeta,s),l=ge(a.endpointSchemas,s);return!u&&!l?null:{input:l?.input?oe(l.input):null,output:l?.output?oe(l.output):null,description:u?.description}}var er=["equals","contains","startsWith","endsWith","in"],Ts=["equals","gt","gte","lt","lte","in"],vs=["equals"],As=["equals","before","after","between"];function Ao(e){let n=K(e);switch(Z(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=j(n);return r?Ao(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function nr(e){let n=K(e),t=Z(n);if(Xt(t)){let o=j(n);return o?nr(o):{}}if(t!=="ZodObject")return{};let r=Kn(e,n),i={};for(let[o,a]of Object.entries(r)){let s=Ao(a);s==="string"?i[o]={type:"string",operators:er}:s==="number"?i[o]={type:"number",operators:Ts}:s==="boolean"?i[o]={type:"boolean",operators:vs}:s==="date"&&(i[o]={type:"date",operators:As})}return i}function xo(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function Vt(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"&&Vt(i,o,t)}}function Yt(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Qt(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];Yt(i)?t.push(o.join(".")):i!==null&&typeof i=="object"&&Qt(i,o,t)}}function tr(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 Yt(a)?[o]:null;if(a!==null&&typeof a=="object"&&!Yt(a)){let s=tr(a,r);if(s!==null)return[o,...s]}return null}function Ro(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 xs=new Set(en);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 xs.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 Qt(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 Vt(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=[];Qt(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=[];Vt(o.endpoints,[],a),i[o.id]=a.map(s=>`${o.id}.api.${s}`)}return i}function ge(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function Rs(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 zt(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 rd(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),c=d.lastIndexOf(".");if(c!==-1){let p=d.slice(0,c),g=d.slice(c+1),f=a.schema?.entities;if(g==="search"&&f){let y=xo(f,p);if(y){let[h,m]=y,C=nr(m),b=[`Search ${i} ${h} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${er.join(", ")}]`];for(let[k,w]of Object.entries(C))b.push(` ${k}?: ${w.type} [${w.operators.join(", ")}]`);return b.push("}"),b.join(`
30
+ `)}}}return zt(Te(e,{type:"db"}),"Path not found. Available db operations")}if(o.startsWith("webhooks.")){let d=o.slice(9);if(a.webhooks){let c=tr(a.webhooks,d.split("."));if(c!==null){let p=c.join("."),g=ge(a.webhookSchemas,p.toLowerCase()),f=g?.response?F(g.response):null,y=[];return g?.description&&y.push(g.description),g?.payload&&y.push(`payload ${jn(Be(g.payload))}`),f&&y.push(`response: ${f}`),y.push(`usage:
31
+ ${Ro(i,c)}`),y.join(`
32
+
33
+ `)}}return zt(Te(e,{type:"webhooks"}),"Path not found. Available webhooks")}let s=o;s.startsWith("api.")&&(s=s.slice(4));let u=ge(a.endpointMeta,s),l=ge(a.endpointSchemas,s);if(u||l){let d=[],c=[u?.riskLevel?`[${u.riskLevel}]`:"",u?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),p=[u?.description,c].filter(Boolean).join(" ");return p&&d.push(p),l?.input&&d.push(`input ${jn(Be(l.input))}`),l?.output&&d.push(`output ${jn(Be(l.output))}`),d.join(`
34
+
35
+ `)}}}return zt(Te(e),"Path not found. Available operations")}function wo(e){let n=e;for(;;){let t=K(n),r=Z(t);if(Xt(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=wo(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),l=Z(u),d=l==="ZodOptional"||l==="ZodNullable",c=wo(s),p=Ps(s);o.push({key:a,optional:d,type:F(c),...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=Co.repeat(n+1),r=Co.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 Ss(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:c,lookupKey:p}=Rs(d,n),g=ge(r.endpointMeta,p),f=ge(r.endpointSchemas,p);!g&&!f||i.push({path:d,shortPath:c,description:g?.description,riskLevel:g?.riskLevel,irreversible:g?.irreversible,input:Be(f?.input),output:Be(f?.output)})}i.sort((d,c)=>d.path.localeCompare(c.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),g=p.startsWith(".")?p.slice(1):p;if(!g.startsWith("webhooks."))continue;let f=g.slice(9),y=tr(r.webhooks,f.split("."));if(y===null)continue;let h=y.join("."),m=ge(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:Ro(n,y)})}o.sort((d,c)=>d.path.localeCompare(c.path));let s=[],u=Te(e,{plugin:n,type:"db"}),l=r.schema?.entities;if(Array.isArray(u)&&l)for(let d of u){let p=d.toLowerCase().slice(n.length+1),g=p.startsWith(".")?p.slice(1):p;if(!g.startsWith("db."))continue;let f=g.slice(3),y=f.lastIndexOf(".");if(y===-1)continue;let h=f.slice(0,y);if(f.slice(y+1)!=="search")continue;let C=xo(l,h);if(!C)continue;let[b,k]=C,w=nr(k),P=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:er},...P]})}return s.sort((d,c)=>d.path.localeCompare(c.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:s}}}function So(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function Is(e,n){let t=So(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 _s(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function Io(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function _o(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 Es(e){return Qe(e.body)}function Eo(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Zn(Array.isArray(r)?r:[r])}function Do(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let u of t){let l=Zn(Array.isArray(u)?u:[u]);if(l)return decodeURIComponent(l)}let r=Eo({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 l=n[u],d=Array.isArray(l)?l[0]:l;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=Qe(typeof o=="string"?(()=>{try{return JSON.parse(o)}catch{return o}})():o);return Zn([a?.validationToken])??null}function Ds(e){if(Do(e))return!0;let n=Qe(e.body??e.payload);return Io(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Zn(e){for(let n of e){let t=_o(n);if(t)return t}}function Os(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 Rr(e){let n=e.database?rr(e.database):void 0,t=n&&e.kek?no(e.plugins,n,e.kek):In(!!n,!!e.kek),r=to(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=Xr(n),a=ho(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 l=Kt(e.plugins,{database:n,tenantId:u,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(l,{[Ye]:i})},keys:t,permissions:o,manage:a},{[Ye]:i});let s=Kt(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,[Ye]:i})}var U=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function Oo(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 Ms(e,n,t,r){let i=ur(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=Q(),u=await X(s,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:u})}async function Yn(e,n,t){let{tenantId:r,redirectUri:i,hubConnect:o=!1}=t,a=T(e,()=>new U("invalid_corsair_instance","Invalid corsair instance"));if(!a.database)throw new Error("No database configured on corsair instance");let s=N(a,n,p=>new U("plugin_not_found",p)),u=Oo(s),d=await I({authType:"oauth_2",integrationName:n,kek:a.kek,database:a.database}).get_client_id();if(!d)throw new Error(`client_id not configured for '${n}'`);if(o){let p=new URL(we({oauthConfig:u,clientId:d,redirectUri:i,state:""}));return p.searchParams.delete("state"),{url:p.toString(),state:""}}let c=He(de(n,r),a.kek);return{url:we({oauthConfig:u,clientId:d,redirectUri:i,state:c}),state:c}}async function ze(e,n){let{code:t,state:r,redirectUri:i}=n,o=T(e,()=>new U("invalid_corsair_instance","Invalid corsair instance")),a=_n(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 l=N(o,s,h=>new U("plugin_not_found",h)),d=Oo(l),c=I({authType:"oauth_2",integrationName:s,kek:o.kek,database:o.database}),p=await c.get_client_id(),g=await c.get_client_secret();if(!p||!g)throw new U("credentials_not_configured",`Credentials not configured for '${s}'`);await Ms(o.database,s,u,o.kek);let f=await Wn(t,p,g,d,i);if(!f.access_token)throw new U("no_access_token",`No access_token returned from ${d.providerName}`);let y=S({authType:"oauth_2",integrationName:s,tenantId:u,kek:o.kek,database:o.database});await y.set_access_token(f.access_token),f.refresh_token&&await y.set_refresh_token(f.refresh_token),f.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+f.expires_in));try{let h=await bn(o.plugins,s,f);if(h)try{let m=l.authConfig?.oauth_2?.account??[];await De({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{cr as a,se as b,$e as c,ye as d,nn as e,$ as f,tn as g,xe as h,rn as i,on as j,sn as k,an as l,dr as m,un as n,Q as o,X as p,L as q,Gn as r,We as s,ae as t,ee as u,je as v,I as w,S as x,wr as y,Pr as z,de as A,Mt as B,De as C,nt as D,Cn as E,Fr as F,we as G,U as H,Yn as I,ze as J,Ar as K,mi as L,_e as M,yn as N,Ee as O,Dr as P,Xn as Q,et as R,Or as S,Mr as T,ue as U,he as V,ce as W,Oe as X,wn as Y,rt as Z,Me as _,ot as $,it as aa,st as ba,at as ca,$r as da,ne as ea,Tn as fa,vn as ga,le as ha,ke as ia,be as ja,Ge as ka,Je as la,An as ma,dt as na,pt as oa,gt as pa,ft as qa,yt as ra,ht as sa,mt as ta,Ce as ua,te as va,kt as wa,qr as xa,Rn as ya,Sn as za,Gr as Aa,bt as Ba,Ct as Ca,wt as Da,Pt as Ea,Tt as Fa,vt as Ga,At as Ha,xt as Ia,Rt as Ja,St as Ka,It as La,_t as Ma,Et as Na,Dt as Oa,Ot as Pa,Zt as Qa,Pe as Ra,go as Sa,fo as Ta,yo as Ua,mo as Va,ws as Wa,Wn as Xa,td as Ya,Te as Za,rd as _a,jn as $a,Ss as ab,So as bb,Is as cb,_s as db,Io as eb,_o as fb,Qe as gb,Es as hb,Eo as ib,Do as jb,Ds as kb,Zn as lb,Os as mb,Ye as nb,Rr as ob};
@@ -1,6 +1,6 @@
1
- import { T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, b as PermissionRecord, c as ConnectLink, d as CreateConnectLinkInput, O as OAuthCallbackResult, e as OAuthCallbackInput } from '../../types-CNagdEGY.js';
2
- export { f as PermissionLookupInput } from '../../types-CNagdEGY.js';
3
- import { C as CorsairClientOptions, a as CorsairManagementClient } from '../../types-DGS4LASW.js';
1
+ import { T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, b as PermissionRecord, c as ConnectLink, d as CreateConnectLinkInput, O as OAuthCallbackResult, e as OAuthCallbackInput } from '../../types-cJXSdmph.js';
2
+ export { f as PermissionLookupInput } from '../../types-cJXSdmph.js';
3
+ import { C as CorsairClientOptions, a as CorsairManagementClient } from '../../types-B2mWx_9M.js';
4
4
  import '../../index-ggMa1Rj6.js';
5
5
  import 'zod';
6
6
  import '../../constants-DnSLjl7e.js';
package/dist/core.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-Beq30pp1.js';
1
+ export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-8JfaxmWD.js';
2
2
  import { CorsairDatabase } from './db.js';
3
- import { A as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './types-DEr-UGKS.js';
4
- export { a as AccountFieldNames, d as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, b as BaseKeyManager, e as Bivariant, c as IntegrationFieldNames, O as OAuth2IntegrationCredentials, P as PluginAuthConfig, U as UnionToIntersection } from './types-DEr-UGKS.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-gB2SaqVO.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-DurEU-12.js';
3
+ import { A as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './types-BZ-KI4kd.js';
4
+ export { a as AccountFieldNames, d as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, b as BaseKeyManager, e as Bivariant, c as IntegrationFieldNames, O as OAuth2IntegrationCredentials, P as PluginAuthConfig, U as UnionToIntersection } from './types-BZ-KI4kd.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-BjEnNYJD.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-DU4saqFg.js';
7
7
  import { A as AuthTypes } from './constants-DnSLjl7e.js';
8
8
  export { a as AllProviders, B as BaseProviders, P as PickAuth, b as ProviderDisplayNames, f as formatProviderDisplayName } from './constants-DnSLjl7e.js';
9
9
  import 'kysely';
@@ -12,7 +12,7 @@ import 'zod';
12
12
  import 'pg';
13
13
  import 'postgres';
14
14
  import './orm.js';
15
- import './types-CNagdEGY.js';
15
+ import './types-cJXSdmph.js';
16
16
 
17
17
  /**
18
18
  * Context interface with account ID resolver for logging events.
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{$a as w,Oa as q,Ta as r,Ua as s,Va as t,Za as u,_a as v,a,ab as x,b,bb as y,cb as z,db as A,eb as B,fb as C,gb as D,hb as E,ib as F,jb as G,kb as H,lb as I,mb as J,n as d,o as e,p as f,q as g,r as h,s as i,t as j,ta as p,u as k,v as l,w as m,x as n,y as o}from"./chunk-RQJN7RGN.js";import{g as c}from"./chunk-FLNFC4KL.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};
1
+ import{$a as u,Qa as q,Va as r,Wa as s,Xa as t,a,ab as v,b,bb as w,cb as x,db as y,eb as z,fb as A,gb as B,hb as C,ib as D,jb as E,kb as F,lb as G,mb as H,nb as I,o as d,ob as J,p as e,q as f,r as g,s as h,t as i,u as j,v as k,va as p,w as l,x as m,y as n,z as o}from"./chunk-BI3ICPNA.js";import{g as c}from"./chunk-FLNFC4KL.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
@@ -1,6 +1,6 @@
1
1
  export { f as formatProviderDisplayName } from './constants-DnSLjl7e.js';
2
- import { g as HubOAuthMode, h as HubConnectSessionResult, i as HubPermissionSessionResult, j as HubConnectSource, H as HubConfig, f as HubConfigInput, k as HubConnectSessionInput, l as HubListProjectConnectionsInput, A as AccountKeyManagerFor, m as HubPermissionSessionInput } from './types-DEr-UGKS.js';
3
- export { D as DEFAULT_HUB_API_URL } from './types-DEr-UGKS.js';
2
+ import { g as HubOAuthMode, h as HubConnectSessionResult, i as HubPermissionSessionResult, H as HubConfig, f as HubConfigInput, j as HubConnectSessionInput, k as HubListProjectConnectionsInput, A as AccountKeyManagerFor, l as HubPermissionSessionInput } from './types-BZ-KI4kd.js';
3
+ export { D as DEFAULT_HUB_API_URL, m as HubEnvironmentSlug } from './types-BZ-KI4kd.js';
4
4
  import { e as TunnelType, c as ProcessCorsairRequest } from './index-LpuBJQ1m.js';
5
5
  export { f as BROWSER_DELIVERY_TTL_MS, g as BrowserDeliveryMode, B as BrowserDeliveryPayload, S as SIGNED_TUNNEL_REPLAY_WINDOW_MS, d as TunnelEnvelope } from './index-LpuBJQ1m.js';
6
6
  export { b as buildBrowserDeliveryRedirectUrl, s as signBrowserDeliveryToken, v as verifyBrowserDeliveryToken } from './browser-delivery-CvBUoA96.js';
@@ -46,8 +46,8 @@ type ConnectStatusResponse = {
46
46
  };
47
47
  type CreateConnectSessionRequestBody = {
48
48
  tenantId: string;
49
- deliveryUrl: string;
50
- source?: 'client' | 'server';
49
+ /** Required for development environment; ignored for production. */
50
+ deliveryUrl?: string;
51
51
  plugins: ConnectPluginManifestEntry[];
52
52
  };
53
53
  type CreatePermissionSessionRequestBody = {
@@ -57,7 +57,8 @@ type CreatePermissionSessionRequestBody = {
57
57
  endpoint: string;
58
58
  args: unknown;
59
59
  tenantId: string;
60
- deliveryUrl: string;
60
+ /** Required for development environment; ignored for production. */
61
+ deliveryUrl?: string;
61
62
  expiresAt: string;
62
63
  };
63
64
  type HubOAuthRefreshResponse = {
@@ -73,18 +74,12 @@ declare function parseOAuthRefreshResponse(payload: unknown): HubOAuthRefreshRes
73
74
  declare function parseConnectStatusResponse(payload: unknown): ConnectStatusResponse;
74
75
  declare function parseHubApiErrorBody(payload: unknown): string | null;
75
76
 
76
- type ConnectSourceValidationError = {
77
- error: string;
78
- status: number;
79
- };
80
- declare function isLoopbackDeliveryUrl(deliveryUrl: string): boolean;
81
- declare function resolveConnectSourceFromDeliveryUrl(deliveryUrl: string): HubConnectSource;
82
- declare function shouldUseBrowserDelivery(source: HubConnectSource, deliveryUrl: string): boolean;
83
- declare function validateExplicitConnectSource(input: {
84
- source?: HubConnectSource;
85
- deliveryUrl: string;
86
- oauthMode?: HubOAuthMode;
87
- }): ConnectSourceValidationError | null;
77
+ type HubEnvironmentSlug = 'development' | 'production';
78
+ type DeliveryTransport = 'browser' | 'server';
79
+ declare function isLoopbackUrl(url: string): boolean;
80
+ declare function resolveDeliveryTransport(slug: HubEnvironmentSlug): DeliveryTransport;
81
+ declare function usesBrowserDelivery(slug: HubEnvironmentSlug): boolean;
82
+ declare function validateProductionDeliveryUrl(deliveryUrl: string): string | null;
88
83
 
89
84
  declare class HubNotConfiguredError extends Error {
90
85
  constructor();
@@ -92,6 +87,7 @@ declare class HubNotConfiguredError extends Error {
92
87
  declare function normalizeHubConfig(input: HubConfigInput): HubConfig;
93
88
  declare function getHubConfig(corsair: unknown): HubConfig;
94
89
  declare function resolveHubOAuthCallbackUrl(config: HubConfig): string;
90
+ declare function inferHubEnvironmentSlug(apiKey: string): 'development' | 'production';
95
91
 
96
92
  declare function createHubConnectSession(corsair: unknown, input: HubConnectSessionInput): Promise<HubConnectSessionResult>;
97
93
 
@@ -101,6 +97,11 @@ declare function getConnectStatusForTenant(corsair: unknown, tenantId: string, o
101
97
 
102
98
  declare function listHubProjectConnections(corsair: unknown, input: HubListProjectConnectionsInput): Promise<HubProjectConnection[]>;
103
99
 
100
+ declare function resolveHubDeliveryUrl(input?: {
101
+ deliveryUrl?: string;
102
+ deliveryPath?: string;
103
+ }): string;
104
+
104
105
  /**
105
106
  * Server (production) delivery — hub POSTs a signed JSON envelope to the app's public delivery URL.
106
107
  *
@@ -313,6 +314,8 @@ type ConnectSessionTokenPayload = {
313
314
  jti: string;
314
315
  /** Corsair project id (`proj_*`). */
315
316
  projectId: string;
317
+ /** Corsair environment id (`env_*`). */
318
+ environmentId: string;
316
319
  /** Tenant being set up. */
317
320
  tenantId: string;
318
321
  /** App delivery endpoint used for credential transfer for this session. */
@@ -368,8 +371,6 @@ type ConnectTokenPayload = {
368
371
  redirectUri: string;
369
372
  /** App delivery endpoint for credential transfer after OAuth completes. */
370
373
  deliveryUrl: string;
371
- /** Whether credentials are delivered via browser redirect or server POST. */
372
- source: HubConnectSource;
373
374
  /** BYO (app holds OAuth app) vs managed (hub holds OAuth app). */
374
375
  oauthMode: HubOAuthMode;
375
376
  /** Unix expiry (seconds). */
@@ -386,7 +387,7 @@ declare function getConnectTokenExpiryMs(): number;
386
387
  */
387
388
  declare function signConnectToken(payload: Omit<ConnectTokenPayload, 'exp' | 'iat'>, signingSecret: string): string;
388
389
  /**
389
- * Verifies a connect OAuth token (e.g. to read `source` and `oauthMode` during callback).
390
+ * Verifies a connect OAuth token (e.g. to read `oauthMode` during callback).
390
391
  */
391
392
  declare function verifyConnectToken(token: string, signingSecret: string): ConnectTokenPayload | null;
392
393
  /** Encodes a connect token for use in a URL path. */
@@ -448,4 +449,4 @@ declare function decodePermissionTokenFromPath(encoded: string): string;
448
449
  */
449
450
  declare function createSignedTokenJti(): string;
450
451
 
451
- 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, HubListProjectConnectionsInput, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, HubPermissionSessionInput, HubPermissionSessionResult, type HubProjectConnection, 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, listHubProjectConnections, normalizeHubConfig, parseConnectSessionResponse, parseConnectStatusResponse, parseHubApiErrorBody, parseOAuthRefreshResponse, parsePermissionSessionResponse, parseProjectConnectionsResponse, parseServerDeliveryAckBody, processManagedOAuthDelivery, resolveConnectSourceFromDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, shouldUseBrowserDelivery, signConnectSessionToken, signConnectToken, signDeliveryEnvelope, signPermissionToken, validateExplicitConnectSource, verifyConnectSessionToken, verifyConnectToken, verifyDeliveryEnvelope, verifyPermissionToken, verifySignedTunnelDelivery };
452
+ export { type ConnectAuthFieldStatus, type ConnectAuthKind, type ConnectAuthStatusLevel, type ConnectPluginManifestEntry, type ConnectSessionTokenPayload, type ConnectStatusPluginEntry, type ConnectStatusResponse, type ConnectTokenPayload, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, HubConfig, HubConfigInput, HubConnectSessionInput, HubConnectSessionResult, type HubDeliveryRequest, type HubDeliveryResult, HubListProjectConnectionsInput, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, HubPermissionSessionInput, HubPermissionSessionResult, type HubProjectConnection, 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, inferHubEnvironmentSlug, isLoopbackUrl, isServerDeliveryAckSuccessful, listHubProjectConnections, normalizeHubConfig, parseConnectSessionResponse, parseConnectStatusResponse, parseHubApiErrorBody, parseOAuthRefreshResponse, parsePermissionSessionResponse, parseProjectConnectionsResponse, parseServerDeliveryAckBody, processManagedOAuthDelivery, resolveDeliveryTransport, resolveHubDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, signConnectSessionToken, signConnectToken, signDeliveryEnvelope, signPermissionToken, usesBrowserDelivery, validateProductionDeliveryUrl, verifyConnectSessionToken, verifyConnectToken, verifyDeliveryEnvelope, verifyPermissionToken, verifySignedTunnelDelivery };
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as C,Aa as U,Ba as V,Ca as W,Da as X,Ea as Y,Fa as Z,Ga as _,Ha as $,Ia as aa,J as m,Ja as ba,K as n,Ka as ca,L as o,La as da,M as p,Ma as ea,Na as fa,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 D,b as a,c as b,ca as E,d as c,da as F,e as d,ea as G,f as e,fa as H,g as f,h as g,i as h,j as i,k as j,l as k,m as l,na as I,oa as J,pa as K,qa as L,ra as M,sa as N,ua as O,va as P,wa as Q,xa as R,ya as S,za as T}from"./chunk-RQJN7RGN.js";import"./chunk-FLNFC4KL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{t as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,v as ManagedOAuthDeliveryError,u as SIGNED_TUNNEL_REPLAY_WINDOW_MS,P as attachManagedRefreshAuth,F as buildBrowserDeliveryRedirectUrl,T as createConnectSessionJti,Y as createConnectTokenJti,q as createHubConnectSession,Q as createHubPermissionSession,S as createHubRouteHandlers,ca as createPermissionSessionJti,E as createSignedTokenJti,X as decodeConnectSessionTokenFromPath,ba as decodeConnectTokenFromPath,fa as decodePermissionTokenFromPath,D as deliverSignedEnvelope,aa as encodeConnectTokenForPath,R as formatHubApprovalMessage,a as formatProviderDisplayName,C as formatServerDeliveryError,U as getConnectSessionExpiryMs,r as getConnectStatusForTenant,Z as getConnectTokenExpiryMs,e as getHubConfig,O as getManagedAccessToken,I as handleHubDeliveryGet,J as handleHubDeliveryPost,L as handleHubDeliveryRequest,K as hubDeliveryToResponse,m as isLoopbackDeliveryUrl,B as isServerDeliveryAckSuccessful,s as listHubProjectConnections,d as normalizeHubConfig,g as parseConnectSessionResponse,k as parseConnectStatusResponse,l as parseHubApiErrorBody,j as parseOAuthRefreshResponse,i as parsePermissionSessionResponse,h as parseProjectConnectionsResponse,A as parseServerDeliveryAckBody,w as processManagedOAuthDelivery,n as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,M as respondToHubDelivery,N as respondToHubDeliveryFromRequest,o as shouldUseBrowserDelivery,G as signBrowserDeliveryToken,V as signConnectSessionToken,_ as signConnectToken,x as signDeliveryEnvelope,da as signPermissionToken,p as validateExplicitConnectSource,H as verifyBrowserDeliveryToken,W as verifyConnectSessionToken,$ as verifyConnectToken,y as verifyDeliveryEnvelope,ea as verifyPermissionToken,z as verifySignedTunnelDelivery};
1
+ import{$ as C,Aa as U,Ba as V,Ca as W,Da as X,Ea as Y,Fa as Z,Ga as _,Ha as $,Ia as aa,Ja as ba,Ka as ca,La as da,M as n,Ma as ea,N as o,Na as fa,O as p,Oa as ga,P as q,Pa as ha,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 D,b as a,ba as E,c as b,ca as F,d as c,e as d,ea as G,f as e,fa as H,g as f,ga as I,h as g,ha as J,i as h,j as i,k as j,l as k,m as l,n as m,pa as K,qa as L,ra as M,sa as N,ta as O,ua as P,wa as Q,xa as R,ya as S,za as T}from"./chunk-BI3ICPNA.js";import"./chunk-FLNFC4KL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{v as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,x as ManagedOAuthDeliveryError,w as SIGNED_TUNNEL_REPLAY_WINDOW_MS,R as attachManagedRefreshAuth,H as buildBrowserDeliveryRedirectUrl,V as createConnectSessionJti,_ as createConnectTokenJti,o as createHubConnectSession,S as createHubPermissionSession,U as createHubRouteHandlers,ea as createPermissionSessionJti,G as createSignedTokenJti,Z as decodeConnectSessionTokenFromPath,da as decodeConnectTokenFromPath,ha as decodePermissionTokenFromPath,F as deliverSignedEnvelope,ca as encodeConnectTokenForPath,T as formatHubApprovalMessage,a as formatProviderDisplayName,E as formatServerDeliveryError,W as getConnectSessionExpiryMs,p as getConnectStatusForTenant,$ as getConnectTokenExpiryMs,e as getHubConfig,Q as getManagedAccessToken,K as handleHubDeliveryGet,L as handleHubDeliveryPost,N as handleHubDeliveryRequest,M as hubDeliveryToResponse,g as inferHubEnvironmentSlug,r as isLoopbackUrl,D as isServerDeliveryAckSuccessful,q as listHubProjectConnections,d as normalizeHubConfig,h as parseConnectSessionResponse,l as parseConnectStatusResponse,m as parseHubApiErrorBody,k as parseOAuthRefreshResponse,j as parsePermissionSessionResponse,i as parseProjectConnectionsResponse,C as parseServerDeliveryAckBody,y as processManagedOAuthDelivery,s as resolveDeliveryTransport,n as resolveHubDeliveryUrl,f as resolveHubOAuthCallbackUrl,O as respondToHubDelivery,P as respondToHubDeliveryFromRequest,I as signBrowserDeliveryToken,X as signConnectSessionToken,aa as signConnectToken,z as signDeliveryEnvelope,fa as signPermissionToken,t as usesBrowserDelivery,u as validateProductionDeliveryUrl,J as verifyBrowserDeliveryToken,Y as verifyConnectSessionToken,ba as verifyConnectToken,A as verifyDeliveryEnvelope,ga as verifyPermissionToken,B as verifySignedTunnelDelivery};
@@ -1,6 +1,6 @@
1
1
  import { CorsairDatabase } from './db.js';
2
- import { H as HubConfig } from './types-DEr-UGKS.js';
3
- import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-gB2SaqVO.js';
2
+ import { H as HubConfig } from './types-BZ-KI4kd.js';
3
+ import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-BjEnNYJD.js';
4
4
 
5
5
  declare const CORSAIR_INTERNAL: unique symbol;
6
6
  type CorsairInternalConfig = {
@@ -2,8 +2,8 @@ import { ZodTypeAny } from 'zod';
2
2
  import { CorsairDatabase, CorsairDatabaseInput } from './db.js';
3
3
  import { CorsairPluginSchema, PluginEntityClients } from './orm.js';
4
4
  import { c as AllErrors, A as AuthTypes, a as AllProviders } from './constants-DnSLjl7e.js';
5
- import { A as AccountKeyManagerFor, P as PluginAuthConfig, I as IntegrationKeyManagerFor, H as HubConfig, f as HubConfigInput } from './types-DEr-UGKS.js';
6
- import { M as ManagementOk, T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, f as PermissionLookupInput, b as PermissionRecord, d as CreateConnectLinkInput, c as ConnectLink, R as ResolvedConnectLink, e as OAuthCallbackInput, O as OAuthCallbackResult } from './types-CNagdEGY.js';
5
+ import { A as AccountKeyManagerFor, P as PluginAuthConfig, I as IntegrationKeyManagerFor, H as HubConfig, f as HubConfigInput } from './types-BZ-KI4kd.js';
6
+ import { M as ManagementOk, T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, f as PermissionLookupInput, b as PermissionRecord, d as CreateConnectLinkInput, c as ConnectLink, R as ResolvedConnectLink, e as OAuthCallbackInput, O as OAuthCallbackResult } from './types-cJXSdmph.js';
7
7
  import { a as CorsairPermission } from './index-ggMa1Rj6.js';
8
8
 
9
9
  /**
package/dist/index.d.ts CHANGED
@@ -1,22 +1,22 @@
1
- import { C as CorsairClientOptions, a as CorsairManagementClient } from './types-DGS4LASW.js';
2
- export { b as CorsairClientError } from './types-DGS4LASW.js';
3
- export { c as createCorsair } from './index-Beq30pp1.js';
4
- import { 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-gB2SaqVO.js';
5
- export { a3 as CorsairManageNamespace, b as CorsairManualConfig, a as CorsairPermissionsOptions } from './index-gB2SaqVO.js';
6
- import { F as FormFieldSchema, L as ListOperationsOptions } from './tenant-match-utils-DurEU-12.js';
7
- export { A as AuthMissingError, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, o as firstString, f as formatDocSchemaShape, p as getHeader, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-DurEU-12.js';
1
+ import { C as CorsairClientOptions, a as CorsairManagementClient } from './types-B2mWx_9M.js';
2
+ export { b as CorsairClientError } from './types-B2mWx_9M.js';
3
+ export { c as createCorsair } from './index-8JfaxmWD.js';
4
+ import { 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-BjEnNYJD.js';
5
+ export { a3 as CorsairManageNamespace, b as CorsairManualConfig, a as CorsairPermissionsOptions } from './index-BjEnNYJD.js';
6
+ import { F as FormFieldSchema, L as ListOperationsOptions } from './tenant-match-utils-DU4saqFg.js';
7
+ export { A as AuthMissingError, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, o as firstString, f as formatDocSchemaShape, p as getHeader, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-DU4saqFg.js';
8
8
  export { SetupCorsairOptions, setupCorsair } from './setup.js';
9
9
  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';
10
10
  import { B as BaseProviders } from './constants-DnSLjl7e.js';
11
- export { R as ResolveAccountFromWebhookLinkInput, W as WebhookTenantLink, r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-BTqtHnSW.js';
12
- export { c as ConnectLink, a as ConnectionStatus, d as CreateConnectLinkInput, C as CreateTenantInput, M as ManagementOk, e as OAuthCallbackInput, O as OAuthCallbackResult, f as PermissionLookupInput, b as PermissionRecord, g as PluginConnectionState, P as PluginInfo, R as ResolvedConnectLink, T as Tenant } from './types-CNagdEGY.js';
11
+ export { R as ResolveAccountFromWebhookLinkInput, W as WebhookTenantLink, r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-CZFbUeH1.js';
12
+ export { c as ConnectLink, a as ConnectionStatus, d as CreateConnectLinkInput, C as CreateTenantInput, M as ManagementOk, e as OAuthCallbackInput, O as OAuthCallbackResult, f as PermissionLookupInput, b as PermissionRecord, g as PluginConnectionState, P as PluginInfo, R as ResolvedConnectLink, T as Tenant } from './types-cJXSdmph.js';
13
13
  import './db.js';
14
14
  import 'kysely';
15
15
  import './index-ggMa1Rj6.js';
16
16
  import 'zod';
17
17
  import 'pg';
18
18
  import 'postgres';
19
- import './types-DEr-UGKS.js';
19
+ import './types-BZ-KI4kd.js';
20
20
  import './orm.js';
21
21
 
22
22
  type ManagementHandlerOptions = {
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{a as N,b as j}from"./chunk-XLNT2UI2.js";import{$a as L,B as y,C as h,D as k,E as x,N as P,Oa as I,Pa as O,Qa as R,Ra as T,Sa as A,Wa as l,Xa as c,Ya as d,Za as m,ab as W,ba as b,bb as F,cb as v,db as E,eb as _,fb as $,jb as M,kb as D,lb as g,ma as S,mb as H,ta as w}from"./chunk-RQJN7RGN.js";import"./chunk-FLNFC4KL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";function s(n){let t=n[g];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function B(n,t){let r=c(s(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
1
+ import{a as N,b as j}from"./chunk-XLNT2UI2.js";import{$a as m,C as y,D as h,E as k,F as x,K as P,Qa as I,Ra as O,Sa as R,Ta as T,Ua as A,Ya as l,Za as c,_a as d,bb as L,cb as W,da as b,db as F,eb as v,fb as E,gb as _,hb as $,lb as M,mb as D,nb as g,oa as S,ob as H,va as w}from"./chunk-BI3ICPNA.js";import"./chunk-FLNFC4KL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";function s(n){let t=n[g];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function B(n,t){let r=c(s(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
2
2
  `):Object.values(r).flat().join(`
3
3
  `)}function J(n,t){return d(s(n),t)}function q(n,t){return l(s(n),t)}var Y=Symbol.for("corsair:internal");function z(n,t){let r=n;for(let e of t){if(!r||typeof r!="object")return null;r=r[e]}return typeof r=="function"?r:null}function C(n){return n[Y]?.database}async function G(n,t){let r=new Date().toISOString(),e=await n.permissions.find_by_token(t);if(!e)return console.error("executePermission: no permission found for token."),{error:"executePermission: no permission found for token."};if(e.status!=="approved")return console.error(`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`};if(e.expires_at<r){let o=C(n);return o&&await o.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",e.id).execute(),console.error(`executePermission: permission '${e.id}' has expired.`),{error:`executePermission: permission '${e.id}' has expired.`,endpoint:e.endpoint,plugin:e.plugin,result:null}}let f=e.tenant_id??"default",a=(n.withTenant?n.withTenant(f):n)[e.plugin];if(!a?.api)return console.error(`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`),{error:`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`,plugin:e.plugin,endpoint:e.endpoint,result:null};let p=z(a.api,e.endpoint.split("."));if(!p)return console.error(`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`};await n.permissions.set_executing(e.id);try{let o=typeof e.args=="string"?JSON.parse(e.args):e.args,i=await p(o);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:i}}catch(o){let i=o instanceof Error?o.message:String(o),u=C(n);return u&&await u.db.updateTable("corsair_permissions").set({status:"failed",error:i,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:i}}}export{w as AuthMissingError,N as CorsairClientError,_ as asRecord,F as collectPluginWebhookMatchers,H as createCorsair,j as createCorsairClient,D as decodePubSubData,G as executePermission,M as firstString,m as formatDocSchemaShape,v as getHeader,J as getSchema,q as getStructuredSchema,B as listOperations,O as managementHandler,L as matchWebhookPlugin,W as matchWebhookPluginAndTenant,S as processCorsair,b as processWebhook,$ as readBodyRecord,h as resolveAccountFromWebhookLink,I as resolveConnectLink,x as resolveTenantFromWebhookLink,k as resolveTenantIdFromWebhookLink,y as setWebhookTenantLink,P as setupCorsair,R as toExpressHandler,E as toExternalId,T as toHonoHandler,A as toNextJsHandler};
package/dist/oauth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { O as OAuthConfig } from './index-gB2SaqVO.js';
1
+ import { O as OAuthConfig } from './index-BjEnNYJD.js';
2
2
  import 'zod';
3
3
  import './db.js';
4
4
  import 'kysely';
@@ -7,8 +7,8 @@ import 'pg';
7
7
  import 'postgres';
8
8
  import './orm.js';
9
9
  import './constants-DnSLjl7e.js';
10
- import './types-DEr-UGKS.js';
11
- import './types-CNagdEGY.js';
10
+ import './types-BZ-KI4kd.js';
11
+ import './types-cJXSdmph.js';
12
12
 
13
13
  type OAuthState = {
14
14
  plugin: string;
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{A as b,F as c,G as d,H as e,I as f,z as a}from"./chunk-RQJN7RGN.js";import"./chunk-FLNFC4KL.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{A as a,B as b,G as c,H as d,I as e,J as f}from"./chunk-BI3ICPNA.js";import"./chunk-FLNFC4KL.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,7 +1,7 @@
1
- import { a as CorsairInternalConfig } from './index-Beq30pp1.js';
1
+ import { a as CorsairInternalConfig } from './index-8JfaxmWD.js';
2
2
  import { CorsairDatabase } from './db.js';
3
- import { C as CorsairPlugin, e as CorsairSingleTenantClient, d as CorsairTenantWrapper } from './index-gB2SaqVO.js';
4
- import './types-DEr-UGKS.js';
3
+ import { C as CorsairPlugin, e as CorsairSingleTenantClient, d as CorsairTenantWrapper } from './index-BjEnNYJD.js';
4
+ import './types-BZ-KI4kd.js';
5
5
  import './constants-DnSLjl7e.js';
6
6
  import 'kysely';
7
7
  import './index-ggMa1Rj6.js';
@@ -9,7 +9,7 @@ import 'zod';
9
9
  import 'pg';
10
10
  import 'postgres';
11
11
  import './orm.js';
12
- import './types-CNagdEGY.js';
12
+ import './types-cJXSdmph.js';
13
13
 
14
14
  /** Plugin id → credential field → value (from CLI `field=value` pairs). */
15
15
  type SetupCredentials = Record<string, Record<string, string>>;
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{N as a,O as b}from"./chunk-RQJN7RGN.js";import"./chunk-FLNFC4KL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{K as a,L as b}from"./chunk-BI3ICPNA.js";import"./chunk-FLNFC4KL.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 './constants-DnSLjl7e.js';
2
- import { W as WebhookTenantMatch } from './index-gB2SaqVO.js';
2
+ import { W as WebhookTenantMatch } from './index-BjEnNYJD.js';
3
3
  import { C as CorsairAccount } from './index-ggMa1Rj6.js';
4
4
  import { CorsairDatabase } from './db.js';
5
5
 
@@ -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-gB2SaqVO.js';
1
+ import { D as EndpointRiskLevel, C as CorsairPlugin, Y as CorsairWebhookMatcher, Z as CorsairWebhookTenantMatcher, _ as RawWebhookRequest, W as WebhookTenantMatch } from './index-BjEnNYJD.js';
2
2
  import { a as AllProviders } from './constants-DnSLjl7e.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-BTqtHnSW.js';
3
+ export { r as resolveAccountFromWebhookLink, a as resolveTenantFromWebhookLink, b as resolveTenantIdFromWebhookLink, s as setWebhookTenantLink } from './tenant-links-CZFbUeH1.js';
4
4
  export { v as verifyBrowserDeliveryToken } from './browser-delivery-CvBUoA96.js';
5
5
  import './constants-DnSLjl7e.js';
6
- import './index-gB2SaqVO.js';
6
+ import './index-BjEnNYJD.js';
7
7
  import 'zod';
8
8
  import './db.js';
9
9
  import 'kysely';
@@ -11,8 +11,8 @@ import './index-ggMa1Rj6.js';
11
11
  import 'pg';
12
12
  import 'postgres';
13
13
  import './orm.js';
14
- import './types-DEr-UGKS.js';
15
- import './types-CNagdEGY.js';
14
+ import './types-BZ-KI4kd.js';
15
+ import './types-cJXSdmph.js';
16
16
 
17
17
  declare function isConnectStatusBrowserDelivery(payload: BrowserDeliveryPayload): boolean;
18
18
  declare function isAuthCredentialsBrowserDelivery(payload: BrowserDeliveryPayload): boolean;
package/dist/tunnel.js CHANGED
@@ -1 +1 @@
1
- import{B as a,C as b,D as c,E as d,fa as e,ga as f,ha as g,ia as h,ja as i,ka as j,la as k,ma as l}from"./chunk-RQJN7RGN.js";import"./chunk-FLNFC4KL.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{C as a,D as b,E as c,F 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-BI3ICPNA.js";import"./chunk-FLNFC4KL.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,4 +1,4 @@
1
- import { M as ManagementOk, T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, f as PermissionLookupInput, b as PermissionRecord, d as CreateConnectLinkInput, c as ConnectLink, R as ResolvedConnectLink, e as OAuthCallbackInput, O as OAuthCallbackResult } from './types-CNagdEGY.js';
1
+ import { M as ManagementOk, T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, f as PermissionLookupInput, b as PermissionRecord, d as CreateConnectLinkInput, c as ConnectLink, R as ResolvedConnectLink, e as OAuthCallbackInput, O as OAuthCallbackResult } from './types-cJXSdmph.js';
2
2
 
3
3
  type CorsairClientOptions = {
4
4
  /** Origin + base path of the mounted handler, e.g. 'https://api.example.com/api/corsair'. */
@@ -1,12 +1,11 @@
1
1
  import { A as AuthTypes } from './constants-DnSLjl7e.js';
2
2
 
3
- type HubConnectSource = 'client' | 'server';
3
+ type HubEnvironmentSlug = 'development' | 'production';
4
4
  type HubOAuthMode = 'byo' | 'managed';
5
5
  declare const DEFAULT_HUB_API_URL = "https://auth.corsair.dev";
6
6
  type HubConfigInput = {
7
7
  projectApiKey: string;
8
8
  signingSecret: string;
9
- deliveryUrl: string;
10
9
  apiUrl?: string;
11
10
  oauthCallbackUrl?: string;
12
11
  };
@@ -14,15 +13,14 @@ type HubConfig = {
14
13
  apiUrl: string;
15
14
  projectApiKey: string;
16
15
  signingSecret: string;
17
- deliveryUrl: string;
18
16
  oauthCallbackUrl?: string;
19
17
  };
20
18
  type HubConnectSessionInput = {
21
19
  /** When omitted, the connect link covers all configured plugins. */
22
20
  plugin?: string;
23
21
  tenantId: string;
24
- /** Inferred from hub deliveryUrl when omitted (loopback → client, else server). */
25
- source?: HubConnectSource;
22
+ /** Override auto-detected delivery URL (development only). */
23
+ deliveryUrl?: string;
26
24
  providerName?: string;
27
25
  oauthMode?: HubOAuthMode;
28
26
  };
@@ -30,6 +28,7 @@ type HubConnectSessionResult = {
30
28
  connectUrl: string;
31
29
  token: string;
32
30
  projectId: string;
31
+ environmentId: string;
33
32
  expiresAt?: string;
34
33
  };
35
34
  type HubListProjectConnectionsInput = {
@@ -43,6 +42,7 @@ type HubPermissionSessionInput = {
43
42
  args: unknown;
44
43
  tenantId: string;
45
44
  expiresAt: string;
45
+ deliveryUrl?: string;
46
46
  };
47
47
  type HubPermissionSessionResult = {
48
48
  approvalUrl: string;
@@ -184,4 +184,4 @@ type AccountKeyManagerFor<T extends AuthTypes, Config extends PluginAuthConfig |
184
184
  get_integration_credentials: () => Promise<OAuth2IntegrationCredentials>;
185
185
  } : {});
186
186
 
187
- export { type AccountKeyManagerFor as A, type BaseAuthFieldConfig as B, DEFAULT_HUB_API_URL as D, type HubConfig as H, type IntegrationKeyManagerFor as I, type OAuth2IntegrationCredentials as O, type PluginAuthConfig as P, type UnionToIntersection as U, type AccountFieldNames as a, type BaseKeyManager as b, type IntegrationFieldNames as c, BASE_AUTH_FIELDS as d, type Bivariant as e, type HubConfigInput as f, type HubOAuthMode as g, type HubConnectSessionResult as h, type HubPermissionSessionResult as i, type HubConnectSource as j, type HubConnectSessionInput as k, type HubListProjectConnectionsInput as l, type HubPermissionSessionInput as m };
187
+ export { type AccountKeyManagerFor as A, type BaseAuthFieldConfig as B, DEFAULT_HUB_API_URL as D, type HubConfig as H, type IntegrationKeyManagerFor as I, type OAuth2IntegrationCredentials as O, type PluginAuthConfig as P, type UnionToIntersection as U, type AccountFieldNames as a, type BaseKeyManager as b, type IntegrationFieldNames as c, BASE_AUTH_FIELDS as d, type Bivariant as e, type HubConfigInput as f, type HubOAuthMode as g, type HubConnectSessionResult as h, type HubPermissionSessionResult as i, type HubConnectSessionInput as j, type HubListProjectConnectionsInput as k, type HubPermissionSessionInput as l, type HubEnvironmentSlug as m };
@@ -43,8 +43,6 @@ type CreateConnectLinkInput = {
43
43
  tenantId?: string;
44
44
  /** Hub mode only — BYO uses your OAuth app; managed uses Corsair's. */
45
45
  oauthMode?: 'byo' | 'managed';
46
- /** Hub mode only — inferred from deliveryUrl when omitted. */
47
- source?: 'client' | 'server';
48
46
  /** Hub mode only — override the provider display name. */
49
47
  providerName?: string;
50
48
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.93",
3
+ "version": "0.1.94",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,38 +0,0 @@
1
- import{a as ie,b as tr,c as T,d as $,e as rr,f as J,g as E,h as F,i as en,j as or,k as Gn,l as ir,m as sr}from"./chunk-FLNFC4KL.js";import{a as nr}from"./chunk-IGGCNGU2.js";var nn=["agentql","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"],ar={agentql:"AgentQL",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 se(e){let n=ar[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var $e="https://auth.corsair.dev";var ye=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()||$e).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 Eo(e){return e.apiUrl.trim().length>0&&e.deliveryUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function D(e){let n=T(e).hub;if(!n||!Eo(n))throw new ye;return n}function rn(e){return e.oauthCallbackUrl?e.oauthCallbackUrl:`${e.apiUrl.replace(/\/$/,"")}/oauth/callback`}function A(e){return typeof e=="string"&&e.length>0}function Do(e){return e==="pending"||e==="connected"||e==="failed"}function Oo(e){return e==="oauth"||e==="api_key"||e==="bot_token"}function on(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!A(n.connectUrl)||!A(n.token)||!A(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 A(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function sn(e){if(!Array.isArray(e))throw new Error("Hub API returned an invalid connections response (expected array)");let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;!A(r.tenantId)||!A(r.plugin)||!Do(r.status)||!Oo(r.authKind)||n.push({tenantId:r.tenantId,plugin:r.plugin,status:r.status,authKind:r.authKind,connectedAt:A(r.connectedAt)?r.connectedAt:null,expiresAt:A(r.expiresAt)?r.expiresAt:null})}return n}function an(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!A(n.approvalUrl)||!A(n.token)||!A(n.projectId)||!A(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 un(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(A(n.access_token))return{access_token:n.access_token,refresh_token:A(n.refresh_token)?n.refresh_token:void 0,expires_in:(()=>{if(typeof n.expires_in=="number")return n.expires_in;if(typeof n.expires_in=="string"&&n.expires_in.trim().length>0){let t=Number(n.expires_in);return Number.isFinite(t)?t:void 0}})(),scope:A(n.scope)?n.scope:void 0};throw new Error(A(n.error)?A(n.error_description)?n.error_description:n.error:"Hub token refresh returned no access_token")}function Mo(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function Ho(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;A(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 Fo(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 ur(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!A(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(!A(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=Ho(i.fields),s=Mo(i.missingRequiredFields),u=Fo(i.status,i.connected,a,s);t.push({plugin:i.plugin,providerName:A(i.providerName)?i.providerName:i.plugin,authKind:o,status:u,connected:i.connected,fields:a,missingRequiredFields:s})}return{tenantId:n.tenantId,plugins:t}}function cn(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}function cr(e){return e.replace(/\/$/,"")}async function lr(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 dr(e,n,t){if(n===404&&t)return t;let r=cn(e);return r||`Hub API returned HTTP ${n}`}async function xe(e){let n=cr(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 lr(t);if(!t.ok)throw new Error(dr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function pr(e){let n=cr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`}}),r=await lr(t);if(!t.ok)throw new Error(dr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as gr,createDecipheriv as fr,randomBytes as ln,scrypt as Uo}from"crypto";import{promisify as Bo}from"util";var yr=Bo(Uo),dn="aes-256-gcm",hr=12,pn=16,No=16,Le=32;function X(){return ln(Le).toString("base64")}async function ee(e,n){let t=ln(No),r=await yr(n,t,Le),i=ln(hr),o=gr(dn,r,i,{authTagLength:pn}),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"),l=Buffer.from(o,"base64"),d=await yr(n,a,Le),c=fr(dn,d,s,{authTagLength:pn});return c.setAuthTag(u),Buffer.concat([c.update(l),c.final()]).toString("utf8")}function Jn(e,n){let t=Buffer.from(n,"base64"),r=ln(hr),i=gr(dn,t,r,{authTagLength:pn}),o=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[r.toString("base64"),a.toString("base64"),o.toString("base64")].join(":")}function We(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"),l=fr(dn,o,a,{authTagLength:pn});return l.setAuthTag(s),Buffer.concat([l.update(u),l.final()]).toString("utf8")}function ae(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=Jn(i,n);return t}function ne(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=We(i,n);return t}function je(e,n,t){let r=ne(e,n);return ae(r,t)}function mr(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 zn=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 f=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!f)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return s={id:f.id,config:zn(f.config),dek:f.dek??null},s},updateIntegration:async f=>{let y=await u.getIntegration();await i.db.updateTable("corsair_integrations").set({...f.config!==void 0?{config:f.config}:{},...f.dek!==void 0?{dek:f.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),s=null}},l=null,d=async()=>{if(l)return l;let f=await u.getIntegration();if(!f.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return l=await L(f.dek,r),l},c=async()=>{let f=await u.getIntegration(),y=await d(),h=f.config;return!h||Object.keys(h).length===0?{}:ne(h,y)};return{get_dek:d,issue_new_dek:async()=>{let f=await u.getIntegration(),y=X(),h={};if(f.dek){let C=await L(f.dek,r),b=f.config;b&&Object.keys(b).length>0&&(h=je(b,C,y))}let m=await ee(y,r);return await u.updateIntegration({config:h,dek:m}),l=y,y},...mr(c,async f=>{let y=await d(),h;try{h=await c()}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(f))k===null?delete m[b]:m[b]=k;let C=ae(m,y);await u.updateIntegration({config:C})},a)}}function R(e){let{authType:n,integrationName:t,tenantId:r,kek:i,database:o,extraAccountFields:a=[]}=e,s=[...E[n].account,...a],u=null,l=null,d=async()=>{if(l)return l;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 l={id:k.id,config:zn(k.config),dek:k.dek??null},l},c={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:zn(w.config),dek:w.dek??null},u},updateAccount:async k=>{let w=await c.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,g=null,f=async()=>{if(p)return p;let k=await c.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(g)return g;let k=await c.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return g=await L(k.dek,i),g},h=async()=>{let k=await c.getAccount(),w=await f(),P=k.config;return!P||Object.keys(P).length===0?{}:ne(P,w)},m=async()=>{let k=await c.getIntegration(),w=await y(),P=k.config;return!P||Object.keys(P).length===0?{}:ne(P,w)},b={get_dek:f,issue_new_dek:async()=>{let k=await c.getAccount(),w=X(),P={};if(k.dek){let M=await L(k.dek,i),H=k.config;H&&Object.keys(H).length>0&&(P=je(H,M,w))}let O=await ee(w,i);return await c.updateAccount({config:P,dek:O}),p=w,w},...mr(h,async k=>{let w=await f(),P;try{P=await h()}catch(H){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,H),P={}}let O={...P};for(let[H,x]of Object.entries(k))x===null?delete O[H]:O[H]=x;let M=ae(O,w);await c.updateAccount({config:M})},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 kr(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=X(),o=await ee(i,t);return await e.db.updateTable("corsair_integrations").set({dek:o,updated_at:new Date}).where("id","=",r.id).execute(),i}async function br(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=X(),s=await ee(a,r);return await e.db.updateTable("corsair_accounts").set({dek:s,updated_at:new Date}).where("id","=",o.id).execute(),a}var $o=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function Se(e){return $o.has(e)}function Lo(e,n){return Se(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function Wo(e){return!Se(e)}function jo(e){switch(e){case"oauth_2":case"managed":return["access_token","refresh_token"];case"api_key":return["api_key"];case"bot_token":return["bot_token"]}}function Ko(e,n){return jo(e).every(r=>n.find(o=>o.level==="account"&&o.name===r)?.configured??!1)}async function Cr(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 qo(e,n){let r=e.authConfig?.[n]?.integration??[];return[...E[n].integration,...r]}function Zo(e,n){let r=e.authConfig?.[n]?.account??[];return[...E[n].account,...r]}function Go(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:Ko(n,t),fields:t,missingRequiredFields:r}}async function gn(e,n,t){let r=F(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}),l=R({authType:r,integrationName:n.id,tenantId:i,kek:e.kek,database:e.database,extraAccountFields:s}),d=qo(n,r),c=Zo(n,r),p=[];for(let g of d)p.push({name:g,level:"integration",required:Lo(r,g),configured:await Cr(u,g)});for(let g of c)p.push({name:g,level:"account",required:Wo(g),configured:await Cr(l,g)});return Go(n.id,r,p)}async function Ke(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 gn(e,a,r);s&&o.push(s)}return o}function fn(e){return e.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}var Jo=new Set(["localhost","127.0.0.1","[::1]","::1"]);function qe(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Jo.has(n)}catch{return!1}}function Re(e){return qe(e)?"client":"server"}function wr(e,n){return e==="client"||qe(n)}function Ie(e){if(!e.source)return null;let n=qe(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 Vo,ZodDate as Yo,ZodEnum as Qo,ZodNullable as Xo,ZodNumber as ei,ZodObject as ni,ZodOptional as ti,ZodRecord as ri,ZodString as oi,ZodType as ii}from"zod";var zo={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:{}}}},Vn=zo;async function Tr(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=tr(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=ai(e,a.plugins,n),u={...a,database:a.database},l=u.database.db;await li(l,i);let d=await di(l,u,s.tenantId,s.provisionAccounts,r);n?.credentials&&Object.keys(n.credentials).length>0&&await fi(e,s,n.credentials,u,r,i);let c=await hi(d,s,r,o);if(n?.backfill){r("[corsair:setup] Starting backfill...");let p=vr({plugins:a.plugins,database:l,kek:a.kek,multiTenancy:!0}).withTenant(s.tenantId);await mi(p,a.plugins,c,r,i),r("[corsair:setup] Backfill complete.")}return t.join(`
2
- `)}function Yn(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...E[n][t],...r])}function si(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=F(i);if(!o)continue;let a=Yn(i,o,"account");for(let s of Object.keys(r))if(a.has(s))return!0}return!1}function ai(e,n,t){let r=rr(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&&si(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 Ar(e,n){return ie(e)?n===0?!0:Object.values(e).every(t=>Ar(t,n-1)):!1}function ui(e){return Ar(e,4)}var ci={...ir};function yn(e){if(e instanceof ni){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof ii?yn(r):"unknown";return n}return e instanceof Xo?`${yn(e.unwrap())} | null`:e instanceof ti?`${yn(e.unwrap())} | undefined`:e instanceof Qo?e.options.join(" | "):e instanceof oi?"string":e instanceof ei?"number":e instanceof Vo?"boolean":e instanceof Yo?"date":e instanceof ri?"jsonb":"unknown"}async function li(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(i=>i.name));for(let[i,o]of Object.entries(ci))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 di(e,n,t,r,i){let o=new Date,a=new Map;for(let s of n.plugins){let u=s.id,l=F(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 c=l?s.authConfig?.[l]?.integration??[]:[],p=l?s.authConfig?.[l]?.account??[]:[],g=l&&d?I({authType:l,integrationName:u,kek:n.kek,database:n.database,extraIntegrationFields:c}):void 0;if(d&&!d.dek&&g&&(await g.issue_new_dek(),i(`[corsair:setup] Issued integration DEK: ${u}`)),!d||!l||!g)continue;let f;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}`)}f=y&&R({authType:l,integrationName:u,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:p}),y&&f&&!y.dek&&(await f.issue_new_dek(),i(`[corsair:setup] Issued account DEK: ${u}`))}a.set(u,{pluginId:u,authType:l,integration:g,account:f,integrationFields:[...E[l].integration,...c],accountFields:r?[...E[l].account,...p]:[]})}return a}function pi(e){if(!ie(e))return;let n=e.keys;return ie(n)?n:void 0}function gi(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function fi(e,n,t,r,i,o){let a=pi(e),s=n.provisionAccounts?gi(e,n.tenantId):void 0;for(let[u,l]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 c=F(d);if(!c){o(`[corsair:setup] Plugin '${u}' has no auth type \u2014 skipping credentials.`);continue}let p=Yn(d,c,"integration"),g=Yn(d,c,"account"),f=a?.[u],y=s?.[u],h=ie(y)?y.keys:void 0;for(let[m,C]of Object.entries(l))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(f,`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(g.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 Pr=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function yi(e,n,t,r,i,o,a,s,u){let l=[],d=[];for(let p of i){if(Pr.has(p))continue;let g=J(t,`get_${p}`);if(!g)continue;let f=null;try{let y=await g();f=typeof y=="string"?y:null}catch{}f||l.push(p)}if(r&&o.length>0)for(let p of o){if(Pr.has(p))continue;let g=J(r,`get_${p}`);if(!g)continue;let f=null;try{let y=await g();f=typeof y=="string"?y:null}catch{}f||d.push(p)}let c=l.length===0&&d.length===0;if(c)s(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else if(n==="managed")s(`[corsair:setup] '${e}' (managed) is not connected yet. Use Connect in your app \u2014 Corsair Hub delivers OAuth tokens after authorization.`);else{let p=[...l,...d];if(u==="cli"){let g=p.map(f=>`${f}=VALUE`).join(" ");s(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
- corsair setup --${e} ${g}`)}else{let g=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let f of l)g.push(` await corsair.keys.${e}.set_${f}(value)`);for(let f of d){let y=a.provisionAccounts?a.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(a.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;g.push(` await ${y}.keys.set_${f}(value)`)}s(g.join(`
5
- `))}}return c}async function hi(e,n,t,r){let i=new Set;for(let o of e.values())await yi(o.pluginId,o.authType,o.integration,o.account,o.integrationFields,o.accountFields,n,t,r)&&i.add(o.pluginId);return i}async function mi(e,n,t,r,i){if(!ui(Vn)){i("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let o=Vn,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 l=ie(e)?e[s]:void 0,d=ie(l)?l.api:void 0;if(d)for(let[c,p]of Object.entries(u))for(let[g,f]of Object.entries(p)){r(`[corsair:setup] Backfilling ${s} \u203A ${c}.${g}...`);try{let y=ie(d)?d[c]:void 0;await J(y,g)?.(f)}catch(y){i(`[corsair:setup] ${s} \u203A ${c}.${g} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function _e(e,n){if(!T(e).database)throw new Error("A database must be configured to provision Corsair for connect");await Tr(e,{tenantId:n})}var ki=new Set(["access_token","refresh_token","expires_at","scope"]);function bi(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function Ci(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!Se(t)&&!ki.has(t)):n.filter(t=>!Se(t))}async function xr(e,n,t={}){let r=T(e),i=D(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 l=F(u);if(!l)continue;let d=bi(l),c=t.providerNameOverrides?.[u.id]??se(u.id),p=await gn(r,u,n),g=en(u,l),f=Ci(l,g),y={plugin:u.id,providerName:c,authKind:d,alreadyConfigured:p?.connected??!1};if(f.length>0&&(y.credentialFields=f),d==="oauth"){let m=t.oauthModeOverrides?.[u.id]??(l==="managed"?"managed":"byo");if(y.oauthMode=m,!t.skipOAuthUrlGeneration&&m!=="managed")try{let C=await Qn(e,u.id,{tenantId:n,redirectUri:o,hubConnect:!0});y.oauthUrl=C.url}catch(C){y.setupError=C instanceof Error?C.message:`Could not prepare OAuth for ${u.id}`}}a.push(y)}return a}function Sr(e,n){let t=D(e);if(n){let r=Ie({source:n,deliveryUrl:t.deliveryUrl});if(r)throw new Error(r.error);return n}return Re(t.deliveryUrl)}async function Rr(e,n){await _e(e,n)}async function hn(e,n){let t=D(e);await Rr(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 xr(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=Sr(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:s,plugins:a},parseResponse:on})}function Ir(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function wi(e,n){return n&&!n.has(e.id)?!1:F(e)!==null}async function Ee(e,n,t={}){let r=T(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,a=await Ke(r,i,{pluginIds:t.pluginIds}),s=new Map(a.map(l=>[l.plugin,l])),u=r.plugins.filter(l=>wi(l,o)).map(l=>{let d=F(l),c=s.get(l.id);return c?{plugin:l.id,providerName:se(l.id),authKind:Ir(d),status:c.status,connected:c.connected,fields:c.fields.map(p=>({name:p.name,level:p.level,required:p.required,configured:p.configured})),missingRequiredFields:c.missingRequiredFields}:{plugin:l.id,providerName:se(l.id),authKind:Ir(d),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:i,plugins:u}}async function _r(e,n){let t=D(e);return pr({hub:t,path:`/projects/${encodeURIComponent(n.projectId)}/connections`,notFoundMessage:"Hub REST API not found at /projects/:id/connections. Check HUB_API_URL and ensure the Hub API is deployed.",parseResponse:sn})}var ue=6e4,he=3e5;var z=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function mn(e,n){let t=T(e,()=>new z("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new z("no_database","Database not configured");let r=$(t,n.plugin,d=>new z("plugin_not_found",d)),i=F(r);if(!i)throw new z("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new z("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await _e(e,n.tenantId);let o=new Set(en(r,i)),s=r.authConfig?.[i]?.account??[],u=R({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:s}),l=0;for(let[d,c]of Object.entries(n.credentials)){if(!c.trim())continue;if(!o.has(d))throw new z("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let p=J(u,`set_${d}`);if(!p)throw new z("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await p(c.trim()),l+=1}if(l===0)throw new z("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var kn=new Map;function Pi(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 Pi(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 Er=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function Ti(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 Ai(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=Er(n.config),i={};Object.keys(r).length>0&&(i=ne(r,t)),i[e.link.linkType]=e.link.externalId;let o=ae(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function De(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:a,extraAccountFields:s=[]}=e,{accountId:u}=await Ti({database:n,pluginId:r,tenantId:i}),l=!1;if(a){let d=R({authType:a,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:s}),c=`set_${o.linkType}`,p=d[c];typeof p=="function"&&(await p(o.externalId),l=!0)}l||await Ai({database:n,kek:t,accountId:u,link:o})}async function Xn(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=Er(s.config)[i];if(!d)continue;if(We(d,u)===o)return s}catch{continue}return null}async function wn(e){return(await Xn(e))?.tenant_id??null}async function Dr(e){return wn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var ce=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Oe(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:a,scope:s}=n;if(!i.trim())throw new ce("no_access_token","Managed OAuth delivery missing access_token");let u=T(e,()=>new ce("invalid_corsair_instance","Invalid corsair instance"));if(!u.database)throw new ce("no_database","No database configured on corsair instance");let l=$(u,t,c=>new ce("plugin_not_found",c));await _e(e,r);let d=R({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 c=await Cn(u.plugins,t,{access_token:i,refresh_token:o,scope:s});if(c)try{let p=l.authConfig?.managed?.account??[];await De({database:u.database,kek:u.kek,pluginId:t,tenantId:r,link:c,authType:"managed",extraAccountFields:p})}catch(p){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,p)}}catch(c){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,c)}return{plugin:t,tenantId:r}}import{createHmac as et,randomUUID as vi,timingSafeEqual as Or}from"crypto";function Mr(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Pn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=et("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":vi()}}}function nt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Mr(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=et("sha256",n).update(e.body).digest("hex");try{return Or(Buffer.from(o,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function Me(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Mr(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=et("sha256",n).update(e.body).digest("hex");try{if(!Or(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 tt(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function rt(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function ot(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 it(e){let{body:n,headers:t}=Pn(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 xi(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(xi(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 Si(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Ri(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 Fr(e,n,t,r){let i=Si(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=Ri(i)||o);let s={headers:i,body:o,...r?{query:r}:{}},u=r?.tenantId||"default",l=e.withTenant?e.withTenant(u):e,d=nn;for(let c of d){let p=l[c];if(!p||!p.webhooks||p.pluginWebhookMatcher&&!p.pluginWebhookMatcher(s))continue;let g=Hr(p.webhooks,s);if(!g)continue;let f=g.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let h=await g.webhook.handler(y),m=!!Object.keys(h.returnToSender||{})?.length;return{plugin:c,action:f,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 ${c}.${f}:`,h),{plugin:c,action:f,body:o,response:{success:!1,error:h instanceof Error?h.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{randomBytes as Di}from"crypto";import{createHmac as Ii,randomBytes as _i,timingSafeEqual as Ei}from"crypto";function te(){return _i(16).toString("base64url")}function Ze(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Ii("sha256",t).update(e).digest("base64url")}function V(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=Ze(i,t);try{if(!Ei(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 Tn(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=Ze(o,n);return`${o}.${a}`}function Ge(e,n,t){let r=Math.floor(Date.now()/1e3);return Tn(e,n,r+Math.floor(t/1e3))}function me(e){return decodeURIComponent(e)}function st(e){return encodeURIComponent(e)}function Ur(e){let n=e.trim();return n.length>0?n:null}function An(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function vn(e,n){if(!Ur(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??Di(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 le(e,n){return Ur(n)?V(e,n):null}function ke(e){return e.deliveryMode==="connect.status"}function be(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&&!ke(e)&&!be(e)&&!Je(e)&&!ze(e)}function at(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 Oi(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 Mi(e,n,t){let r=await Oi(e,n,t),i={...t.query??{},...r?{tenantId:r}:{}},o=await Fr(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 Hi(e,n){return await Ve(e,n),{status:"ok"}}async function Fi(e,n){return await Oe(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function ct(e,n,t){let r=await ut(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function ut(e,n,t){let r=T(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 Ui(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 Bi(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await Ee(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function lt(e,n,t={}){let r=T(e),i=at(n.headers,"x-corsair-signature"),o=at(n.headers,"x-corsair-timestamp"),a=at(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let u=Me({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 l=bn(`nonce:${a.trim()}`,3e5);if(!l.ok)return{status:"failed",retryable:!1,error:l.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(s.type){case"webhook":return Mi(e,r,s.payload);case"oauth.callback":return Hi(e,s.payload);case"oauth.tokens":return Fi(e,s.payload);case"permission.approve":return ut(e,s.payload,"approved");case"permission.deny":return ut(e,s.payload,"denied");case"auth.credentials":return Ui(e,s.payload);case"connect.status":return Bi(e,s.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${s.type}`}}}var Ni="corsair:client-bridge";function Br(e){let n=JSON.stringify({type:Ni,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 $i=[".corsair.dev"];function Li(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function Wi(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Li(n)?!0:$i.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Nr(e){return!e||!Wi(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 $r(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 dt(e,n){let t=D(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=le(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(ke(o)){if(!o.hubSuccessUrl)return{type:"json",status:400,body:{error:"Connect status delivery missing hubSuccessUrl"}};let s=o.tenantId?.trim()||"default",u=await Ee(e,s,{pluginIds:o.statusPlugins});return{type:"redirect",url:Sn(o.hubSuccessUrl,{status:u})}}if(be(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 ct(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 Oe(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(ke(o)||be(o))&&o.hubSuccessUrl?{type:"redirect",url:Sn(o.hubSuccessUrl,{error:u})}:(ke(o)||be(o))&&o.hubOrigin&&o.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Br({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 pt(e,n){let t=D(e),r=await lt(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 gt(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 ft(e,n){return n.method==="GET"?dt(e,n.url):pt(e,{headers:n.headers,body:n.body??""})}async function yt(e,n){try{let t=await ft(e,n);return gt(t)}catch(t){if(t instanceof ye)return Response.json({error:t.message},{status:503});throw t}}async function Ce(e,n){let t=n.method.toUpperCase(),r=Nr(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 yt(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return $r(i,r)}var re=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 Lr=300;async function ht(e,n){let{keys:t,hub:r,plugin:i,tenantId:o}=e,a=n?.forceRefresh??!1,[s,u,l]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!s&&!l)throw new re(i,"managed");let d=Math.floor(Date.now()/1e3);if(!a&&s&&u&&Number(u)>d+Lr)return{accessToken:s,expiresAt:Number(u),refreshed:!1};if(!l&&s&&!a){let g=u?Number(u):null;if(g===null||g>d+Lr)return{accessToken:s,expiresAt:g??d+3600,refreshed:!1}}let c=await xe({hub:r,path:"/oauth/refresh",body:{plugin:i,tenantId:o},parseResponse:un}),p=c.expires_in?d+c.expires_in:u?Number(u):d+3600;return await t.set_access_token(c.access_token),await t.set_expires_at(String(p)),c.refresh_token&&await t.set_refresh_token(c.refresh_token),c.scope&&await t.set_scope(c.scope),{accessToken:c.access_token,expiresAt:p,refreshed:!0}}async function Wr(e,n){e._refreshAuth=async()=>(await ht(n,{forceRefresh:!0})).accessToken}async function Rn(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:an})}function In(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}function jr(e){return{delivery:n=>Ce(e,n),deliveryOptions:n=>Ce(e,n)}}var Kr=1200*1e3;function mt(){return te()}function kt(){return Kr}function bt(e,n){return Ge(e,n,Kr)}function Ct(e,n){return V(e,n)}function wt(e){return me(e)}var qr=600*1e3;function Pt(){return te()}function Tt(){return qr}function At(e,n){return Ge(e,n,qr)}function vt(e,n){return V(e,n)}function xt(e){return st(e)}function St(e){return me(e)}function Rt(){return te()}function It(e,n,t){return Tn(e,n,Math.floor(t.getTime()/1e3))}function _t(e,n){return V(e,n)}function Et(e){return me(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 ${Le}`)}})}import*as Ye from"crypto";function de(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function Dt(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 He(e,n){let t=Ye.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var Ot=600*1e3;function En(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),i=e.slice(t+1),o=Ye.createHmac("sha256",n).update(r).digest("base64url"),a=Buffer.from(i,"base64url"),s=Buffer.from(o,"base64url");return a.length!==s.length||!Ye.timingSafeEqual(a,s)?null:Dt(r,{maxAgeMs:Ot})}function Fe(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}var ji=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Zr(e,n,t,r,i){let o={pluginId:n,operation:t,input:r,originalError:e},a=Object.keys(i).find(l=>i[l]?.match(e,o));return await(i[a||"DEFAULT"]?.handler||ji)(e,o)}import{randomBytes as qi}from"crypto";import{v4 as Zi}from"uuid";var Mt="Permission approval required. Set manual.approvalBaseUrl (or use hub for hosted approval) so an approval URL can be generated. Optionally set manual.onApprovalRequired to customize the agent message.";function Ft(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function Gr(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Ht(e){return In(e)}async function Ut(e,n){if(Ft(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?Gr(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:Ki(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function Ki(e){try{return JSON.parse(e)}catch{return e}}async function Dn(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await Ut(e,n);return{...n,approvalUrl:r}}async function Bt(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:i,permissionToken:o,plugin:a,endpoint:s,args:u,tenantId:l,expiresAt:d,operationPath:c}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:o,id:i,plugin:a,endpoint:s,args:u});let g=await Ut({manual:t,hub:r},{id:i,token:o,plugin:a,endpoint:s,args:JSON.stringify(u),tenant_id:l,expires_at:d});return Ft(t)?g?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:g}):Ht(g):Mt:r?g?Ht(g):`Action '${c}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Mt}var Gi={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 Ji(e,n,t){return t!==void 0?t:Gi[n][e]}function Nt(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 zr(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 Jr(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 Vr(e){let n=Ji(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 f=e.db,y=s.id;return{result:"allow",onComplete:async()=>{await f.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"?Jr(e.db,s.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:s.id,token:s.token,expiresAt:s.expires_at})}let u=Zi(),l=qi(32).toString("hex"),d=e.timeoutMs??600*1e3,c=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:l,plugin:e.pluginId,endpoint:e.endpointPath,args:i,tenant_id:a,status:"pending",expires_at:c}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
21
- Action: ${r}`,`
22
- Permission ID: ${u}`,`
23
- Permission token: ${l}`,`
24
- Expires at: ${c}`,`
25
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Jr(e.db,u,d):{result:"blocked",reason:"pending",id:u,token:l,expiresAt:c}}function zi(e){return typeof e=="function"}function Vi(e,n,t){let r=He(de(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 $t({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:i,errorHandlers:o,currentPath:a=[],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:d,permissionsOptions:c,tenantId:p,manualConfig:g,hubConfig:f}){for(let[y,h]of Object.entries(e)){let m=n?.[y];if(zi(h)){let C=m,b=[...a,y].join("."),k=async(w={})=>{let P;if(u){let _=l?.[b],{result:ve,reason:Z,onComplete:Ne,token:Q,id:fe,expiresAt:N}=await Vr({pluginId:i,endpointPath:b,args:w,mode:u.mode,override:u.overrides?.[b],riskLevel:_?.riskLevel??"write",meta:_,db:d,timeoutMs:c?Nt(c.timeout):void 0,tenantId:p,approvalMode:c?.mode});if(ve==="blocked"){let G;throw Z==="denied"?G=`Action '${b}' was denied by the user. Await further instructions before proceeding.`:Z==="policy"?G=`Action '${b}' is blocked by the permission policy. Update the corsair config to allow it.`:Z==="timeout"?G=`Action '${b}' timed out waiting for approval.`:Q&&fe?G=await Bt({permissionsOptions:c,manual:g,hub:f,permissionId:fe,permissionToken:Q,plugin:i,endpoint:b,args:w,tenantId:p??"default",expiresAt:N??new Date(Date.now()+(c?Nt(c.timeout):600*1e3)).toISOString(),operationPath:b}):G=`Action '${b}' requires user approval before it can run.`,new Error(G)}P=Ne}let O=async(_,ve,Z)=>{try{return await h(ve,Z)}catch(Ne){if(Ne instanceof Error){let Q=await Zr(Ne,i,b,typeof Z=="object"&&Z!==null?Z:{args:Z},o);if(_<(Q.maxRetries||0)){let fe=_+1;console.log(`Retrying (${fe} / ${Q.maxRetries})...`);let N;if(Q.headersRetryAfterMs)N=Q.headersRetryAfterMs;else switch(Q.retryStrategy){case"exponential_backoff":N=Math.pow(2,fe-1)*1e3;break;case"exponential_backoff_jitter":let G=Math.pow(2,fe-1)*1e3,_o=(Math.random()-.5)*1e3;N=Math.max(0,G+_o);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 O(fe,ve,Z),console.log(`[corsair:${i}:${b}] Retry strategy:`,Q)}}throw Ne}},M;try{M=s?await s(t,"endpoint"):void 0}catch(_){throw g&&Fe(g)&&g.oauthConfig&&g.kek&&_ instanceof re&&_.authType==="oauth_2"?Vi(i,g,p):_}if(!C?.before&&!C?.after){let _=await O(0,{...t,key:M},w);return await P?.(),_}let H={...t,key:M},x=C.before?await C.before(H,w):{ctx:H,args:w,continue:!0,passToAfter:void 0};if(x.continue===!1)return;let Ae=await O(0,x.ctx,x.args);return await C.after?.(x.ctx,Ae,x.passToAfter),await P?.(),Ae};r[y]=k}else if(h&&typeof h=="object"){let C={};$t({endpoints:h,hooks:m,ctx:t,tree:C,pluginId:i,errorHandlers:o,currentPath:[...a,y],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:d,permissionsOptions:c,tenantId:p,manualConfig:g,hubConfig:f}),r[y]=C}}}function Yi(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Lt({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:i}){for(let[o,a]of Object.entries(e)){let s=n?.[o];if(Yi(a)){let u=s,l=async d=>{let c=(g,f)=>a.handler(g,f),p=i?await i(t,"webhook"):void 0;return!u?.before&&!u?.after?c({...t,key:p},d):(async()=>{let g={...t,key:p},f=u.before?await u.before(g,d):{ctx:g,args:d,continue:!0,passToAfter:void 0};if(f.continue===!1)return;let y=await c(f.ctx,f.args);return y?.success===!0&&await u.after?.(f.ctx,y,f.passToAfter),y})()};r[o]={match:a.match,handler:l}}else if(a&&typeof a=="object"){let u={};Lt({webhooks:a,hooks:s,ctx:t,webhooksTree:u,keyBuilder:i}),r[o]=u}}}function Qi(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 Xi(e,n,t,r,i){return e?Gn(e.db,n,t,r,i):{findByEntityId:async()=>null,existsByEntityId:async()=>!1,findIdByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function Wt(e,n){let{database:t,tenantId:r,kek:i,rootErrorHandlers:o,permissionsOptions:a,manualConfig:s,hubConfig:u}=n,l={},d={};for(let c of e)l[c.id]={},d[c.id]={};for(let c of e){let p=c.schema,g=r??"default",f=Qi(t,c.id,g);if(p?.entities){let x={};for(let[Ae,_]of Object.entries(p.entities)){let ve=t?Gn(t.db,f,Ae,p.version,_):Xi(void 0,f,Ae,p.version,_);x[Ae]=ve}d[c.id].db=x,l[c.id].db=x}let y=c.options,h=c.authConfig,m;if(t&&i&&y?.authType){let x=h?.[y.authType]?.account??[];m=R({authType:y.authType,integrationName:c.id,tenantId:g,kek:i,database:t,extraAccountFields:x}),l[c.id].keys=m}let C={database:t,db:d[c.id]?.db??{},$getAccountId:f,...c.options?{options:c.options}:{},...m?{keys:m,authType:y?.authType}:{},tenantId:g,...u?{hub:u}:{}},b=c.endpoints??{},k=c.hooks,w={...o,...c.errorHandlers},P={},O=c.options?.permissions;$t({endpoints:b,hooks:k,ctx:C,tree:P,pluginId:c.id,errorHandlers:w,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:O,endpointMeta:c.endpointMeta,database:t,permissionsOptions:a,tenantId:r,manualConfig:s?{...s,oauthConfig:c.oauthConfig,kek:i,tenantId:g}:void 0,hubConfig:u}),Object.keys(P).length>0&&(l[c.id].api=P),C.endpoints=P;let M=c.webhooks??{},H=c.webhookHooks;if(Object.keys(M).length>0){let x={};Lt({webhooks:M,hooks:H,ctx:C,webhooksTree:x,keyBuilder:c.keyBuilder}),l[c.id].webhooks=x,c.pluginWebhookMatcher&&(l[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher),c.pluginTenantWebhookMatcher&&(l[c.id].pluginTenantWebhookMatcher=c.pluginTenantWebhookMatcher)}}return l}function Yr(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 es="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function Qr(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] ${es}`),t):n}import*as Xr from"querystring";function we(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}?${Xr.stringify(o)}`}var W=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function ns(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 jt(e,n){let t=T(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=En(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=ns(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 c=we({oauthConfig:u,clientId:d,redirectUri:r,state:n});return{plugin:o,tenantId:a,providerName:u.providerName,oauthUrl:c,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 eo(e){let n={error:e.code,message:e.message,...e.extra};return S(e.status,n)}function pe(e){return new v(404,"not_found",e)}function Y(e,n={}){return new v(400,"bad_request",e,n)}function no(e,n){return $(e,n,t=>pe(t))}async function to(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(l=>o[`get_${l}`]()))}catch{a=i.map(()=>null)}let s=i.filter((l,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 ro(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await to(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 On(){return{ok:!0}}async function Mn(e){return Promise.all(e.plugins.map(n=>ro(n,e)))}async function Hn(e,n){let t=no(e,n);return ro(t,e)}async function ts(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 oo(e,n){let t=await ts(e,n),r=t.filter(i=>i.hasCredentials).map(i=>i.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function Fn(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 Un(e,n){if(!n)throw Y("Tenant id must be a non-empty string");return oo(e,n)}async function Bn(e,n){let t=n?.id?.trim();if(!t)throw Y("Tenant id is required",{missingFields:["id"]});return oo(e,t)}async function Nn(e,n){let t=n?.trim()||"default",r={},i=await Ke(e,t);for(let o of i)r[o.plugin]=fn(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 Kt(e,n){if(!e.database)throw pe(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw pe(`Permission '${n}' not found`);return Dn(e,t)}function rs(e){if(!e.oauthConfig)throw Y(`Plugin '${e.id}' has no oauthConfig`)}function os(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 qt(e){let n=os(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 is(e){let n=!!e.hub,t=Fe(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 io(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 ss(e,n){let t=n?.plugin?.trim();if(!t)throw Y("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=no(e,t);rs(i);let o=qt(e);io(e);let a=await to(i,e);if(!a.configured)throw new v(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:a.missingFields});let s=He(de(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()+Ot).toISOString()}}async function as(e,n,t){io(n);let r=t.tenantId?.trim()||"default",i=D(e);if(t.source){let l=Ie({source:t.source,deliveryUrl:i.deliveryUrl,oauthMode:t.oauthMode});if(l)throw Y(l.error)}let o={tenantId:r,source:t.source??Re(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 $n(e,n,t){return is(n),n.hub?as(e,n,t):ss(n,t)}async function Ln(e,n,t){if(n.hub&&!Fe(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 Y("state is required",{missingFields:["state"]});qt(n);try{return await jt(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw Y("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 Wn(e,n,t){if(n.hub&&!Fe(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 Y("Missing required fields",{missingFields:o});let a=qt(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 Y("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 pe("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw pe("Permission not found");return Dn(e,t)}async function so(e,n){return"id"in n?Kt(e,n.id):Zt(e,n.token)}var ao=[{method:"GET",pattern:"/ok",handler:async()=>S(200,On())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>S(200,await Fn(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 Un(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>S(200,await Mn(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>S(200,await Hn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>S(200,await Nn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>S(200,await Kt(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 $n(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>S(200,await Ln(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>S(200,await Wn(e,n,t))}];(()=>{let e=new Set;for(let n of ao){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function us(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 cs(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 ls(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 ds="/api/corsair";function Pe(e,n={}){let t=n.basePath??ds,r=T(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async i=>{try{let o=new URL(i.url),a=cs(o.pathname,t),s=i.method.toUpperCase();if(s==="OPTIONS"||a==="/"||a==="")return await Ce(e,i);if(s!=="GET"&&s!=="POST")return S(405,{error:"method_not_allowed",message:`Method ${s} not allowed`});let u=Object.fromEntries(o.searchParams);for(let l of ao){if(l.method!==s)continue;let d=us(l.pattern,a);if(!d)continue;let c=await ls(i);return await l.handler({corsair:e,internal:r,req:i,params:d,query:u,body:c})}throw pe(`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 eo(o);let a=o instanceof Error?o.message:"Internal server error";return S(500,{error:"internal_error",message:a})}}}function ps(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,l]of Object.entries(e.headers))if(l!=null)if(Array.isArray(l))for(let d of l)o.append(u,d);else o.set(u,l);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 gs(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 uo(e,n){let t=Pe(e,n);return async(r,i,o)=>{try{let a=await t(ps(r));await gs(i,a)}catch(a){o(a)}}}function co(e,n){let t=Pe(e,n);return r=>t(r.req.raw)}function lo(e,n){let t=Pe(e,n);return{GET:t,POST:t,OPTIONS:t}}function po(e){let n={[Qe]:e};return{ok:On,tenants:{list:()=>Fn(e),create:t=>Bn(e,t),get:t=>Un(e,t)},plugins:{list:()=>Mn(e),get:t=>Hn(e,t)},connectionStatus:{get:t=>Nn(e,t?.tenantId)},permissions:{get:t=>so(e,t)},connect:{createLink:t=>$n(n,e,t),resolve:t=>Ln(n,e,t),oauthCallback:t=>Wn(n,e,t)}}}async function go(e,n,t,r,i="pending"){if(!e)return null;try{let o=or(),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 fs(e,n,t,r="pending"){try{let i=await e.$getAccountId();return go(e.database,i,n,t,r)}catch(i){return console.warn("Failed to log event:",i),null}}import*as fo from"https";import*as yo from"querystring";function jn(e,n,t,r,i){let o=new URL(r.tokenUrl),a=r.tokenAuthMethod==="basic";return new Promise((s,u)=>{let l={code:e.trim(),redirect_uri:i,grant_type:"authorization_code"};a||(l.client_id=n,l.client_secret=t);let d=yo.stringify(l),c={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(d).toString()};a&&(c.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let p=fo.request({hostname:o.hostname,...o.port?{port:Number(o.port)}:{},path:o.pathname+o.search,method:"POST",headers:c},g=>{let f="";g.on("data",y=>{f+=y}),g.on("end",()=>{if(g.statusCode!==200){u(new Error(`Token exchange failed (${g.statusCode}): ${f}`));return}try{s(JSON.parse(f))}catch{u(new Error(`Token endpoint returned non-JSON response: ${f}`))}})});p.on("error",g=>u(new Error(`Request failed: ${g.message}`))),p.write(d),p.end()})}var ho=" ";function K(e){let n=e;return n._def??n.def??{}}function q(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 ko(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 bo(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function qn(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function Ue(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 ys(e){let n=e;for(;n;){let t=K(n),r=Co(n,t);if(r)return r;let i=q(t);if(Yt(i)||i==="ZodPipe"||i==="ZodEffects"||i==="ZodTransform"){n=ko(t,i);continue}break}}function Yt(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function U(e){let n=K(e),t=q(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??Ue(n)[0]??"unknown");case"ZodEnum":return Ue(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=j(n);return r?U(r):"unknown"}case"ZodNullable":{let r=j(n);return`${r?U(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=j(n);return r?U(r):"unknown"}case"ZodArray":{let r=bo(n);if(!r)return"unknown[]";let i=K(r),o=q(i)==="ZodUnion",a=U(r);return`${o?`(${a})`:a}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=qn(e,n),i=Object.entries(r);return i.length===0?"{}":`{ ${i.map(([a,s])=>{let u=q(K(s));return`${u==="ZodOptional"||u==="ZodNullable"?a+"?":a}: ${U(s)}`}).join(", ")} }`}case"ZodUnion":return Ue(n).map(r=>U(r)).join(" | ");case"ZodIntersection":return`${U(n.left)} & ${U(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=ko(n,t);return r?U(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function oe(e){let n=K(e),t=q(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??Ue(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=Ue(n).map(o=>String(o));return{kind:"string",optional:!1,description:r,enum:i}}case"ZodOptional":{let i=j(n),o=i?oe(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodNullable":{let i=j(n),o=i?oe(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodDefault":case"ZodCatch":{let i=j(n);return i?{...oe(i),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let i=bo(n);return{kind:"array",optional:!1,description:r,items:i?oe(i):{kind:"unknown",optional:!1}}}case"ZodObject":{let i=qn(e,n),o={};for(let[a,s]of Object.entries(i))o[a]=oe(s);return{kind:"object",optional:!1,description:r,fields:o}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let i=Ue(n);for(let o of i){let a=K(o);if(q(a)==="ZodObject")return{...oe(o),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let i=j(n);return i?{...oe(i),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function Gl(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=ge(a.endpointMeta,s),l=ge(a.endpointSchemas,s);return!u&&!l?null:{input:l?.input?oe(l.input):null,output:l?.output?oe(l.output):null,description:u?.description}}var Qt=["equals","contains","startsWith","endsWith","in"],hs=["equals","gt","gte","lt","lte","in"],ms=["equals"],ks=["equals","before","after","between"];function wo(e){let n=K(e);switch(q(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=j(n);return r?wo(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Xt(e){let n=K(e),t=q(n);if(Yt(t)){let o=j(n);return o?Xt(o):{}}if(t!=="ZodObject")return{};let r=qn(e,n),i={};for(let[o,a]of Object.entries(r)){let s=wo(a);s==="string"?i[o]={type:"string",operators:Qt}:s==="number"?i[o]={type:"number",operators:hs}:s==="boolean"?i[o]={type:"boolean",operators:ms}:s==="date"&&(i[o]={type:"date",operators:ks})}return i}function Po(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function Jt(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"&&Jt(i,o,t)}}function zt(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Vt(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];zt(i)?t.push(o.join(".")):i!==null&&typeof i=="object"&&Vt(i,o,t)}}function er(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 zt(a)?[o]:null;if(a!==null&&typeof a=="object"&&!zt(a)){let s=er(a,r);if(s!==null)return[o,...s]}return null}function To(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 bs=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 bs.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 Vt(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 Jt(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=[];Vt(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=[];Jt(o.endpoints,[],a),i[o.id]=a.map(s=>`${o.id}.api.${s}`)}return i}function ge(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function Cs(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 Gt(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 Jl(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),c=d.lastIndexOf(".");if(c!==-1){let p=d.slice(0,c),g=d.slice(c+1),f=a.schema?.entities;if(g==="search"&&f){let y=Po(f,p);if(y){let[h,m]=y,C=Xt(m),b=[`Search ${i} ${h} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Qt.join(", ")}]`];for(let[k,w]of Object.entries(C))b.push(` ${k}?: ${w.type} [${w.operators.join(", ")}]`);return b.push("}"),b.join(`
30
- `)}}}return Gt(Te(e,{type:"db"}),"Path not found. Available db operations")}if(o.startsWith("webhooks.")){let d=o.slice(9);if(a.webhooks){let c=er(a.webhooks,d.split("."));if(c!==null){let p=c.join("."),g=ge(a.webhookSchemas,p.toLowerCase()),f=g?.response?U(g.response):null,y=[];return g?.description&&y.push(g.description),g?.payload&&y.push(`payload ${Kn(Be(g.payload))}`),f&&y.push(`response: ${f}`),y.push(`usage:
31
- ${To(i,c)}`),y.join(`
32
-
33
- `)}}return Gt(Te(e,{type:"webhooks"}),"Path not found. Available webhooks")}let s=o;s.startsWith("api.")&&(s=s.slice(4));let u=ge(a.endpointMeta,s),l=ge(a.endpointSchemas,s);if(u||l){let d=[],c=[u?.riskLevel?`[${u.riskLevel}]`:"",u?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),p=[u?.description,c].filter(Boolean).join(" ");return p&&d.push(p),l?.input&&d.push(`input ${Kn(Be(l.input))}`),l?.output&&d.push(`output ${Kn(Be(l.output))}`),d.join(`
34
-
35
- `)}}}return Gt(Te(e),"Path not found. Available operations")}function mo(e){let n=e;for(;;){let t=K(n),r=q(t);if(Yt(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=mo(e),t=K(n);if(q(t)==="ZodObject"){let i=qn(n,t),o=[];for(let[a,s]of Object.entries(i)){let u=K(s),l=q(u),d=l==="ZodOptional"||l==="ZodNullable",c=mo(s),p=ys(s);o.push({key:a,optional:d,type:U(c),...p!==void 0?{description:p}:{}})}return{kind:"object",fields:o}}return{kind:"inline",type:U(n)}}function Kn(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=ho.repeat(n+1),r=ho.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 ws(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:c,lookupKey:p}=Cs(d,n),g=ge(r.endpointMeta,p),f=ge(r.endpointSchemas,p);!g&&!f||i.push({path:d,shortPath:c,description:g?.description,riskLevel:g?.riskLevel,irreversible:g?.irreversible,input:Be(f?.input),output:Be(f?.output)})}i.sort((d,c)=>d.path.localeCompare(c.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),g=p.startsWith(".")?p.slice(1):p;if(!g.startsWith("webhooks."))continue;let f=g.slice(9),y=er(r.webhooks,f.split("."));if(y===null)continue;let h=y.join("."),m=ge(r.webhookSchemas,h.toLowerCase()),C=m?.response?U(m.response):void 0;o.push({path:d,description:m?.description,payload:Be(m?.payload),responseType:C,usageExample:To(n,y)})}o.sort((d,c)=>d.path.localeCompare(c.path));let s=[],u=Te(e,{plugin:n,type:"db"}),l=r.schema?.entities;if(Array.isArray(u)&&l)for(let d of u){let p=d.toLowerCase().slice(n.length+1),g=p.startsWith(".")?p.slice(1):p;if(!g.startsWith("db."))continue;let f=g.slice(3),y=f.lastIndexOf(".");if(y===-1)continue;let h=f.slice(0,y);if(f.slice(y+1)!=="search")continue;let C=Po(l,h);if(!C)continue;let[b,k]=C,w=Xt(k),P=Object.entries(w).map(([O,M])=>({field:O,type:M.type,operators:M.operators}));s.push({path:d,entityName:b,filters:[{field:"entity_id",type:"string",operators:Qt},...P]})}return s.sort((d,c)=>d.path.localeCompare(c.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:s}}}function Ao(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function Ps(e,n){let t=Ao(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 Ts(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function vo(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function xo(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 As(e){return Xe(e.body)}function So(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Zn(Array.isArray(r)?r:[r])}function Ro(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let u of t){let l=Zn(Array.isArray(u)?u:[u]);if(l)return decodeURIComponent(l)}let r=So({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 l=n[u],d=Array.isArray(l)?l[0]:l;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 vs(e){if(Ro(e))return!0;let n=Xe(e.body??e.payload);return vo(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Zn(e){for(let n of e){let t=xo(n);if(t)return t}}function xs(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 vr(e){let n=e.database?nr(e.database):void 0,t=n&&e.kek?Yr(e.plugins,n,e.kek):_n(!!n,!!e.kek),r=Qr(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=zr(n),a=po(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 l=Wt(e.plugins,{database:n,tenantId:u,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(l,{[Qe]:i})},keys:t,permissions:o,manage:a},{[Qe]:i});let s=Wt(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 B=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function Io(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 Ss(e,n,t,r){let i=sr(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=X(),u=await ee(s,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:u})}async function Qn(e,n,t){let{tenantId:r,redirectUri:i,hubConnect:o=!1}=t,a=T(e,()=>new B("invalid_corsair_instance","Invalid corsair instance"));if(!a.database)throw new Error("No database configured on corsair instance");let s=$(a,n,p=>new B("plugin_not_found",p)),u=Io(s),d=await I({authType:"oauth_2",integrationName:n,kek:a.kek,database:a.database}).get_client_id();if(!d)throw new Error(`client_id not configured for '${n}'`);if(o){let p=new URL(we({oauthConfig:u,clientId:d,redirectUri:i,state:""}));return p.searchParams.delete("state"),{url:p.toString(),state:""}}let c=He(de(n,r),a.kek);return{url:we({oauthConfig:u,clientId:d,redirectUri:i,state:c}),state:c}}async function Ve(e,n){let{code:t,state:r,redirectUri:i}=n,o=T(e,()=>new B("invalid_corsair_instance","Invalid corsair instance")),a=En(r,o.kek);if(!a)throw new B("invalid_state","Invalid or tampered state parameter");let{plugin:s,tenantId:u}=a;if(!o.database)throw new B("no_database","No database configured on corsair instance");let l=$(o,s,h=>new B("plugin_not_found",h)),d=Io(l),c=I({authType:"oauth_2",integrationName:s,kek:o.kek,database:o.database}),p=await c.get_client_id(),g=await c.get_client_secret();if(!p||!g)throw new B("credentials_not_configured",`Credentials not configured for '${s}'`);await Ss(o.database,s,u,o.kek);let f=await jn(t,p,g,d,i);if(!f.access_token)throw new B("no_access_token",`No access_token returned from ${d.providerName}`);let y=R({authType:"oauth_2",integrationName:s,tenantId:u,kek:o.kek,database:o.database});await y.set_access_token(f.access_token),f.refresh_token&&await y.set_refresh_token(f.refresh_token),f.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+f.expires_in));try{let h=await Cn(o.plugins,s,f);if(h)try{let m=l.authConfig?.oauth_2?.account??[];await De({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{ar as a,se as b,$e as c,ye as d,tn as e,D as f,rn as g,on as h,sn as i,an as j,un as k,ur as l,cn as m,X as n,ee as o,L as p,Jn as q,We as r,ae as s,ne as t,je as u,I as v,R as w,kr as x,br as y,de as z,Dt as A,De as B,Xn as C,wn as D,Dr as E,we as F,B as G,Qn as H,Ve as I,qe as J,Re as K,wr as L,Ie as M,Tr as N,fi as O,hn as P,Ee as Q,_r as R,ue as S,he as T,ce as U,Oe as V,Pn as W,nt as X,Me as Y,tt as Z,rt as _,ot as $,it as aa,Fr as ba,te as ca,An as da,vn as ea,le as fa,ke as ga,be as ha,Je as ia,ze as ja,xn as ka,ct as la,lt as ma,dt as na,pt as oa,gt as pa,ft as qa,yt as ra,Ce as sa,re as ta,ht as ua,Wr as va,Rn as wa,In as xa,jr as ya,mt as za,kt as Aa,bt as Ba,Ct as Ca,wt as Da,Pt as Ea,Tt as Fa,At as Ga,vt as Ha,xt as Ia,St as Ja,Rt as Ka,It as La,_t as Ma,Et as Na,jt as Oa,Pe as Pa,uo as Qa,co as Ra,lo as Sa,go as Ta,fs as Ua,jn as Va,Gl as Wa,Te as Xa,Jl as Ya,Kn as Za,ws as _a,Ao as $a,Ps as ab,Ts as bb,vo as cb,xo as db,Xe as eb,As as fb,So as gb,Ro as hb,vs as ib,Zn as jb,xs as kb,Qe as lb,vr as mb};