corsair 0.1.81 → 0.1.83

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 @@
1
+ import{b as F,c as D,d as P,e as B}from"./chunk-IGGCNGU2.js";var R={oauth_2:{integration:["client_id","client_secret","redirect_url"],account:["access_token","refresh_token","expires_at","scope","webhook_signature"]},api_key:{integration:[],account:["api_key","webhook_signature"]},bot_token:{integration:[],account:["bot_token","webhook_signature"]},managed:{integration:[],account:["access_token","refresh_token","expires_at","scope","webhook_signature"]}};function L(e,t){if(!e||typeof e!="object")return;let r=e[t];return typeof r=="function"?(...n)=>Reflect.apply(r,e,n):void 0}import{Kysely as J}from"kysely";var H=Symbol.for("corsair:internal"),x=class extends Error{constructor(t="Invalid corsair instance"){super(t),this.name="InvalidCorsairInstanceError"}};function I(e){return typeof e=="object"&&e!==null}function S(e){return!I(e)||!Array.isArray(e.plugins)||typeof e.kek!="string"||typeof e.multiTenancy!="boolean"?!1:e.database===void 0?!0:I(e.database)?e.database.db instanceof J:!1}function O(e){if(!e||typeof e!="object")return;let r=Object.getOwnPropertyDescriptor(e,H)?.value;return S(r)?r:void 0}function G(e,t){let r=O(e);if(!r)throw t?.()??new x;return r}function N(e,t){return e.plugins.find(r=>r.id===t)}function X(e,t,r){let n=N(e,t);if(!n)throw r(`Plugin '${t}' not found`);return n}function Y(e){return"withTenant"in e&&typeof e.withTenant=="function"}import{v7 as q}from"uuid";function T(){return q()}function v(e){return e==="oauth_2"||e==="api_key"||e==="bot_token"||e==="managed"}function V(e){let t=e.options?.authType;return v(t)?t:void 0}function ee(e,t){let r=e.authConfig,n=R[t].account,i=r?.[t]?.account??[];return[...n,...i]}import{z as h}from"zod";import{sql as w}from"kysely";function A(e){return e.replace(/'/g,"''")}function W(e){let t=A(e);return w`data->>'${w.raw(t)}'`}function j(e){let t=A(e);return w`(data->>'${w.raw(t)}')::numeric`}function K(e){let t=A(e);return w`(data->>'${w.raw(t)}')::boolean`}function U(e){let t=A(e);return w`(data->>'${w.raw(t)}')::timestamptz`}function te(e){if(typeof e=="string")try{return JSON.parse(e)}catch{return e}return e}function Z(e){let t=e;for(;t;){if(t instanceof h.ZodOptional||t instanceof h.ZodNullable){t=t._def.innerType;continue}if(t instanceof h.ZodDefault){t=t._def.innerType;continue}break}return t}function ne(e){let t=Z(e);if(t instanceof h.ZodString)return"string";if(t instanceof h.ZodNumber)return"number";if(t instanceof h.ZodBoolean)return"boolean";if(t instanceof h.ZodDate)return"date"}function re(e){let t=Z(e);if(!(t instanceof h.ZodObject))return{};let r=t.shape,n={};for(let[i,a]of Object.entries(r)){let u=ne(a);u&&(n[i]=u)}return n}function ie(e,t,r){if(typeof r=="string")return e.where(t,"=",r);if(typeof r=="object"&&r!==null&&!Array.isArray(r)){let n=r;"equals"in n&&typeof n.equals=="string"&&(e=e.where(t,"=",n.equals)),"contains"in n&&typeof n.contains=="string"&&(e=e.where(t,"like",`%${n.contains}%`)),"startsWith"in n&&typeof n.startsWith=="string"&&(e=e.where(t,"like",`${n.startsWith}%`)),"endsWith"in n&&typeof n.endsWith=="string"&&(e=e.where(t,"like",`%${n.endsWith}`)),"in"in n&&Array.isArray(n.in)&&(e=e.where(t,"in",n.in))}return e}function oe(e,t,r){if(typeof r=="number")return e.where(t,"=",r);if(typeof r=="object"&&r!==null&&!Array.isArray(r)){let n=r;typeof n.equals=="number"&&(e=e.where(t,"=",n.equals)),typeof n.gt=="number"&&(e=e.where(t,">",n.gt)),typeof n.gte=="number"&&(e=e.where(t,">=",n.gte)),typeof n.lt=="number"&&(e=e.where(t,"<",n.lt)),typeof n.lte=="number"&&(e=e.where(t,"<=",n.lte)),Array.isArray(n.in)&&(e=e.where(t,"in",n.in))}return e}function se(e,t,r){if(typeof r=="boolean")return e.where(t,"=",r);if(typeof r=="object"&&r!==null&&!Array.isArray(r)){let n=r;typeof n.equals=="boolean"&&(e=e.where(t,"=",n.equals))}return e}function ae(e,t,r){if(r instanceof Date)return e.where(t,"=",r);if(typeof r=="object"&&r!==null&&!Array.isArray(r)){let n=r;if(n.equals instanceof Date&&(e=e.where(t,"=",n.equals)),n.before instanceof Date&&(e=e.where(t,"<",n.before)),n.after instanceof Date&&(e=e.where(t,">",n.after)),Array.isArray(n.between)&&n.between.length===2){let[i,a]=n.between;i instanceof Date&&(e=e.where(t,">=",i)),a instanceof Date&&(e=e.where(t,"<=",a))}}return e}function ue(e,t,r,n){return r==="number"?oe(e,j(t),n):r==="boolean"?se(e,K(t),n):r==="date"?ae(e,U(t),n):ie(e,W(t),n)}function ce(e,t,r){if(typeof r=="object"&&r!==null&&!Array.isArray(r)){let n=r;return"equals"in n&&(e=e.where(t,"=",n.equals)),"contains"in n&&typeof n.contains=="string"&&(e=e.where(t,"like",`%${n.contains}%`)),"startsWith"in n&&typeof n.startsWith=="string"&&(e=e.where(t,"like",`${n.startsWith}%`)),"endsWith"in n&&typeof n.endsWith=="string"&&(e=e.where(t,"like",`%${n.endsWith}`)),"in"in n&&Array.isArray(n.in)&&(e=e.where(t,"in",n.in)),e}return e.where(t,"=",r)}function de(e){return typeof e=="number"?e:typeof e=="bigint"?Number(e):Number.parseInt(String(e??0),10)}function C(e,t,r){return e.selectFrom("corsair_entities").selectAll().where("account_id","=",t).where("entity_type","=",r)}function $(e,t,r,n,i){let a=re(i);function u(o){let y=te(o.data);return{...o,data:i.parse(y)}}return{findByEntityId:async o=>{let y=await t(),d=await C(e,y,r).where("entity_id","=",o).executeTakeFirst();return d?u(d):null},findById:async o=>{let y=await t(),d=await C(e,y,r).where("id","=",o).executeTakeFirst();return d?u(d):null},findManyByEntityIds:async o=>{if(o.length===0)return[];let y=await t();return(await C(e,y,r).where("entity_id","in",o).execute()).map(u)},list:async o=>{let y=await t(),d=C(e,y,r);return typeof o?.limit=="number"&&(d=d.limit(o.limit)),typeof o?.offset=="number"&&(d=d.offset(o.offset)),(await d.execute()).map(u)},search:async o=>{let y=await t(),d=C(e,y,r),c=new Set(["data","limit","offset"]);for(let[l,f]of Object.entries(o))c.has(l)||f===void 0||(d=ce(d,l,f));if(o.data&&typeof o.data=="object")for(let[l,f]of Object.entries(o.data)){if(f===void 0)continue;let g=a[l]??"string";d=ue(d,l,g,f)}return typeof o.limit=="number"&&(d=d.limit(o.limit)),typeof o.offset=="number"&&(d=d.offset(o.offset)),(await d.execute()).map(u)},upsertByEntityId:async(o,y)=>{let d=await t(),c=i.parse(y),s=new Date,l=await C(e,d,r).select("id").where("entity_id","=",o).executeTakeFirst();if(l?.id){await e.updateTable("corsair_entities").set({version:n,data:c,updated_at:s}).where("id","=",l.id).execute();let E=await e.selectFrom("corsair_entities").selectAll().where("id","=",l.id).executeTakeFirst();return u(E)}let f=T();await e.insertInto("corsair_entities").values({id:f,created_at:s,updated_at:s,account_id:d,entity_id:o,entity_type:r,version:n,data:c}).execute();let g=await e.selectFrom("corsair_entities").selectAll().where("id","=",f).executeTakeFirst();return u(g)},deleteById:async o=>{let y=await t(),d=await e.deleteFrom("corsair_entities").where("account_id","=",y).where("entity_type","=",r).where("id","=",o).executeTakeFirst();return Number(d.numDeletedRows)>0},deleteByEntityId:async o=>{let y=await t(),d=await e.deleteFrom("corsair_entities").where("account_id","=",y).where("entity_type","=",r).where("entity_id","=",o).executeTakeFirst();return Number(d.numDeletedRows)>0},count:async()=>{let o=await t(),y=await e.selectFrom("corsair_entities").select(d=>d.fn.countAll().as("count")).where("account_id","=",o).where("entity_type","=",r).executeTakeFirst();return de(y?.count)}}}var le={corsair_integrations:F,corsair_accounts:D,corsair_entities:P,corsair_events:B};function ye(e){return le[e]}function M(e){if(typeof e=="string")try{return JSON.parse(e)}catch{return e}return e}function p(e){if(!e)throw new Error("Corsair database is not configured. Pass `database` to createCorsair(...) to enable ORM.")}function b(e){if(!e)return[];let t=[];for(let r in e){let n=r,i=e[n];if(i!==void 0)if(typeof i=="object"&&i!==null&&!Array.isArray(i)&&!(i instanceof Date)){let a=i;"in"in a&&Array.isArray(a.in)?t.push({field:n,operator:"in",value:a.in}):"like"in a&&typeof a.like=="string"&&t.push({field:n,operator:"like",value:a.like})}else t.push({field:n,value:i})}return t}function m(e,t){if(!t?.length)return e;let r=e;for(let n of t){let i=n.operator??"=";r=r.where(n.field,i,n.value)}return r}function fe(e){return typeof e=="number"?e:typeof e=="bigint"?Number(e):Number.parseInt(String(e??0),10)}function k(e,t){let r=ye(t),n=()=>(p(e),e),i=()=>n().db.selectFrom(t),a=()=>n().db.insertInto(t),u=()=>n().db.updateTable(t),o=()=>n().db.deleteFrom(t);function y(c){let s={};for(let[l,f]of Object.entries(c))s[l]=M(f);return r.parse(s)}function d(c){let s={};for(let[l,f]of Object.entries(c))s[l]=M(f);return r.parse(s)}return{findById:async c=>{p(e);let s=i().selectAll();s=m(s,[{field:"id",value:c}]);let l=await s.executeTakeFirst();return l?y(l):null},findOne:async c=>{p(e);let s=i().selectAll();s=m(s,b(c));let l=await s.executeTakeFirst();return l?y(l):null},findMany:async c=>{p(e);let s=i().selectAll();return s=m(s,b(c?.where)),typeof c?.limit=="number"&&(s=s.limit(c.limit)),typeof c?.offset=="number"&&(s=s.offset(c.offset)),(await s.execute()).map(f=>y(f))},create:async c=>{p(e);let s=new Date,l={id:c.id??T(),created_at:s,updated_at:s,...c},f=await a().values(l).returningAll().executeTakeFirst();return f?y(f):d(l)},update:async(c,s)=>{p(e);let l={...s,updated_at:new Date},f=u().set(l).returningAll();f=m(f,[{field:"id",value:c}]);let g=await f.executeTakeFirst();return g?y(g):null},updateMany:async(c,s)=>{p(e);let l={...s,updated_at:new Date},f=i().select("id");f=m(f,b(c));let g=await f.execute();for(let E of g){let _=u().set(l);_=m(_,[{field:"id",value:E.id}]),await _.execute()}return g.length},delete:async c=>{p(e);let s=o();s=m(s,[{field:"id",value:c}]);let l=await s.executeTakeFirst();return Number(l?.numDeletedRows??0)>0},deleteMany:async c=>{p(e);let s=o();s=m(s,b(c));let l=await s.executeTakeFirst();return Number(l?.numDeletedRows??0)},count:async c=>{p(e);let s=i().select(f=>f.fn.countAll().as("count"));s=m(s,b(c));let l=await s.executeTakeFirst();return fe(l?.count)}}}function pe(e){let t=k(e,"corsair_integrations");return{...t,findByName:r=>t.findOne({name:r}),upsertByName:async(r,n)=>{let i=await t.findOne({name:r});return i?await t.update(i.id,n):t.create({...n,name:r})}}}function ge(e){let t=k(e,"corsair_accounts");return{...t,findByTenantAndIntegration:async(r,n)=>{p(e);let i=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();return i?t.findOne({tenant_id:r,integration_id:i.id}):null},listByTenant:(r,n)=>t.findMany({where:{tenant_id:r},limit:n?.limit,offset:n?.offset}),upsertByTenantAndIntegration:async(r,n,i)=>{let a=await t.findOne({tenant_id:r,integration_id:n});return a?await t.update(a.id,i):t.create({...i,tenant_id:r,integration_id:n})}}}function me(e){let t=k(e,"corsair_entities");return{...t,findByEntityId:({accountId:r,entityType:n,entityId:i})=>t.findOne({account_id:r,entity_type:n,entity_id:i}),findManyByEntityIds:async({accountId:r,entityType:n,entityIds:i})=>i.length===0?[]:(p(e),await e.db.selectFrom("corsair_entities").selectAll().where("account_id","=",r).where("entity_type","=",n).where("entity_id","in",i).execute()),listByScope:({accountId:r,entityType:n,limit:i,offset:a})=>t.findMany({where:{account_id:r,entity_type:n},limit:i,offset:a}),searchByEntityId:async({accountId:r,entityType:n,query:i,limit:a,offset:u})=>{p(e);let o=e.db.selectFrom("corsair_entities").selectAll().where("account_id","=",r).where("entity_type","=",n).where("entity_id","like",`%${i}%`);return typeof a=="number"&&(o=o.limit(a)),typeof u=="number"&&(o=o.offset(u)),await o.execute()},upsertByEntityId:async({accountId:r,entityType:n,entityId:i,version:a,data:u})=>{let o=await t.findOne({account_id:r,entity_type:n,entity_id:i});return o?await t.update(o.id,{version:a,data:u}):t.create({account_id:r,entity_type:n,entity_id:i,version:a,data:u})},deleteByEntityId:async({accountId:r,entityType:n,entityId:i})=>{p(e);let a=await e.db.deleteFrom("corsair_entities").where("account_id","=",r).where("entity_type","=",n).where("entity_id","=",i).executeTakeFirst();return Number(a.numDeletedRows)>0}}}function we(e){let t=k(e,"corsair_events");return{...t,listByAccount:(r,n)=>t.findMany({where:{account_id:r},limit:n?.limit,offset:n?.offset}),listByStatus:(r,n)=>{let i={status:r};return n?.accountId&&(i.account_id=n.accountId),t.findMany({where:i,limit:n?.limit,offset:n?.offset})},listPending:r=>{let n={status:"pending"};return r?.accountId&&(n.account_id=r.accountId),t.findMany({where:n,limit:r?.limit??100})},updateStatus:(r,n)=>t.update(r,{status:n})}}function Q(e){return{integrations:pe(e),accounts:ge(e),entities:me(e),events:we(e)}}function he(e,t,r,n,i){let a=null;async function u(){if(a!==null)return a;p(e);let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",t.integrationName).executeTakeFirst();if(!o)throw new Error(`Integration "${t.integrationName}" not found. Make sure to create the integration first.`);let y=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t.tenantId).where("integration_id","=",o.id).executeTakeFirst();if(!y)throw new Error(`Account not found for tenant "${t.tenantId}" and integration "${t.integrationName}". Make sure to create the account first.`);return a=y.id,a}return p(e),$(e.db,u,r,n,i)}function z(e){let{database:t,integrationName:r,schema:n,tenantId:i}=e,a=Q(t),u={tenantId:i,integrationName:r},o=null;async function y(){if(o!==null)return o;p(t);let c=await t.db.selectFrom("corsair_integrations").selectAll().where("name","=",r).executeTakeFirst();if(!c)throw new Error(`Integration "${r}" not found. Make sure to create the integration first.`);let s=await t.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",i).where("integration_id","=",c.id).executeTakeFirst();if(!s)throw new Error(`Account not found for tenant "${i}" and integration "${r}". Make sure to create the account first.`);return o=s.id,o}let d={};for(let[c,s]of Object.entries(n.entities))d[c]=he(t,u,c,n.version,s);return{...d,$orm:a,$integrationName:r,$tenantId:i,$getAccountId:y}}function $e(e,t){let r=Q(e);return{$tenantId:t,$orm:r,listAccounts:n=>r.accounts.listByTenant(t,n),findAccountByIntegration:n=>r.accounts.findByTenantAndIntegration(t,n),listEntities:async n=>{p(e);let i=await e.db.selectFrom("corsair_accounts").select("id").where("tenant_id","=",t).execute();if(i.length===0)return[];let a=i.map(o=>o.id),u=e.db.selectFrom("corsair_entities").selectAll().where("account_id","in",a);return n?.entityType&&(u=u.where("entity_type","=",n.entityType)),typeof n?.limit=="number"&&(u=u.limit(n.limit)),typeof n?.offset=="number"&&(u=u.offset(n.offset)),await u.execute()},listEvents:async n=>{p(e);let i=await e.db.selectFrom("corsair_accounts").select("id").where("tenant_id","=",t).execute();if(i.length===0)return[];let a=i.map(o=>o.id),u=e.db.selectFrom("corsair_events").selectAll().where("account_id","in",a);return n?.status&&(u=u.where("status","=",n.status)),typeof n?.limit=="number"&&(u=u.limit(n.limit)),typeof n?.offset=="number"&&(u=u.offset(n.offset)),await u.execute()},forIntegration:n=>z({database:e,integrationName:n.integrationName,schema:n.schema,tenantId:t})}}function Me(e,t){return{forTenant:r=>z({database:e,integrationName:t.integrationName,schema:t.schema,tenantId:r})}}export{I as a,O as b,G as c,X as d,Y as e,L as f,R as g,V as h,ee as i,T as j,$ as k,le as l,Q as m,z as n,$e as o,Me as p};
@@ -0,0 +1,38 @@
1
+ import{a as oe,b as yt,c as A,d as $,e as ht,f as z,g as F,h as N,i as Ke,j as mt,k as An,l as kt,m as bt}from"./chunk-NZS35HPL.js";import{a as ft}from"./chunk-IGGCNGU2.js";var je=["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"],wt={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 de(e){let n=wt[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var Se="https://auth.corsair.dev";var pe=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret, deliveryUrl } to createCorsair()."),this.name="HubNotConfiguredError"}};function Ze(e){let n=(e.apiUrl?.trim()||Se).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 Hr(e){return e.apiUrl.trim().length>0&&e.deliveryUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function M(e){let n=A(e).hub;if(!n||!Hr(n))throw new pe;return n}function qe(e){return e.oauthCallbackUrl?e.oauthCallbackUrl:`${e.apiUrl.replace(/\/$/,"")}/oauth/callback`}function B(e){return typeof e=="string"&&e.length>0}function Ct(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!B(n.connectUrl)||!B(n.token)||!B(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 B(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function Pt(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!B(n.approvalUrl)||!B(n.token)||!B(n.projectId)||!B(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 At(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(!B(n.access_token))throw new Error("Hub token refresh returned no access_token");return{access_token:n.access_token,refresh_token:B(n.refresh_token)?n.refresh_token:void 0,expires_in:typeof n.expires_in=="number"?n.expires_in:void 0,scope:B(n.scope)?n.scope:void 0}}function Tt(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}function Ur(e){return e.replace(/\/$/,"")}async function $r(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=Tt(e);return r||`Hub API returned HTTP ${n}`}async function be(e){let n=Ur(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 $r(t);if(!t.ok)throw new Error(Fr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import*as Ee from"crypto";function J(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function Tn(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 ie(e,n){let t=Ee.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var xn=600*1e3;function Ge(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),i=e.slice(t+1),o=Ee.createHmac("sha256",n).update(r).digest("base64url"),s=Buffer.from(i,"base64url"),a=Buffer.from(o,"base64url");return s.length!==a.length||!Ee.timingSafeEqual(s,a)?null:Tn(r,{maxAgeMs:xn})}var Nr=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Oe(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Nr.has(n)}catch{return!1}}function we(e){return Oe(e)?"client":"server"}function xt(e,n){return e==="client"||Oe(n)}function Ce(e){if(!e.source)return null;let n=Oe(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 Lr,ZodDate as Wr,ZodEnum as Kr,ZodNullable as jr,ZodNumber as Zr,ZodObject as qr,ZodOptional as Gr,ZodRecord as zr,ZodString as Jr,ZodType as Vr}from"zod";var Br={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=Br;async function Rt(e,n){let t=[],r=g=>{t.push(g),console.log(g)},i=g=>{t.push(g),console.warn(g)},o=n?.caller??"script",s=yt(e);if(!s)throw new Error("setupCorsair: invalid corsair instance");if(!s.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let a=Qr(e,s.plugins,n),u={...s,database:s.database},c=u.database.db;await no(c,i);let d=await to(c,u,a.tenantId,a.provisionAccounts,r);n?.credentials&&Object.keys(n.credentials).length>0&&await io(e,a,n.credentials,u,r,i);let l=await ao(d,a,r,o);if(n?.backfill){r("[corsair:setup] Starting backfill...");let g=_t({plugins:s.plugins,database:c,kek:s.kek,multiTenancy:!0}).withTenant(a.tenantId);await uo(g,s.plugins,l,r,i),r("[corsair:setup] Backfill complete.")}return t.join(`
2
+ `)}function Rn(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...F[n][t],...r])}function Yr(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let i=n.find(a=>a.id===t);if(!i)continue;let o=N(i);if(!o)continue;let s=Rn(i,o,"account");for(let a of Object.keys(r))if(s.has(a))return!0}return!1}function Qr(e,n,t){let r=ht(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&&Yr(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 It(e,n){return oe(e)?n===0?!0:Object.values(e).every(t=>It(t,n-1)):!1}function Xr(e){return It(e,4)}var eo={...kt};function ze(e){if(e instanceof qr){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Vr?ze(r):"unknown";return n}return e instanceof jr?`${ze(e.unwrap())} | null`:e instanceof Gr?`${ze(e.unwrap())} | undefined`:e instanceof Kr?e.options.join(" | "):e instanceof Jr?"string":e instanceof Zr?"number":e instanceof Lr?"boolean":e instanceof Wr?"date":e instanceof zr?"jsonb":"unknown"}async function no(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(i=>i.name));for(let[i,o]of Object.entries(eo))r.has(i)||n(`[corsair:setup] Table "${i}" does not exist. Run your database migrations before calling setupCorsair.
3
+ Schema: ${JSON.stringify(ze(o),null,2)}`)}async function to(e,n,t,r,i){let o=new Date,s=new Map;for(let a of n.plugins){let u=a.id,c=N(a),d=await e.selectFrom("corsair_integrations").selectAll().where("name","=",u).executeTakeFirst();if(!d){let y=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:y,name:u,config:{},created_at:o,updated_at:o}).execute(),d=await e.selectFrom("corsair_integrations").selectAll().where("id","=",y).executeTakeFirst(),i(`[corsair:setup] Created integration: ${u}`)}let l=c?a.authConfig?.[c]?.integration??[]:[],g=c?a.authConfig?.[c]?.account??[]:[],f=c&&d?O({authType:c,integrationName:u,kek:n.kek,database:n.database,extraIntegrationFields:l}):void 0;if(d&&!d.dek&&f&&(await f.issue_new_dek(),i(`[corsair:setup] Issued integration DEK: ${u}`)),!d||!c||!f)continue;let p;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}`)}p=y&&I({authType:c,integrationName:u,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),y&&p&&!y.dek&&(await p.issue_new_dek(),i(`[corsair:setup] Issued account DEK: ${u}`))}s.set(u,{pluginId:u,authType:c,integration:f,account:p,integrationFields:[...F[c].integration,...l],accountFields:r?[...F[c].account,...g]:[]})}return s}function ro(e){if(!oe(e))return;let n=e.keys;return oe(n)?n:void 0}function oo(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function io(e,n,t,r,i,o){let s=ro(e),a=n.provisionAccounts?oo(e,n.tenantId):void 0;for(let[u,c]of Object.entries(t)){let d=r.plugins.find(m=>m.id===u);if(!d){o(`[corsair:setup] Unknown plugin '${u}' \u2014 skipping credentials.`);continue}let l=N(d);if(!l){o(`[corsair:setup] Plugin '${u}' has no auth type \u2014 skipping credentials.`);continue}let g=Rn(d,l,"integration"),f=Rn(d,l,"account"),p=s?.[u],y=a?.[u],h=oe(y)?y.keys:void 0;for(let[m,C]of Object.entries(c))if(C){if(g.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=z(p,`set_${m}`);if(!b){o(`[corsair:setup] Cannot set integration field '${m}' for '${u}'.`);continue}await b(C),i(`[corsair:setup] Set ${u} integration.${m}`);continue}if(f.has(m)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${u}.${m}' on a multi-tenant instance`);let b=z(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 vt=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function so(e,n,t,r,i,o,s,a,u){let c=[],d=[];for(let g of i){if(vt.has(g))continue;let f=z(t,`get_${g}`);if(!f)continue;let p=null;try{let y=await f();p=typeof y=="string"?y:null}catch{}p||c.push(g)}if(r&&o.length>0)for(let g of o){if(vt.has(g))continue;let f=z(r,`get_${g}`);if(!f)continue;let p=null;try{let y=await f();p=typeof y=="string"?y:null}catch{}p||d.push(g)}let l=c.length===0&&d.length===0;if(l)a(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else{let g=[...c,...d];if(u==="cli"){let f=g.map(p=>`${p}=VALUE`).join(" ");a(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
+ corsair setup --${e} ${f}`)}else{let f=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let p of c)f.push(` await corsair.keys.${e}.set_${p}(value)`);for(let p of d){let y=s.provisionAccounts?s.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(s.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;f.push(` await ${y}.keys.set_${p}(value)`)}a(f.join(`
5
+ `))}}return l}async function ao(e,n,t,r){let i=new Set;for(let o of e.values())await so(o.pluginId,o.authType,o.integration,o.account,o.integrationFields,o.accountFields,n,t,r)&&i.add(o.pluginId);return i}async function uo(e,n,t,r,i){if(!Xr(vn)){i("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let o=vn,s=new Set(n.map(a=>a.id));for(let[a,u]of Object.entries(o)){if(!s.has(a))continue;if(!t.has(a)){r(`[corsair:setup] Skipping backfill for '${a}' \u2014 auth not configured.`);continue}let c=oe(e)?e[a]:void 0,d=oe(c)?c.api:void 0;if(d)for(let[l,g]of Object.entries(u))for(let[f,p]of Object.entries(g)){r(`[corsair:setup] Backfilling ${a} \u203A ${l}.${f}...`);try{let y=oe(d)?d[l]:void 0;await z(y,f)?.(p)}catch(y){i(`[corsair:setup] ${a} \u203A ${l}.${f} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Pe(e,n){if(!A(e).database)throw new Error("A database must be configured to provision Corsair for connect");await Rt(e,{tenantId:n})}var co=new Set(["webhook_signature","expires_at","scope"]);function lo(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function po(e){return e==="oauth_2"||e==="managed"?["access_token"]:e==="api_key"?["api_key"]:e==="bot_token"?["bot_token"]:[]}async function go(e,n,t,r){let i=po(t);if(i.length===0)return!0;let s=(typeof e.withTenant=="function"?e.withTenant(r):e)[n.id],a=s&&typeof s=="object"&&"keys"in s?s.keys:null;if(!a)return!1;for(let u of i){if((t==="oauth_2"||t==="managed")&&u==="refresh_token")continue;let c=z(a,`get_${u}`);if(!c)continue;let d=null;try{let l=await c();d=typeof l=="string"?l:null}catch{d=null}if(!d)return!1}return!0}function fo(e,n){return e==="oauth_2"||e==="managed"?[]:n.filter(t=>!co.has(t))}async function St(e,n,t={}){let r=A(e),i=M(e),o=qe(i),s=[],a=t.pluginIds?new Set(t.pluginIds):null;for(let u of r.plugins){if(a&&!a.has(u.id))continue;let c=N(u);if(!c)continue;let d=lo(c),l=t.providerNameOverrides?.[u.id]??de(u.id),g=await go(e,u,c,n),f=Ke(u,c),p={plugin:u.id,providerName:l,authKind:d,alreadyConfigured:g};if(d==="oauth"){let h=t.oauthModeOverrides?.[u.id]??(c==="managed"?"managed":"byo");if(p.oauthMode=h,!t.skipOAuthUrlGeneration)if(h==="managed")p.state=ie(J(u.id,n),r.kek);else try{let m=await In(e,u.id,{tenantId:n,redirectUri:o});p.oauthUrl=m.url,p.state=m.state}catch(m){p.setupError=m instanceof Error?m.message:`Could not prepare OAuth for ${u.id}`}}else{let y=fo(c,f);y.length>0&&(p.credentialFields=y)}s.push(p)}return s}function Et(e,n){let t=M(e);if(n){let r=Ce({source:n,deliveryUrl:t.deliveryUrl});if(r)throw new Error(r.error);return n}return we(t.deliveryUrl)}async function Ot(e,n){await Pe(e,n)}async function Je(e,n){let t=M(e);await Ot(e,n.tenantId);let r=n.plugin?[n.plugin]:void 0,i=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,o=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,s=await St(e,n.tenantId,{pluginIds:r,oauthModeOverrides:i,providerNameOverrides:o});if(s.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is not configured on this Corsair instance`:"No plugins are configured on this Corsair instance");let a=Et(e,n.source);return be({hub:t,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{tenantId:n.tenantId,deliveryUrl:t.deliveryUrl,source:a,plugins:s},parseResponse:Ct})}import{createCipheriv as Dt,createDecipheriv as Mt,randomBytes as Ve,scrypt as yo}from"crypto";import{promisify as ho}from"util";var Ht=ho(yo),Ye="aes-256-gcm",Ut=12,Qe=16,mo=16,De=32;function X(){return Ve(De).toString("base64")}async function ee(e,n){let t=Ve(mo),r=await Ht(n,t,De),i=Ve(Ut),o=Dt(Ye,r,i,{authTagLength:Qe}),s=Buffer.concat([o.update(e,"utf8"),o.final()]),a=o.getAuthTag();return[t.toString("base64"),i.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function L(e,n){let[t,r,i,o]=e.split(":");if(!t||!r||!i||!o)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),u=Buffer.from(i,"base64"),c=Buffer.from(o,"base64"),d=await Ht(n,s,De),l=Mt(Ye,d,a,{authTagLength:Qe});return l.setAuthTag(u),Buffer.concat([l.update(c),l.final()]).toString("utf8")}function _n(e,n){let t=Buffer.from(n,"base64"),r=Ve(Ut),i=Dt(Ye,t,r,{authTagLength:Qe}),o=Buffer.concat([i.update(e,"utf8"),i.final()]),s=i.getAuthTag();return[r.toString("base64"),s.toString("base64"),o.toString("base64")].join(":")}function Me(e,n){let[t,r,i]=e.split(":");if(!t||!r||!i)throw new Error("Invalid encrypted data format");let o=Buffer.from(n,"base64"),s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),u=Buffer.from(i,"base64"),c=Mt(Ye,o,s,{authTagLength:Qe});return c.setAuthTag(a),Buffer.concat([c.update(u),c.final()]).toString("utf8")}function se(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=_n(i,n);return t}function ne(e,n){let t={};for(let[r,i]of Object.entries(e))t[r]=Me(i,n);return t}function He(e,n,t){let r=ne(e,n);return se(r,t)}function $t(e,n,t){let r={};for(let i of t)r[`get_${i}`]=async()=>(await e())[i]??null,r[`set_${i}`]=async o=>{let s=[null,void 0,""].includes(o)?null:o;await n({[i]:s})};return r}var Sn=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function O(e){let{authType:n,integrationName:t,kek:r,database:i,extraIntegrationFields:o=[]}=e,s=[...F[n].integration,...o],a=null,u={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let p=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!p)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:p.id,config:Sn(p.config),dek:p.dek??null},a},updateIntegration:async p=>{let y=await u.getIntegration();await i.db.updateTable("corsair_integrations").set({...p.config!==void 0?{config:p.config}:{},...p.dek!==void 0?{dek:p.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),a=null}},c=null,d=async()=>{if(c)return c;let p=await u.getIntegration();if(!p.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return c=await L(p.dek,r),c},l=async()=>{let p=await u.getIntegration(),y=await d(),h=p.config;return!h||Object.keys(h).length===0?{}:ne(h,y)};return{get_dek:d,issue_new_dek:async()=>{let p=await u.getIntegration(),y=X(),h={};if(p.dek){let C=await L(p.dek,r),b=p.config;b&&Object.keys(b).length>0&&(h=He(b,C,y))}let m=await ee(y,r);return await u.updateIntegration({config:h,dek:m}),c=y,y},...$t(l,async p=>{let y=await d(),h;try{h=await l()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,b),h={}}let m={...h};for(let[b,k]of Object.entries(p))k===null?delete m[b]:m[b]=k;let C=se(m,y);await u.updateIntegration({config:C})},s)}}function I(e){let{authType:n,integrationName:t,tenantId:r,kek:i,database:o,extraAccountFields:s=[]}=e,a=[...F[n].account,...s],u=null,c=null,d=async()=>{if(c)return c;let k=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!k)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return c={id:k.id,config:Sn(k.config),dek:k.dek??null},c},l={kek:i,integrationName:t,tenantId:r,getIntegration:d,getAccount:async()=>{if(u)return u;let k=await d(),w=await o.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",k.id).executeTakeFirst();if(!w)throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`);return u={id:w.id,config:Sn(w.config),dek:w.dek??null},u},updateAccount:async k=>{let w=await l.getAccount();await o.db.updateTable("corsair_accounts").set({...k.config!==void 0?{config:k.config}:{},...k.dek!==void 0?{dek:k.dek}:{},updated_at:new Date}).where("id","=",w.id).execute(),u=null}},g=null,f=null,p=async()=>{if(g)return g;let k=await l.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return g=await L(k.dek,i),g},y=async()=>{if(f)return f;let k=await l.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return f=await L(k.dek,i),f},h=async()=>{let k=await l.getAccount(),w=await p(),P=k.config;return!P||Object.keys(P).length===0?{}:ne(P,w)},m=async()=>{let k=await l.getIntegration(),w=await y(),P=k.config;return!P||Object.keys(P).length===0?{}:ne(P,w)},b={get_dek:p,issue_new_dek:async()=>{let k=await l.getAccount(),w=X(),P={};if(k.dek){let S=await L(k.dek,i),E=k.config;E&&Object.keys(E).length>0&&(P=He(E,S,w))}let _=await ee(w,i);return await l.updateAccount({config:P,dek:_}),g=w,w},...$t(h,async k=>{let w=await p(),P;try{P=await h()}catch(E){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,E),P={}}let _={...P};for(let[E,x]of Object.entries(k))x===null?delete _[E]:_[E]=x;let S=se(_,w);await l.updateAccount({config:S})},a)};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 Ft(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 Nt(e,n,t,r){let i=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!i)throw new Error(`Integration "${n}" not found.`);let o=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",i.id).executeTakeFirst();if(!o)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let s=X(),a=await ee(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",o.id).execute(),s}import*as Bt from"querystring";function Ae(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}?${Bt.stringify(o)}`}var W=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function ko(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 En(e,n){let t=A(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=Ge(n,t.kek);if(!i)throw new W("invalid_state","Invalid or tampered state parameter");let{plugin:o,tenantId:s}=i,a=$(t,o,g=>new W("plugin_not_found",g)),u=ko(a),d=await O({authType:"oauth_2",integrationName:o,kek:t.kek,database:t.database}).get_client_id();if(!d)throw new W("client_id_not_configured",`client_id not configured for '${o}'`);let l=Ae({oauthConfig:u,clientId:d,redirectUri:r,state:n});return{plugin:o,tenantId:s,providerName:u.providerName,oauthUrl:l,state:n}}import{randomBytes as wo}from"crypto";import{v4 as Co}from"uuid";async function On(e,n){return be({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:Pt})}function Dn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var Mn="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 Un(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function Lt(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function Hn(e){return Dn(e)}async function $n(e,n){if(Un(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?Lt(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await On(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:bo(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function bo(e){try{return JSON.parse(e)}catch{return e}}async function Xe(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await $n(e,n);return{...n,approvalUrl:r}}async function Fn(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:i,permissionToken:o,plugin:s,endpoint:a,args:u,tenantId:c,expiresAt:d,operationPath:l}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:o,id:i,plugin:s,endpoint:a,args:u});let f=await $n({manual:t,hub:r},{id:i,token:o,plugin:s,endpoint:a,args:JSON.stringify(u),tenant_id:c,expires_at:d});return Un(t)?f?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:f}):Hn(f):Mn:r?f?Hn(f):`Action '${l}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:Mn}var Po={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 Ao(e,n,t){return t!==void 0?t:Po[n][e]}function Nn(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 Kt(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 Wt(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 jt(e){let n=Ao(e.riskLevel,e.mode,e.override);if(n==="allow")return{result:"allow"};let t=e.meta?.irreversible?" (irreversible)":"",r=e.meta?.description?`${e.meta.description}${t}`:`${e.pluginId}.${e.endpointPath}${t}`;if(n==="deny"||!e.db)return console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 denied by permission mode '${e.mode}'.`,`
6
+ Action: ${r}`,`
7
+ To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let i=JSON.stringify(e.args),o=new Date().toISOString(),s=e.tenantId??"default",a=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",i).where("tenant_id","=",s).where("expires_at",">",o).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(a){if(a.status==="approved"){let p=e.db,y=a.id;return{result:"allow",onComplete:async()=>{await p.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",y).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
8
+ Action: ${r}`,`
9
+ Permission ID: ${a.id}`,`
10
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Wt(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:a.id,token:a.token,expiresAt:a.expires_at})}let u=Co(),c=wo(32).toString("hex"),d=e.timeoutMs??600*1e3,l=new Date(Date.now()+d).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:u,created_at:new Date,updated_at:new Date,token:c,plugin:e.pluginId,endpoint:e.endpointPath,args:i,tenant_id:s,status:"pending",expires_at:l}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
11
+ Action: ${r}`,`
12
+ Permission ID: ${u}`,`
13
+ Permission token: ${c}`,`
14
+ Expires at: ${l}`,`
15
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Wt(e.db,u,d):{result:"blocked",reason:"pending",id:u,token:c,expiresAt:l}}var T=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 v(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function Zt(e){let n={error:e.code,message:e.message,...e.extra};return v(e.status,n)}function ae(e){return new T(404,"not_found",e)}function V(e,n={}){return new T(400,"bad_request",e,n)}function qt(e,n){return $(e,n,t=>ae(t))}async function Bn(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=O({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),i=F[t].integration,o=r,s;try{s=await Promise.all(i.map(c=>o[`get_${c}`]()))}catch{s=i.map(()=>null)}let a=i.filter((c,d)=>s[d]==null),u;return t==="oauth_2"?u=!a.includes("client_id")&&!a.includes("client_secret"):u=a.length===0,{configured:u,missingFields:a}}async function Gt(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await Bn(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 en(){return{ok:!0}}async function nn(e){return Promise.all(e.plugins.map(n=>Gt(n,e)))}async function tn(e,n){let t=qt(e,n);return Gt(t,e)}async function zt(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 Jt(e,n){let t=await zt(e,n),r=t.filter(i=>i.hasCredentials).map(i=>i.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function rn(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let i=r.tenant_id;if(!i)continue;let o=n.get(i);o||(o={id:i,accounts:[],connectedPlugins:[]},n.set(i,o));let s=!!r.dek;o.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&o.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function on(e,n){if(!n)throw V("Tenant id must be a non-empty string");return Jt(e,n)}async function sn(e,n){let t=n?.id?.trim();if(!t)throw V("Tenant id is required",{missingFields:["id"]});return Jt(e,t)}async function Te(e,n){let t=n?.trim()||"default",r={},i=e.database?await zt(e,t):[],o=new Map(i.map(s=>[s.integrationName,s]));for(let s of e.plugins){if(!(await Bn(s,e)).configured){r[s.id]="missing_credentials";continue}let u=o.get(s.id),c;u&&u.hasCredentials?c="connected":c="not_connected",r[s.id]=c}return r}async function Ln(e,n){if(!e.database)throw ae(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ae(`Permission '${n}' not found`);return Xe(e,t)}function To(e){if(!e.oauthConfig)throw V(`Plugin '${e.id}' has no oauthConfig`)}function xo(e){if(!e.manual)throw new T(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function Wn(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}function Kn(e){let n=xo(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new T(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 vo(e){let n=!!e.hub,t=Wn(e.manual);if(!n&&!t)throw new T(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function Vt(e){if(!e.database||!e.kek)throw new T(500,"database_not_configured","A database and kek are required to issue connect links.")}async function Ro(e,n){let t=n?.plugin?.trim();if(!t)throw V("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=qt(e,t);To(i);let o=Kn(e);Vt(e);let s=await Bn(i,e);if(!s.configured)throw new T(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:s.missingFields});let a=ie(J(t,r),e.kek),u;try{u=new URL(o.baseUrl)}catch{throw new T(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",a),{connectUrl:u.toString(),expiresAt:new Date(Date.now()+xn).toISOString()}}async function Io(e,n,t){Vt(n);let r=t.tenantId?.trim()||"default",i=M(e);if(t.source){let c=Ce({source:t.source,deliveryUrl:i.deliveryUrl,oauthMode:t.oauthMode});if(c)throw V(c.error)}let o={tenantId:r,source:t.source??we(i.deliveryUrl),oauthMode:t.oauthMode},s=t.plugin?.trim();s&&(o.plugin=s);let a=t.providerName?.trim();a&&(o.providerName=a);let u=await Je(e,o);return{connectUrl:u.connectUrl,expiresAt:u.expiresAt}}async function an(e,n,t){return vo(n),n.hub?Io(e,n,t):Ro(n,t)}async function un(e,n,t){if(n.hub&&!Wn(n.manual))throw new T(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw V("state is required",{missingFields:["state"]});Kn(n);try{return await En(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw V("Invalid or expired state");case"client_id_not_configured":throw new T(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new T(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function cn(e,n,t){if(n.hub&&!Wn(n.manual))throw new T(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),i=t?.state?.trim(),o=[];if(r||o.push("code"),i||o.push("state"),o.length)throw V("Missing required fields",{missingFields:o});let s=Kn(n),{processOAuthCallback:a}=await import("./oauth.js");try{return await a(e,{code:r,state:i,redirectUri:s.redirectUri})}catch(u){if(u instanceof Error&&u.name==="OAuthCallbackError")switch(u.code){case"invalid_state":throw V("Invalid or expired state");case"credentials_not_configured":throw new T(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new T(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function jn(e,n){if(!e.database)throw ae("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ae("Permission not found");return Xe(e,t)}async function Yt(e,n){return"id"in n?Ln(e,n.id):jn(e,n.token)}function _o(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function So(e,n){return n&&!n.has(e.id)?!1:N(e)!==null}async function Ue(e,n,t={}){let r=A(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,s=await Te(r,i),a=r.plugins.filter(u=>So(u,o)).map(u=>{let c=N(u),d=s[u.id]??"not_connected";return{plugin:u.id,providerName:de(u.id),authKind:_o(c),connected:d==="connected"}});return{tenantId:i,plugins:a}}var Y=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function ln(e,n){let t=A(e,()=>new Y("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Y("no_database","Database not configured");let r=$(t,n.plugin,d=>new Y("plugin_not_found",d)),i=N(r);if(!i)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new Y("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Pe(e,n.tenantId);let o=new Set(Ke(r,i)),a=r.authConfig?.[i]?.account??[],u=I({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a}),c=0;for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!o.has(d))throw new Y("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let g=z(u,`set_${d}`);if(!g)throw new Y("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await g(l.trim()),c+=1}if(c===0)throw new Y("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var dn=new Map;function Eo(e){for(let[n,t]of dn)t<=e&&dn.delete(n)}function pn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return Eo(r),dn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(dn.set(t,r+n),{ok:!0})}async function gn(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 Qt=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function Oo(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 Do(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=Qt(n.config),i={};Object.keys(r).length>0&&(i=ne(r,t)),i[e.link.linkType]=e.link.externalId;let o=se(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function xe(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:s,extraAccountFields:a=[]}=e,{accountId:u}=await Oo({database:n,pluginId:r,tenantId:i}),c=!1;if(s){let d=I({authType:s,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:a}),l=`set_${o.linkType}`,g=d[l];typeof g=="function"&&(await g(o.externalId),c=!0)}c||await Do({database:n,kek:t,accountId:u,link:o})}async function Zn(e){let{database:n,kek:t,pluginId:r,linkType:i,externalId:o}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let u=await L(a.dek,t),d=Qt(a.config)[i];if(!d)continue;if(Me(d,u)===o)return a}catch{continue}return null}async function fn(e){return(await Zn(e))?.tenant_id??null}async function Xt(e){return fn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var ue=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function ve(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:s,scope:a}=n;if(!i.trim())throw new ue("no_access_token","Managed OAuth delivery missing access_token");let u=A(e,()=>new ue("invalid_corsair_instance","Invalid corsair instance"));if(!u.database)throw new ue("no_database","No database configured on corsair instance");let c=$(u,t,l=>new ue("plugin_not_found",l));await Pe(e,r);let d=I({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),s&&await d.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await d.set_scope(a);try{let l=await gn(u.plugins,t,{access_token:i,refresh_token:o,scope:a});if(l)try{let g=c.authConfig?.managed?.account??[];await xe({database:u.database,kek:u.kek,pluginId:t,tenantId:r,link:l,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(l){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,l)}return{plugin:t,tenantId:r}}function Mo(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function er(e,n,t=[]){for(let[r,i]of Object.entries(e))if(Mo(i)){if(i.match(n))return{webhook:i,path:[...t,r]}}else if(i&&typeof i=="object"){let o=er(i,n,[...t,r]);if(o)return o}return null}function Ho(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Uo(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 nr(e,n,t,r){let i=Ho(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=Uo(i)||o);let a={headers:i,body:o,...r?{query:r}:{}},u=r?.tenantId||"default",c=e.withTenant?e.withTenant(u):e,d=je;for(let l of d){let g=c[l];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(a))continue;let f=er(g.webhooks,a);if(!f)continue;let p=f.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let h=await f.webhook.handler(y),m=!!Object.keys(h.returnToSender||{})?.length;return{plugin:l,action:p,body:o,response:m?{...h?.returnToSender,success:!0}:{success:!0},...h.responseHeaders&&{responseHeaders:h.responseHeaders}}}catch(h){return console.error(`Error executing webhook handler for ${l}.${p}:`,h),{plugin:l,action:p,body:o,response:{success:!1,error:h instanceof Error?h.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{createHmac as $o,timingSafeEqual as Fo}from"crypto";var No=300*1e3;function Bo(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function qn(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Bo(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)>No)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let o=$o("sha256",n).update(e.body).digest("hex");try{if(!Fo(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}}import{createHmac as Lo,timingSafeEqual as Wo}from"crypto";function ge(e){return e.deliveryMode==="connect.status"}function fe(e){return e.deliveryMode==="auth.credentials"}function $e(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function Fe(e){return e.deliveryMode==="oauth.tokens"}function yn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!ge(e)&&!fe(e)&&!$e(e)&&!Fe(e)}function rr(e){let n=e.trim();return n.length>0?n:null}function Ko(e,n){let t=rr(n);if(!t)throw new Error("Signing secret is required for browser delivery tokens");return Lo("sha256",t).update(e).digest("base64url")}function hn(e,n){let t=rr(n);if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[i,o]=r;if(!i||!o)return null;let s=Ko(i,t);try{if(!Wo(Buffer.from(o,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(i,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function Gn(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 Zo(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 fn({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function qo(e,n,t){let r=await Zo(e,n,t),i={...t.query??{},...r?{tenantId:r}:{}},o=await nr(e,t.headers,t.body,i);if(!o.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(o.response&&o.response.success===!1)return{status:"failed",retryable:!1,error:typeof o.response.error=="string"?o.response.error:"Webhook handler failed"};let s=o.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(o.response?.data??o.response);return{status:"ok",webhookResponse:{status:o.response?.statusCode??200,body:a,headers:o.responseHeaders}}}async function Go(e,n){return await Ne(e,n),{status:"ok"}}async function zo(e,n){return await ve(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function Jn(e,n,t){let r=await zn(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function zn(e,n,t){let r=A(e),i=n.token?.trim();if(!i)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let o=new Date().toISOString(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",i).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<o?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Jo(e,n){try{return await ln(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function Vo(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await Ue(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function Vn(e,n,t={}){let r=A(e),i=Gn(n.headers,"x-corsair-signature"),o=Gn(n.headers,"x-corsair-timestamp"),s=Gn(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let u=qn({body:n.body,signatureHeader:i,timestampHeader:o,signingSecret:t.signingSecret});if(!u.ok)return{status:"failed",retryable:!1,error:u.error};if(!s?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let c=pn(`nonce:${s.trim()}`,3e5);if(!c.ok)return{status:"failed",retryable:!1,error:c.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let a;try{a=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(a.type){case"webhook":return qo(e,r,a.payload);case"oauth.callback":return Go(e,a.payload);case"oauth.tokens":return zo(e,a.payload);case"permission.approve":return zn(e,a.payload,"approved");case"permission.deny":return zn(e,a.payload,"denied");case"auth.credentials":return Jo(e,a.payload);case"connect.status":return Vo(e,a.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${a.type}`}}}var Yo="corsair:client-bridge";function or(e){let n=JSON.stringify({type:Yo,requestId:e.requestId,ok:e.ok,body:e.body??null,error:e.error??null}),t=JSON.stringify(e.hubOrigin);return`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><script>
16
+ (function () {
17
+ var message = ${n};
18
+ var targetOrigin = ${t};
19
+ if (window.parent && window.parent !== window) {
20
+ window.parent.postMessage(message, targetOrigin);
21
+ }
22
+ })();
23
+ </script></body></html>`}var Qo=[".corsair.dev"];function Xo(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function ei(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Xo(n)?!0:Qo.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function ir(e){return!e||!ei(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 sr(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 mn(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 Yn(e,n){let t=M(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=hn(i,t.signingSecret);if(!o)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let s=pn(`browser:${o.jti}`,6e4);if(!s.ok)return{type:"json",status:400,body:{error:s.error}};try{if(ge(o)){if(!o.hubSuccessUrl)return{type:"json",status:400,body:{error:"Connect status delivery missing hubSuccessUrl"}};let a=o.tenantId?.trim()||"default",u=await Ue(e,a,{pluginIds:o.statusPlugins});return{type:"redirect",url:mn(o.hubSuccessUrl,{status:u})}}if(fe(o))return o.hubSuccessUrl?o.credentials?(await ln(e,{plugin:o.plugin,tenantId:o.tenantId,credentials:o.credentials}),{type:"redirect",url:mn(o.hubSuccessUrl,{connectedPlugin:o.plugin})}):{type:"redirect",url:mn(o.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if($e(o)){if(!o.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await Jn(e,o.permissionToken,o.deliveryMode==="permission.approve"?"approved":"denied")}else if(Fe(o)){if(!o.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await ve(e,{plugin:o.plugin,tenantId:o.tenantId,accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.expiresIn,scope:o.scope})}else{if(!yn(o)||!o.code||!o.state||!o.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await Ne(e,{code:o.code,state:o.state,redirectUri:o.redirectUri})}}catch(a){let u=a instanceof Error?a.message:"Hub delivery failed";return(ge(o)||fe(o))&&o.hubSuccessUrl?{type:"redirect",url:mn(o.hubSuccessUrl,{error:u})}:(ge(o)||fe(o))&&o.hubOrigin&&o.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:or({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 Qn(e,n){let t=M(e),r=await Vn(e,n,{signingSecret:t.signingSecret});if(r.status!=="ok")return{type:"json",status:r.retryable===!1?400:502,body:{error:r.error??"Tunnel processing failed"}};let i=r.webhookResponse;if(!i)return{type:"json",status:200,body:{status:"ok"}};let o=i.status??200,s=i.headers;return i.body&&typeof i.body=="object"&&!(i.body instanceof ArrayBuffer)?{type:"json",status:o,body:i.body,headers:s}:{type:"text",status:o,body:typeof i.body=="string"?i.body:i.body?JSON.stringify(i.body):null,headers:s}}function Xn(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 et(e,n){return n.method==="GET"?Yn(e,n.url):Qn(e,{headers:n.headers,body:n.body??""})}async function nt(e,n){try{let t=await et(e,n);return Xn(t)}catch(t){if(t instanceof pe)return Response.json({error:t.message},{status:503});throw t}}async function Be(e,n){let t=n.method.toUpperCase(),r=ir(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 nt(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return sr(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 ni=300;async function tt(e,n){let{keys:t,hub:r,plugin:i,tenantId:o}=e,s=n?.forceRefresh??!1,[a,u,c]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!a&&!c)throw new te(i,"managed");let d=Math.floor(Date.now()/1e3);if(!s&&a&&u&&Number(u)>d+ni)return{accessToken:a,expiresAt:Number(u),refreshed:!1};if(!c&&a&&!s)return{accessToken:a,expiresAt:u?Number(u):d+3600,refreshed:!1};let l=await be({hub:r,path:"/oauth/refresh",body:{plugin:i,tenantId:o},parseResponse:At}),g=l.expires_in?d+l.expires_in:u?Number(u):d+3600;return await t.set_access_token(l.access_token),await t.set_expires_at(String(g)),l.refresh_token&&await t.set_refresh_token(l.refresh_token),l.scope&&await t.set_scope(l.scope),{accessToken:l.access_token,expiresAt:g,refreshed:!0}}async function ar(e,n){e._refreshAuth=async()=>(await tt(n,{forceRefresh:!0})).accessToken}function ur(e){return{delivery:n=>Be(e,n),deliveryOptions:n=>Be(e,n)}}function kn(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(i,o){let s=t.length>1;throw new Error(`corsair.keys.${String(o)}: Cannot access keys because ${t.join(" and ")} ${s?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
24
+
25
+ To generate a KEK, run: openssl rand -base64 ${De}`)}})}var ti=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function cr(e,n,t,r,i){let o={pluginId:n,operation:t,input:r,originalError:e},s=Object.keys(i).find(c=>i[c]?.match(e,o));return await(i[s||"DEFAULT"]?.handler||ti)(e,o)}function ri(e){return typeof e=="function"}function oi(e,n,t){let r=ie(J(e,n.tenantId??t??"default"),n.kek),i=new URL(n.baseUrl);i.searchParams.set("state",r);let o=i.toString(),s=n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:o,state:r}):`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${o}`;return new Error(s)}function rt({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:i,errorHandlers:o,currentPath:s=[],keyBuilder:a,permissionsConfig:u,endpointMeta:c,database:d,permissionsOptions:l,tenantId:g,manualConfig:f,hubConfig:p}){for(let[y,h]of Object.entries(e)){let m=n?.[y];if(ri(h)){let C=m,b=[...s,y].join("."),k=async(w={})=>{let P;if(u){let R=c?.[b],{result:ke,reason:q,onComplete:_e,token:Q,id:le,expiresAt:U}=await jt({pluginId:i,endpointPath:b,args:w,mode:u.mode,override:u.overrides?.[b],riskLevel:R?.riskLevel??"write",meta:R,db:d,timeoutMs:l?Nn(l.timeout):void 0,tenantId:g,approvalMode:l?.mode});if(ke==="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.`:Q&&le?G=await Fn({permissionsOptions:l,manual:f,hub:p,permissionId:le,permissionToken:Q,plugin:i,endpoint:b,args:w,tenantId:g??"default",expiresAt:U??new Date(Date.now()+(l?Nn(l.timeout):600*1e3)).toISOString(),operationPath:b}):G=`Action '${b}' requires user approval before it can run.`,new Error(G)}P=_e}let _=async(R,ke,q)=>{try{return await h(ke,q)}catch(_e){if(_e instanceof Error){let Q=await cr(_e,i,b,typeof q=="object"&&q!==null?q:{args:q},o);if(R<(Q.maxRetries||0)){let le=R+1;console.log(`Retrying (${le} / ${Q.maxRetries})...`);let U;if(Q.headersRetryAfterMs)U=Q.headersRetryAfterMs;else switch(Q.retryStrategy){case"exponential_backoff":U=Math.pow(2,le-1)*1e3;break;case"exponential_backoff_jitter":let G=Math.pow(2,le-1)*1e3,Mr=(Math.random()-.5)*1e3;U=Math.max(0,G+Mr);break;case"linear_1s":U=1e3;break;case"linear_2s":U=2e3;break;case"linear_3s":U=3e3;break;case"linear_4s":U=4e3;break;default:U=1e3;break}await new Promise(G=>setTimeout(G,U)),await _(le,ke,q),console.log(`[corsair:${i}:${b}] Retry strategy:`,Q)}}throw _e}},S;try{S=a?await a(t,"endpoint"):void 0}catch(R){throw f?.baseUrl&&f?.oauthConfig&&f.kek&&R instanceof te&&R.authType==="oauth_2"?oi(i,f,g):R}if(!C?.before&&!C?.after){let R=await _(0,{...t,key:S},w);return await P?.(),R}let E={...t,key:S},x=C.before?await C.before(E,w):{ctx:E,args:w,continue:!0,passToAfter:void 0};if(x.continue===!1)return;let me=await _(0,x.ctx,x.args);return await C.after?.(x.ctx,me,x.passToAfter),await P?.(),me};r[y]=k}else if(h&&typeof h=="object"){let C={};rt({endpoints:h,hooks:m,ctx:t,tree:C,pluginId:i,errorHandlers:o,currentPath:[...s,y],keyBuilder:a,permissionsConfig:u,endpointMeta:c,database:d,permissionsOptions:l,tenantId:g,manualConfig:f,hubConfig:p}),r[y]=C}}}function ii(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function ot({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:i}){for(let[o,s]of Object.entries(e)){let a=n?.[o];if(ii(s)){let u=a,c=async d=>{let l=(f,p)=>s.handler(f,p),g=i?await i(t,"webhook"):void 0;return!u?.before&&!u?.after?l({...t,key:g},d):(async()=>{let f={...t,key:g},p=u.before?await u.before(f,d):{ctx:f,args:d,continue:!0,passToAfter:void 0};if(p.continue===!1)return;let y=await l(p.ctx,p.args);return y?.success===!0&&await u.after?.(p.ctx,y,p.passToAfter),y})()};r[o]={match:s.match,handler:c}}else if(s&&typeof s=="object"){let u={};ot({webhooks:s,hooks:a,ctx:t,webhooksTree:u,keyBuilder:i}),r[o]=u}}}function si(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 ai(e,n,t,r,i){return e?An(e.db,n,t,r,i):{findByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function it(e,n){let{database:t,tenantId:r,kek:i,rootErrorHandlers:o,permissionsOptions:s,manualConfig:a,hubConfig:u}=n,c={},d={};for(let l of e)c[l.id]={},d[l.id]={};for(let l of e){let g=l.schema,f=r??"default",p=si(t,l.id,f);if(g?.entities){let x={};for(let[me,R]of Object.entries(g.entities)){let ke=t?An(t.db,p,me,g.version,R):ai(void 0,p,me,g.version,R);x[me]=ke}d[l.id].db=x,c[l.id].db=x}let y=l.options,h=l.authConfig,m;if(t&&i&&y?.authType){let x=h?.[y.authType]?.account??[];m=I({authType:y.authType,integrationName:l.id,tenantId:f,kek:i,database:t,extraAccountFields:x}),c[l.id].keys=m}let C={database:t,db:d[l.id]?.db??{},$getAccountId:p,...l.options?{options:l.options}:{},...m?{keys:m,authType:y?.authType}:{},tenantId:f,...u?{hub:u}:{}},b=l.endpoints??{},k=l.hooks,w={...o,...l.errorHandlers},P={},_=l.options?.permissions;rt({endpoints:b,hooks:k,ctx:C,tree:P,pluginId:l.id,errorHandlers:w,currentPath:[],keyBuilder:l.keyBuilder,permissionsConfig:_,endpointMeta:l.endpointMeta,database:t,permissionsOptions:s,tenantId:r,manualConfig:a?{...a,oauthConfig:l.oauthConfig,kek:i,tenantId:f}:void 0,hubConfig:u}),Object.keys(P).length>0&&(c[l.id].api=P),C.endpoints=P;let S=l.webhooks??{},E=l.webhookHooks;if(Object.keys(S).length>0){let x={};ot({webhooks:S,hooks:E,ctx:C,webhooksTree:x,keyBuilder:l.keyBuilder}),c[l.id].webhooks=x,l.pluginWebhookMatcher&&(c[l.id].pluginWebhookMatcher=l.pluginWebhookMatcher),l.pluginTenantWebhookMatcher&&(c[l.id].pluginTenantWebhookMatcher=l.pluginTenantWebhookMatcher)}}return c}function lr(e,n,t){let r={};for(let i of e){let o=i.options,s=i.authConfig;if(o?.authType){let a=s?.[o.authType]?.integration??[],u=O({authType:o.authType,integrationName:i.id,kek:t,database:n,extraIntegrationFields:a});r[i.id]=u}}return r}var ui="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function dr(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] ${ui}`),t):n}var pr=[{method:"GET",pattern:"/ok",handler:async()=>v(200,en())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>v(200,await rn(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>v(201,await sn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>v(200,await on(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>v(200,await nn(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>v(200,await tn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>v(200,await Te(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>v(200,await Ln(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?v(200,await jn(e,t)):v(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>v(200,await an(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>v(200,await un(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>v(200,await cn(e,n,t))}];(()=>{let e=new Set;for(let n of pr){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function ci(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let i={};for(let o=0;o<t.length;o++){let s=t[o],a=r[o];if(s.startsWith(":"))i[s.slice(1)]=decodeURIComponent(a);else if(s!==a)return null}return i}function li(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 di(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 T(400,"invalid_json","Request body is not valid JSON")}}var pi="/api/corsair";function ye(e,n={}){let t=n.basePath??pi,r=A(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async i=>{try{let o=new URL(i.url),s=li(o.pathname,t),a=i.method.toUpperCase(),u=Object.fromEntries(o.searchParams);for(let c of pr){if(c.method!==a)continue;let d=ci(c.pattern,s);if(!d)continue;let l=await di(i);return await c.handler({corsair:e,internal:r,req:i,params:d,query:u,body:l})}throw ae(`No route for ${a} ${s}`)}catch(o){if(n.onError){let a=await n.onError(o,i);if(a)return a}if(o instanceof T)return Zt(o);let s=o instanceof Error?o.message:"Internal server error";return v(500,{error:"internal_error",message:s})}}}function gi(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,i=`${t}://${n}${r}`,o=new Headers;for(let[u,c]of Object.entries(e.headers))if(c!=null)if(Array.isArray(c))for(let d of c)o.append(u,d);else o.set(u,c);let s=e.method!=="GET"&&e.method!=="HEAD",a={method:e.method,headers:o};return s&&e.body!==void 0&&(a.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),o.has("content-type")||o.set("content-type","application/json")),new Request(i,a)}async function fi(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 gr(e,n){let t=ye(e,n);return async(r,i,o)=>{try{let s=await t(gi(r));await fi(i,s)}catch(s){o(s)}}}function fr(e,n){let t=ye(e,n);return r=>t(r.req.raw)}function yr(e,n){let t=ye(e,n);return{GET:t,POST:t}}function hr(e){let n={[Le]:e};return{ok:en,tenants:{list:()=>rn(e),create:t=>sn(e,t),get:t=>on(e,t)},plugins:{list:()=>nn(e),get:t=>tn(e,t)},connectionStatus:{get:t=>Te(e,t?.tenantId)},permissions:{get:t=>Yt(e,t)},connect:{createLink:t=>an(n,e,t),resolve:t=>un(n,e,t),oauthCallback:t=>cn(n,e,t)}}}async function mr(e,n,t,r,i="pending"){if(!e)return null;try{let o=mt(),s=new Date;return await e.db.insertInto("corsair_events").values({id:o,created_at:s,updated_at:s,account_id:n,event_type:t,payload:r,status:i}).execute(),o}catch(o){return console.warn("Failed to log event:",o),null}}async function yi(e,n,t,r="pending"){try{let i=await e.$getAccountId();return mr(e.database,i,n,t,r)}catch(i){return console.warn("Failed to log event:",i),null}}import*as kr from"https";import*as br from"querystring";function bn(e,n,t,r,i){let o=new URL(r.tokenUrl),s=r.tokenAuthMethod==="basic";return new Promise((a,u)=>{let c={code:e.trim(),redirect_uri:i,grant_type:"authorization_code"};s||(c.client_id=n,c.client_secret=t);let d=br.stringify(c),l={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(d).toString()};s&&(l.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=kr.request({hostname:o.hostname,...o.port?{port:Number(o.port)}:{},path:o.pathname+o.search,method:"POST",headers:l},f=>{let p="";f.on("data",y=>{p+=y}),f.on("end",()=>{if(f.statusCode!==200){u(new Error(`Token exchange failed (${f.statusCode}): ${p}`));return}try{a(JSON.parse(p))}catch{u(new Error(`Token endpoint returned non-JSON response: ${p}`))}})});g.on("error",f=>u(new Error(`Request failed: ${f.message}`))),g.write(d),g.end()})}var wr=" ";function j(e){let n=e;return n._def??n.def??{}}function Z(e){let n=e.typeName;if(n)return n;let t=e.type;if(t)return`Zod${t.split("_").map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("")}`}function K(e){return e.innerType??e.schema??e.out??e.in}function Pr(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 K(e)}}function Ar(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function Cn(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function Re(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 Tr(e,n){return e.description??n.description}function hi(e){let n=e;for(;n;){let t=j(n),r=Tr(n,t);if(r)return r;let i=Z(t);if(lt(i)||i==="ZodPipe"||i==="ZodEffects"||i==="ZodTransform"){n=Pr(t,i);continue}break}}function lt(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function D(e){let n=j(e),t=Z(n);switch(t){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"Date";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(n.value??Re(n)[0]??"unknown");case"ZodEnum":return Re(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=K(n);return r?D(r):"unknown"}case"ZodNullable":{let r=K(n);return`${r?D(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=K(n);return r?D(r):"unknown"}case"ZodArray":{let r=Ar(n);if(!r)return"unknown[]";let i=j(r),o=Z(i)==="ZodUnion",s=D(r);return`${o?`(${s})`:s}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=Cn(e,n),i=Object.entries(r);return i.length===0?"{}":`{ ${i.map(([s,a])=>{let u=Z(j(a));return`${u==="ZodOptional"||u==="ZodNullable"?s+"?":s}: ${D(a)}`}).join(", ")} }`}case"ZodUnion":return Re(n).map(r=>D(r)).join(" | ");case"ZodIntersection":return`${D(n.left)} & ${D(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=Pr(n,t);return r?D(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function re(e){let n=j(e),t=Z(n),r=Tr(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??Re(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=Re(n).map(o=>String(o));return{kind:"string",optional:!1,description:r,enum:i}}case"ZodOptional":{let i=K(n),o=i?re(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodNullable":{let i=K(n),o=i?re(i):{kind:"unknown",optional:!1};return{...o,optional:!0,description:r??o.description}}case"ZodDefault":case"ZodCatch":{let i=K(n);return i?{...re(i),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let i=Ar(n);return{kind:"array",optional:!1,description:r,items:i?re(i):{kind:"unknown",optional:!1}}}case"ZodObject":{let i=Cn(e,n),o={};for(let[s,a]of Object.entries(i))o[s]=re(a);return{kind:"object",optional:!1,description:r,fields:o}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let i=Re(n);for(let o of i){let s=j(o);if(Z(s)==="ZodObject")return{...re(o),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let i=K(n);return i?{...re(i),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function lc(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let i=t.slice(0,r),o=t.slice(r+1),s=e.find(d=>d.id===i);if(!s)return null;let a=o;a.startsWith("api.")&&(a=a.slice(4));let u=ce(s.endpointMeta,a),c=ce(s.endpointSchemas,a);return!u&&!c?null:{input:c?.input?re(c.input):null,output:c?.output?re(c.output):null,description:u?.description}}var dt=["equals","contains","startsWith","endsWith","in"],mi=["equals","gt","gte","lt","lte","in"],ki=["equals"],bi=["equals","before","after","between"];function xr(e){let n=j(e);switch(Z(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=K(n);return r?xr(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function pt(e){let n=j(e),t=Z(n);if(lt(t)){let o=K(n);return o?pt(o):{}}if(t!=="ZodObject")return{};let r=Cn(e,n),i={};for(let[o,s]of Object.entries(r)){let a=xr(s);a==="string"?i[o]={type:"string",operators:dt}:a==="number"?i[o]={type:"number",operators:mi}:a==="boolean"?i[o]={type:"boolean",operators:ki}:a==="date"&&(i[o]={type:"date",operators:bi})}return i}function vr(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function at(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"&&at(i,o,t)}}function ut(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function ct(e,n,t){for(let[r,i]of Object.entries(e)){let o=[...n,r];ut(i)?t.push(o.join(".")):i!==null&&typeof i=="object"&&ct(i,o,t)}}function gt(e,n){if(n.length===0)return null;let[t,...r]=n,i=Object.entries(e).find(([a])=>a.toLowerCase()===t);if(!i)return null;let[o,s]=i;if(r.length===0)return ut(s)?[o]:null;if(s!==null&&typeof s=="object"&&!ut(s)){let a=gt(s,r);if(a!==null)return[o,...a]}return null}function Rr(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let o=0;o<n.length;o++){let s=" ".repeat(o+2);t.push(`${s}${n[o]}: {`)}let r=" ".repeat(n.length+2),i=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${i}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let o=n.length-1;o>=0;o--){let s=" ".repeat(o+2);t.push(`${s}},`)}return t.push(" },"),t.push("})"),t.join(`
26
+ `)}var wi=new Set(je);function he(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let o=e.find(a=>a.id===r);if(!o)return wi.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:he(e);if(t==="webhooks"){if(!o.webhooks)return[];let a=[];return ct(o.webhooks,[],a),a.map(u=>`${o.id}.webhooks.${u}`)}if(t==="db"){let a=o.schema?.entities;return a?Object.keys(a).map(u=>`${o.id}.db.${u}.search`):[]}if(!o.endpoints)return[];let s=[];return at(o.endpoints,[],s),s.map(a=>`${o.id}.api.${a}`)}let i={};if(t==="webhooks")for(let o of e){if(!o.webhooks)continue;let s=[];ct(o.webhooks,[],s),i[o.id]=s.map(a=>`${o.id}.webhooks.${a}`)}else if(t==="db")for(let o of e){let s=o.schema?.entities;s&&(i[o.id]=Object.keys(s).map(a=>`${o.id}.db.${a}.search`))}else for(let o of e){if(!o.endpoints)continue;let s=[];at(o.endpoints,[],s),i[o.id]=s.map(a=>`${o.id}.api.${a}`)}return i}function ce(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function Ci(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let o=t.slice(n.length+1),s=o.startsWith(".")?o.slice(1):o;return s.startsWith("api.")&&(s=s.slice(4)),{shortPath:s,lookupKey:s}}let i=e.slice(n.length+1);return i.toLowerCase().startsWith("api.")&&(i=i.slice(4)),{shortPath:i,lookupKey:i.toLowerCase()}}function st(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 dc(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let i=t.slice(0,r),o=t.slice(r+1),s=e.find(a=>a.id===i);if(s){if(o.startsWith("db.")){let d=o.slice(3),l=d.lastIndexOf(".");if(l!==-1){let g=d.slice(0,l),f=d.slice(l+1),p=s.schema?.entities;if(f==="search"&&p){let y=vr(p,g);if(y){let[h,m]=y,C=pt(m),b=[`Search ${i} ${h} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${dt.join(", ")}]`];for(let[k,w]of Object.entries(C))b.push(` ${k}?: ${w.type} [${w.operators.join(", ")}]`);return b.push("}"),b.join(`
30
+ `)}}}return st(he(e,{type:"db"}),"Path not found. Available db operations")}if(o.startsWith("webhooks.")){let d=o.slice(9);if(s.webhooks){let l=gt(s.webhooks,d.split("."));if(l!==null){let g=l.join("."),f=ce(s.webhookSchemas,g.toLowerCase()),p=f?.response?D(f.response):null,y=[];return f?.description&&y.push(f.description),f?.payload&&y.push(`payload ${wn(Ie(f.payload))}`),p&&y.push(`response: ${p}`),y.push(`usage:
31
+ ${Rr(i,l)}`),y.join(`
32
+
33
+ `)}}return st(he(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=o;a.startsWith("api.")&&(a=a.slice(4));let u=ce(s.endpointMeta,a),c=ce(s.endpointSchemas,a);if(u||c){let d=[],l=[u?.riskLevel?`[${u.riskLevel}]`:"",u?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),g=[u?.description,l].filter(Boolean).join(" ");return g&&d.push(g),c?.input&&d.push(`input ${wn(Ie(c.input))}`),c?.output&&d.push(`output ${wn(Ie(c.output))}`),d.join(`
34
+
35
+ `)}}}return st(he(e),"Path not found. Available operations")}function Cr(e){let n=e;for(;;){let t=j(n),r=Z(t);if(lt(r)){let i=K(t);if(!i)return n;n=i;continue}return n}}function Ie(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=Cr(e),t=j(n);if(Z(t)==="ZodObject"){let i=Cn(n,t),o=[];for(let[s,a]of Object.entries(i)){let u=j(a),c=Z(u),d=c==="ZodOptional"||c==="ZodNullable",l=Cr(a),g=hi(a);o.push({key:s,optional:d,type:D(l),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:o}}return{kind:"inline",type:D(n)}}function wn(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=wr.repeat(n+1),r=wr.repeat(n);return`{
36
+ ${e.fields.map(o=>{let s=o.optional?`${o.key}?`:o.key,a=o.description?` // ${o.description}`:"";return`${t}${s}: ${o.type}${a}`}).join(`
37
+ `)}
38
+ ${r}}`}return"unknown"}function Pi(e,n){let t=he(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(d=>d.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let i=[];for(let d of t){let{shortPath:l,lookupKey:g}=Ci(d,n),f=ce(r.endpointMeta,g),p=ce(r.endpointSchemas,g);!f&&!p||i.push({path:d,shortPath:l,description:f?.description,riskLevel:f?.riskLevel,irreversible:f?.irreversible,input:Ie(p?.input),output:Ie(p?.output)})}i.sort((d,l)=>d.path.localeCompare(l.path));let o=[],s=he(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let d of s){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("webhooks."))continue;let p=f.slice(9),y=gt(r.webhooks,p.split("."));if(y===null)continue;let h=y.join("."),m=ce(r.webhookSchemas,h.toLowerCase()),C=m?.response?D(m.response):void 0;o.push({path:d,description:m?.description,payload:Ie(m?.payload),responseType:C,usageExample:Rr(n,y)})}o.sort((d,l)=>d.path.localeCompare(l.path));let a=[],u=he(e,{plugin:n,type:"db"}),c=r.schema?.entities;if(Array.isArray(u)&&c)for(let d of u){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("db."))continue;let p=f.slice(3),y=p.lastIndexOf(".");if(y===-1)continue;let h=p.slice(0,y);if(p.slice(y+1)!=="search")continue;let C=vr(c,h);if(!C)continue;let[b,k]=C,w=pt(k),P=Object.entries(w).map(([_,S])=>({field:_,type:S.type,operators:S.operators}));a.push({path:d,entityName:b,filters:[{field:"entity_id",type:"string",operators:dt},...P]})}return a.sort((d,l)=>d.path.localeCompare(l.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:a}}}function Ir(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function Ai(e,n){let t=Ir(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 Ti(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function _r(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function Sr(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 We(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function xi(e){return We(e.body)}function Er(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Pn(Array.isArray(r)?r:[r])}function Or(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let u of t){let c=Pn(Array.isArray(u)?u:[u]);if(c)return decodeURIComponent(c)}let r=Er({query:e.query},"validationToken");if(r)return r;let i=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let u of i){let c=n[u],d=Array.isArray(c)?c[0]:c;if(!(!d||typeof d!="string"))try{let g=(d.startsWith("http")?new URL(d):new URL(`https://example.invalid${d.startsWith("/")?d:`/${d}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let o=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,s=We(typeof o=="string"?(()=>{try{return JSON.parse(o)}catch{return o}})():o);return Pn([s?.validationToken])??null}function vi(e){if(Or(e))return!0;let n=We(e.body??e.payload);return _r(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Pn(e){for(let n of e){let t=Sr(n);if(t)return t}}function Ri(e){let t=We(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var Le=Symbol.for("corsair:internal");function _t(e){let n=e.database?ft(e.database):void 0,t=n&&e.kek?lr(e.plugins,n,e.kek):kn(!!n,!!e.kek),r=dr(e),i={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?Ze(e.hub):void 0},o=Kt(n),s=hr(i);if(e.multiTenancy)return Object.assign({withTenant:u=>{if(!u)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let c=it(e.plugins,{database:n,tenantId:u,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(c,{[Le]:i})},keys:t,permissions:o,manage:s},{[Le]:i});let a=it(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign({},a,{keys:t,permissions:o,manage:s,[Le]:i})}var H=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function Dr(e){let n=e.oauthConfig;if(!n)throw new H("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Ii(e,n,t,r){let i=bt(e),o=await i.integrations.findByName(n);if(!o)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:t,integration_id:o.id}))return;let a=X(),u=await ee(a,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:u})}async function In(e,n,t){let{tenantId:r,redirectUri:i}=t,o=A(e,()=>new H("invalid_corsair_instance","Invalid corsair instance"));if(!o.database)throw new Error("No database configured on corsair instance");let s=$(o,n,l=>new H("plugin_not_found",l)),a=Dr(s),c=await O({authType:"oauth_2",integrationName:n,kek:o.kek,database:o.database}).get_client_id();if(!c)throw new Error(`client_id not configured for '${n}'`);let d=ie(J(n,r),o.kek);return{url:Ae({oauthConfig:a,clientId:c,redirectUri:i,state:d}),state:d}}async function Ne(e,n){let{code:t,state:r,redirectUri:i}=n,o=A(e,()=>new H("invalid_corsair_instance","Invalid corsair instance")),s=Ge(r,o.kek);if(!s)throw new H("invalid_state","Invalid or tampered state parameter");let{plugin:a,tenantId:u}=s;if(!o.database)throw new H("no_database","No database configured on corsair instance");let c=$(o,a,h=>new H("plugin_not_found",h)),d=Dr(c),l=O({authType:"oauth_2",integrationName:a,kek:o.kek,database:o.database}),g=await l.get_client_id(),f=await l.get_client_secret();if(!g||!f)throw new H("credentials_not_configured",`Credentials not configured for '${a}'`);await Ii(o.database,a,u,o.kek);let p=await bn(t,g,f,d,i);if(!p.access_token)throw new H("no_access_token",`No access_token returned from ${d.providerName}`);let y=I({authType:"oauth_2",integrationName:a,tenantId:u,kek:o.kek,database:o.database});await y.set_access_token(p.access_token),p.refresh_token&&await y.set_refresh_token(p.refresh_token),p.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+p.expires_in));try{let h=await gn(o.plugins,a,p);if(h)try{let m=c.authConfig?.oauth_2?.account??[];await xe({database:o.database,kek:o.kek,pluginId:a,tenantId:u,link:h,authType:"oauth_2",extraAccountFields:m})}catch(m){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${a}' tenant '${u}':`,m)}}catch(h){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${a}' tenant '${u}':`,h)}return{plugin:a,tenantId:u}}export{wt as a,de as b,Se as c,pe as d,Ze as e,M as f,qe as g,J as h,Tn as i,X as j,ee as k,L as l,_n as m,Me as n,se as o,ne as p,He as q,O as r,I as s,Ft as t,Nt as u,xe as v,Zn as w,fn as x,Xt as y,Ae as z,H as A,In as B,Ne as C,Oe as D,we as E,xt as F,Ce as G,Rt as H,io as I,Je as J,En as K,ue as L,ve as M,nr as N,ge as O,fe as P,$e as Q,Fe as R,yn as S,hn as T,Jn as U,Vn as V,Yn as W,Qn as X,Xn as Y,et as Z,nt as _,Be as $,te as aa,tt as ba,ar as ca,ur as da,ye as ea,gr as fa,fr as ga,yr as ha,mr as ia,yi as ja,bn as ka,lc as la,he as ma,dc as na,wn as oa,Pi as pa,Ir as qa,Ai as ra,Ti as sa,_r as ta,Sr as ua,We as va,xi as wa,Er as xa,Or as ya,vi as za,Pn as Aa,Ri as Ba,Le as Ca,_t as Da};
package/dist/core.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-B06cXWWA.js';
1
+ export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-Dvu7dZkV.js';
2
2
  import { CorsairDatabase } from './db.js';
3
3
  import { A as AuthTypes, a as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './types-CqV508wD.js';
4
4
  export { b as AccountFieldNames, f as AllProviders, e as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, c as BaseKeyManager, g as BaseProviders, k as Bivariant, d as IntegrationFieldNames, O as OAuth2IntegrationCredentials, h as PickAuth, P as PluginAuthConfig, j as ProviderDisplayNames, U as UnionToIntersection, i as formatProviderDisplayName } from './types-CqV508wD.js';
5
- export { t as BeforeHookResult, B as BindEndpoints, L as BindWebhooks, f as BoundEndpointFn, g as BoundEndpointTree, M as BoundWebhook, N as BoundWebhookTree, d as CorsairClient, h as CorsairContext, i as CorsairEndpoint, k as CorsairErrorHandler, a as CorsairIntegration, u as CorsairKeyBuilder, v as CorsairKeyBuilderBase, Q as CorsairOAuthWebhookTenantLinkResolver, q as CorsairPermissionsNamespace, C as CorsairPlugin, w as CorsairPluginContext, c as CorsairSingleTenantClient, b as CorsairTenantWrapper, S as CorsairWebhook, U as CorsairWebhookHandler, V as CorsairWebhookMatcher, X as CorsairWebhookTenantMatcher, x as EndpointHooks, y as EndpointMetaEntry, E as EndpointPathsOf, z as EndpointRiskLevel, j as EndpointTree, r as EnforcePermissionOptions, s as EnforcePermissionResult, l as ErrorContext, m as ErrorHandler, n as ErrorHandlerAndMatchFunction, o as ErrorMatcher, K as KeyBuilderContext, O as OAuthConfig, P as PermissionMode, A as PermissionPolicy, D as PluginEndpointMeta, F as PluginPermissionsConfig, Y as RawWebhookRequest, G as RequiredPluginEndpointMeta, H as RequiredPluginEndpointSchemas, I as RequiredPluginWebhookSchemas, R as RetryStrategies, p as RetryStrategy, T as TokenResponse, J as WebhookHooks, Z as WebhookPathsOf, _ as WebhookRequest, $ as WebhookResponse, W as WebhookTenantMatch, a0 as WebhookTree, e as exchangeCodeForTokens } from './index-DXZWwzui.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-CAvC74W2.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-V9UlHMzS.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-Bh3FG0-Y.js';
7
7
  import 'kysely';
8
8
  import 'zod';
9
9
  import 'pg';
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{Aa as F,Ba as G,Ca as H,Da as I,Ea as J,a,aa as p,b,ea as q,j as d,ja as r,k as e,ka as s,l as f,la as t,m as g,n as h,o as i,p as j,pa as u,q as k,qa as v,r as l,ra as w,s as m,sa as x,t as n,ta as y,u as o,ua as z,va as A,wa as B,xa as C,ya as D,za as E}from"./chunk-GJ743ML7.js";import{g as c}from"./chunk-6D4UDUPJ.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{Aa as G,Ba as H,Ca as I,Da as J,K as p,a,aa as q,b,ia as r,j as d,ja as s,k as e,ka as t,l as f,m as g,n as h,o as i,oa as u,p as j,pa as v,q as k,qa as w,r as l,ra as x,s as m,sa as y,t as n,ta as z,u as o,ua as A,va as B,wa as C,xa as D,ya as E,za as F}from"./chunk-Y22MYO3D.js";import{g as c}from"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,p as resolveConnectLink,A as toExternalId};
package/dist/hub.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { l as HubOAuthMode, m as HubConnectSource, H as HubConfig, n as HubConfigInput, o as HubConnectSessionInput, p as HubConnectSessionResult, a as AccountKeyManagerFor } from './types-CqV508wD.js';
2
2
  export { D as DEFAULT_HUB_API_URL, q as HubPermissionSessionInput, r as HubPermissionSessionResult, i as formatProviderDisplayName } from './types-CqV508wD.js';
3
- import { c as ProcessCorsairRequest } from './index-D9gndzCb.js';
4
- export { d as TunnelEnvelope, e as TunnelType } from './index-D9gndzCb.js';
3
+ import { c as ProcessCorsairRequest } from './index-t-u4QNP-.js';
4
+ export { d as TunnelEnvelope, e as TunnelType } from './index-t-u4QNP-.js';
5
5
 
6
6
  type ConnectAuthKind = 'oauth' | 'api_key' | 'bot_token';
7
7
  type ConnectPluginManifestEntry = {
@@ -13,6 +13,7 @@ type ConnectPluginManifestEntry = {
13
13
  oauthMode?: HubOAuthMode;
14
14
  oauthUrl?: string;
15
15
  state?: string;
16
+ setupError?: string;
16
17
  };
17
18
  type CreateConnectSessionRequestBody = {
18
19
  tenantId: string;
@@ -59,40 +60,6 @@ declare function resolveHubOAuthCallbackUrl(config: HubConfig): string;
59
60
 
60
61
  declare function createHubConnectSession(corsair: unknown, input: HubConnectSessionInput): Promise<HubConnectSessionResult>;
61
62
 
62
- type HubConnectSessionRequestBody = {
63
- plugin?: string;
64
- tenantId?: string;
65
- source?: string;
66
- oauthMode?: string;
67
- providerName?: string;
68
- };
69
- type HubConnectSessionParseError = {
70
- error: string;
71
- status: number;
72
- };
73
- type HubConnectSessionSuccessBody = {
74
- ok: true;
75
- connectUrl: string;
76
- token: string;
77
- projectId: string;
78
- expiresAt?: string;
79
- };
80
- type ResolveHubConnectTenantId = (request: Request) => Promise<string | null | undefined> | string | null | undefined;
81
- type HubConnectSessionResponseOptions = {
82
- /**
83
- * When provided, tenantId from the request body or query is ignored.
84
- * Return null or undefined to respond with 401 Unauthorized.
85
- */
86
- resolveTenantId?: ResolveHubConnectTenantId;
87
- /** Used when resolveTenantId is not provided. Defaults to "default". */
88
- defaultTenantId?: string;
89
- };
90
- declare function parseHubConnectSessionBody(body: HubConnectSessionRequestBody): HubConnectSessionInput | HubConnectSessionParseError;
91
- declare function parseHubConnectSessionSearchParams(url: string): HubConnectSessionRequestBody;
92
- declare function handleHubConnectSessionRequest(corsair: unknown, request: Request, options?: HubConnectSessionResponseOptions): Promise<HubConnectSessionSuccessBody | HubConnectSessionParseError>;
93
- declare function respondToHubConnectSession(corsair: unknown, request: Request, options?: HubConnectSessionResponseOptions): Promise<Response>;
94
- declare function respondToHubConnectSessionFromRequest(corsair: unknown, request: Request, options?: HubConnectSessionResponseOptions): Promise<Response>;
95
-
96
63
  type HubDeliveryResult = {
97
64
  type: 'redirect';
98
65
  url: string;
@@ -155,10 +122,9 @@ type ProcessManagedOAuthDeliveryResult = {
155
122
  };
156
123
  declare function processManagedOAuthDelivery(corsair: unknown, options: ProcessManagedOAuthDeliveryOptions): Promise<ProcessManagedOAuthDeliveryResult>;
157
124
 
158
- type HubRouteHandlersOptions = HubConnectSessionResponseOptions;
159
- declare function createHubRouteHandlers(corsair: unknown, options?: HubRouteHandlersOptions): {
125
+ declare function createHubRouteHandlers(corsair: unknown): {
160
126
  delivery: (request: Request) => Promise<Response>;
161
- createConnectSession: (request: Request) => Promise<Response>;
127
+ deliveryOptions: (request: Request) => Promise<Response>;
162
128
  };
163
129
 
164
- export { type ConnectAuthKind, type ConnectPluginManifestEntry, type ConnectSourceValidationError, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, HubConfig, HubConfigInput, HubConnectSessionInput, type HubConnectSessionParseError, type HubConnectSessionRequestBody, type HubConnectSessionResponseOptions, HubConnectSessionResult, type HubConnectSessionSuccessBody, HubConnectSource, type HubDeliveryRequest, type HubDeliveryResult, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, type HubRouteHandlersOptions, type ManagedAccessTokenResult, type ManagedAuthContext, ManagedOAuthDeliveryError, type ProcessManagedOAuthDeliveryOptions, type ProcessManagedOAuthDeliveryResult, type ResolveHubConnectTenantId, attachManagedRefreshAuth, createHubConnectSession, createHubRouteHandlers, getHubConfig, getManagedAccessToken, handleHubConnectSessionRequest, handleHubDeliveryGet, handleHubDeliveryPost, handleHubDeliveryRequest, hubDeliveryToResponse, isLoopbackDeliveryUrl, normalizeHubConfig, parseHubConnectSessionBody, parseHubConnectSessionSearchParams, processManagedOAuthDelivery, resolveConnectSourceFromDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubConnectSession, respondToHubConnectSessionFromRequest, respondToHubDelivery, respondToHubDeliveryFromRequest, shouldUseBrowserConnectDelivery, validateExplicitConnectSource };
130
+ export { type ConnectAuthKind, type ConnectPluginManifestEntry, type ConnectSourceValidationError, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, HubConfig, HubConfigInput, HubConnectSessionInput, HubConnectSessionResult, HubConnectSource, type HubDeliveryRequest, type HubDeliveryResult, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, type ManagedAccessTokenResult, type ManagedAuthContext, ManagedOAuthDeliveryError, type ProcessManagedOAuthDeliveryOptions, type ProcessManagedOAuthDeliveryResult, attachManagedRefreshAuth, createHubConnectSession, createHubRouteHandlers, getHubConfig, getManagedAccessToken, handleHubDeliveryGet, handleHubDeliveryPost, handleHubDeliveryRequest, hubDeliveryToResponse, isLoopbackDeliveryUrl, normalizeHubConfig, processManagedOAuthDelivery, resolveConnectSourceFromDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, shouldUseBrowserConnectDelivery, validateExplicitConnectSource };
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as x,C as g,D as h,E as i,F as j,I as k,J as l,K as m,L as n,M as o,N as p,O as q,P as r,W as s,X as t,Y as u,Z as v,_ as w,b as a,ba as y,c as b,ca as z,d as c,da as A,e as d,f as e,g as f}from"./chunk-GJ743ML7.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,q as ManagedOAuthDeliveryError,z as attachManagedRefreshAuth,k as createHubConnectSession,A as createHubRouteHandlers,a as formatProviderDisplayName,e as getHubConfig,y as getManagedAccessToken,n as handleHubConnectSessionRequest,s as handleHubDeliveryGet,t as handleHubDeliveryPost,v as handleHubDeliveryRequest,u as hubDeliveryToResponse,g as isLoopbackDeliveryUrl,d as normalizeHubConfig,l as parseHubConnectSessionBody,m as parseHubConnectSessionSearchParams,r as processManagedOAuthDelivery,h as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,o as respondToHubConnectSession,p as respondToHubConnectSessionFromRequest,w as respondToHubDelivery,x as respondToHubDeliveryFromRequest,i as shouldUseBrowserConnectDelivery,j as validateExplicitConnectSource};
1
+ import{$ as s,D as g,E as h,F as i,G as j,J as k,L as l,M as m,W as n,X as o,Y as p,Z as q,_ as r,b as a,ba as t,c as b,ca as u,d as c,da as v,e as d,f as e,g as f}from"./chunk-Y22MYO3D.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,l as ManagedOAuthDeliveryError,u as attachManagedRefreshAuth,k as createHubConnectSession,v as createHubRouteHandlers,a as formatProviderDisplayName,e as getHubConfig,t as getManagedAccessToken,n as handleHubDeliveryGet,o as handleHubDeliveryPost,q as handleHubDeliveryRequest,p as hubDeliveryToResponse,g as isLoopbackDeliveryUrl,d as normalizeHubConfig,m as processManagedOAuthDelivery,h as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,r as respondToHubDelivery,s as respondToHubDeliveryFromRequest,i as shouldUseBrowserConnectDelivery,j as validateExplicitConnectSource};
@@ -1,6 +1,6 @@
1
1
  import { CorsairDatabase } from './db.js';
2
2
  import { H as HubConfig } from './types-CqV508wD.js';
3
- import { C as CorsairPlugin, a as CorsairIntegration, b as CorsairTenantWrapper, c as CorsairSingleTenantClient } from './index-DXZWwzui.js';
3
+ import { C as CorsairPlugin, a as CorsairPermissionsOptions, b as CorsairManualConfig, c as CorsairIntegration, d as CorsairTenantWrapper, e as CorsairSingleTenantClient } from './index-V9UlHMzS.js';
4
4
 
5
5
  declare const CORSAIR_INTERNAL: unique symbol;
6
6
  type CorsairInternalConfig = {
@@ -8,28 +8,8 @@ type CorsairInternalConfig = {
8
8
  database: CorsairDatabase | undefined;
9
9
  kek: string;
10
10
  multiTenancy: boolean;
11
- approval?: {
12
- timeout: string;
13
- onTimeout: 'deny' | 'approve';
14
- mode?: 'synchronous' | 'asynchronous' | (() => 'synchronous' | 'asynchronous');
15
- /** Called when a permission is blocked in async mode. Return the message surfaced to the LLM. */
16
- formatAsyncMessage?: (opts: {
17
- token: string;
18
- id: string;
19
- plugin: string;
20
- endpoint: string;
21
- args: unknown;
22
- }) => string;
23
- };
24
- connect?: {
25
- baseUrl: string;
26
- redirectUri: string;
27
- onAuthMissing?: (opts: {
28
- plugin: string;
29
- connectUrl: string;
30
- state: string;
31
- }) => string;
32
- };
11
+ permissions?: CorsairPermissionsOptions;
12
+ manual?: CorsairManualConfig;
33
13
  hub?: HubConfig;
34
14
  };
35
15
  /**