corsair 0.1.101 → 0.1.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ import{a as Tr,b as le,c as Pr,d as w,e as H,f as Ar,g as U,h as O,i as I,j as cn,k as xr,l as Ir,m as ot,n as Sr,o as Rr}from"./chunk-BPFUYXOD.js";import{a as vr}from"./chunk-IGGCNGU2.js";var ln=["agentql","ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gitlab","gmail","googlecalendar","googledrive","googlemeet","googlesheets","grafana","hackernews","hubspot","instagram","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","supabase","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],Er={agentql:"AgentQL",ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",cursor:"Cursor",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledrive:"Google Drive",googlemeet:"Google Meet",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",instagram:"Instagram",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",supabase:"Supabase",tally:"Tally",tavily:"Tavily",teams:"Teams",telegram:"Telegram",todoist:"Todoist",trello:"Trello",twilio:"Twilio",twitter:"Twitter",twitterapiio:"Twitter API IO",typeform:"Typeform",vapi:"Vapi",xquik:"XQuik",youtube:"YouTube",zendesk:"Zendesk",zohomail:"Zoho Mail",zoom:"Zoom"};function de(e){let n=Er[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var Ke="https://auth.corsair.dev";var pe=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret } to createCorsair()."),this.name="HubNotConfiguredError"}};function dn(e){let n=(e.apiUrl?.trim()||Ke).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim();if(!t||!r)throw new Error("Hub config requires non-empty projectApiKey and signingSecret");return{apiUrl:n,projectApiKey:t,signingSecret:r,oauthCallbackUrl:e.oauthCallbackUrl?.trim().replace(/\/$/,"")}}function gi(e){return e.apiUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function B(e){let n=w(e).hub;if(!n||!gi(n))throw new pe;return n}function _r(e){return e.replace(/\/$/,"")}function pn(e){return e.oauthCallbackUrl?_r(e.oauthCallbackUrl.trim()):`${_r(e.apiUrl)}/oauth/callback`}function Ee(e){if(e.startsWith("ck_dev_"))return"development";if(e.startsWith("ck_prod_"))return"production";throw new Error("Hub API key must start with ck_dev_ (development) or ck_prod_ (production)")}function P(e){return typeof e=="string"&&e.length>0}function fi(e){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"}function yi(e){return e==="oauth_2"||e==="api_key"||e==="bot_token"||e==="managed"}function gn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!P(n.connectUrl)||!P(n.token)||!P(n.projectId))throw new Error("Hub API returned an incomplete connect session (expected connectUrl, token, and projectId)");let t={connectUrl:n.connectUrl,token:n.token,projectId:n.projectId,environmentId:P(n.environmentId)?n.environmentId:n.projectId};return P(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function fn(e){if(!Array.isArray(e))throw new Error("Hub API returned an invalid connections response (expected array)");let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;if(!P(r.tenantId)||!P(r.plugin)||!fi(r.status)||!yi(r.authType)||typeof r.connected!="boolean"||typeof r.verified!="boolean")continue;let o=Array.isArray(r.missingFields)?r.missingFields.filter(i=>typeof i=="string"):[];n.push({tenantId:r.tenantId,plugin:r.plugin,status:r.status,authType:r.authType,connected:r.connected,verified:r.verified,missingFields:o,reportedAt:P(r.reportedAt)?r.reportedAt:new Date().toISOString()})}return n}function yn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!P(n.approvalUrl)||!P(n.token)||!P(n.projectId)||!P(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 mn(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(P(n.access_token))return{access_token:n.access_token,refresh_token:P(n.refresh_token)?n.refresh_token:void 0,expires_in:(()=>{if(typeof n.expires_in=="number")return n.expires_in;if(typeof n.expires_in=="string"&&n.expires_in.trim().length>0){let t=Number(n.expires_in);return Number.isFinite(t)?t:void 0}})(),scope:P(n.scope)?n.scope:void 0};throw new Error(P(n.error)?P(n.error_description)?n.error_description:n.error:"Hub token refresh returned no access_token")}function mi(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function hi(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;P(r.name)&&n.push({name:r.name,level:r.level==="integration"||r.level==="account"?r.level:"account",required:r.required===!0,configured:r.configured===!0})}return n}function ki(e,n,t,r){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"?e:n?"ready":t.some(i=>i.level==="integration"&&i.required&&!i.configured)?"missing_integration":t.some(i=>i.level==="account"&&i.required&&i.configured)?"partial":(r.length>0,"not_started")}function Dr(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!P(n.tenantId)||!Array.isArray(n.plugins))throw new Error("Connect status response was incomplete (expected tenantId and plugins)");let t=[];for(let r of n.plugins){if(!r||typeof r!="object")continue;let o=r;if(!P(o.plugin)||typeof o.connected!="boolean")continue;let i=o.authKind==="oauth"||o.authKind==="api_key"||o.authKind==="bot_token"?o.authKind:"api_key",a=hi(o.fields),s=mi(o.missingRequiredFields),u=ki(o.status,o.connected,a,s);t.push({plugin:o.plugin,providerName:P(o.providerName)?o.providerName:o.plugin,authKind:i,status:u,connected:o.connected,fields:a,missingRequiredFields:s})}return{tenantId:n.tenantId,plugins:t}}function hn(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}var bi="3000",Ci="/api/corsair";function wi(e){return e.replace(/\/$/,"")}function ge(e){let n=e?.deliveryUrl?.trim()||process.env.CORSAIR_DELIVERY_URL?.trim();if(n){let r=/^https?:\/\//i.test(n)?n:`https://${n}`;return wi(r)}return`http://localhost:${process.env.PORT?.trim()||bi}${Ci}`}function Or(e){return e.replace(/\/$/,"")}function it(e){if(!e.projectApiKey.startsWith("ck_dev_"))return null;try{return ge()}catch{return null}}function Mr(e){let n=it(e);return n?{"x-corsair-delivery-url":n}:{}}async function Hr(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=hn(e);return r||`Hub API returned HTTP ${n}`}async function z(e){let n=Or(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.hub.projectApiKey}`,...Mr(e.hub)},body:JSON.stringify(e.body)}),r=await Hr(t);if(!t.ok)throw new Error(Fr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function Ur(e){let n=Or(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`,...Mr(e.hub)}}),r=await Hr(t);if(!t.ok)throw new Error(Fr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as Br,createDecipheriv as Nr,randomBytes as kn,scrypt as vi}from"crypto";import{promisify as Ti}from"util";var $r=Ti(vi),bn="aes-256-gcm",Lr=12,Cn=16,Pi=16,qe=32;function re(){return kn(qe).toString("base64")}async function oe(e,n){let t=kn(Pi),r=await $r(n,t,qe),o=kn(Lr),i=Br(bn,r,o,{authTagLength:Cn}),a=Buffer.concat([i.update(e,"utf8"),i.final()]),s=i.getAuthTag();return[t.toString("base64"),o.toString("base64"),s.toString("base64"),a.toString("base64")].join(":")}async function j(e,n){let[t,r,o,i]=e.split(":");if(!t||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let a=Buffer.from(t,"base64"),s=Buffer.from(r,"base64"),u=Buffer.from(o,"base64"),l=Buffer.from(i,"base64"),c=await $r(n,a,qe),p=Nr(bn,c,s,{authTagLength:Cn});return p.setAuthTag(u),Buffer.concat([p.update(l),p.final()]).toString("utf8")}function st(e,n){let t=Buffer.from(n,"base64"),r=kn(Lr),o=Br(bn,t,r,{authTagLength:Cn}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),a=o.getAuthTag();return[r.toString("base64"),a.toString("base64"),i.toString("base64")].join(":")}function Ze(e,n){let[t,r,o]=e.split(":");if(!t||!r||!o)throw new Error("Invalid encrypted data format");let i=Buffer.from(n,"base64"),a=Buffer.from(t,"base64"),s=Buffer.from(r,"base64"),u=Buffer.from(o,"base64"),l=Nr(bn,i,a,{authTagLength:Cn});return l.setAuthTag(s),Buffer.concat([l.update(u),l.final()]).toString("utf8")}function fe(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=st(o,n);return t}function ie(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Ze(o,n);return t}function Ge(e,n,t){let r=ie(e,n);return fe(r,t)}function jr(e,n,t){let r={};for(let o of t)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let a=[null,void 0,""].includes(i)?null:i;await n({[o]:a})};return r}var at=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function S(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,a=[...O[n].integration,...i],s=null,u={kek:r,integrationName:t,getIntegration:async()=>{if(s)return s;let f=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!f)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return s={id:f.id,config:at(f.config),dek:f.dek??null},s},updateIntegration:async f=>{let y=await u.getIntegration();await o.db.updateTable("corsair_integrations").set({...f.config!==void 0?{config:f.config}:{},...f.dek!==void 0?{dek:f.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),s=null}},l=null,c=async()=>{if(l)return l;let f=await u.getIntegration();if(!f.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return l=await j(f.dek,r),l},p=async()=>{let f=await u.getIntegration(),y=await c(),m=f.config;return!m||Object.keys(m).length===0?{}:ie(m,y)};return{get_dek:c,issue_new_dek:async()=>{let f=await u.getIntegration(),y=re(),m={};if(f.dek){let v=await j(f.dek,r),C=f.config;C&&Object.keys(C).length>0&&(m=Ge(C,v,y))}let h=await oe(y,r);return await u.updateIntegration({config:m,dek:h}),l=y,y},...jr(p,async f=>{let y=await c(),m;try{m=await p()}catch(C){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,C),m={}}let h={...m};for(let[C,E]of Object.entries(f))E===null?delete h[C]:h[C]=E;let v=fe(h,y);await u.updateIntegration({config:v})},a)}}function _(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:a=[],ensureProvisioned:s}=e,u=[...O[n].account,...a],l=null,c=null,p=async()=>{if(c)return c;let k=!1;for(;;){let b=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!b){if(!k&&s){k=!0,await s();continue}throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`)}return c={id:b.id,config:at(b.config),dek:b.dek??null},c}},g={kek:o,integrationName:t,tenantId:r,getIntegration:p,getAccount:async()=>{if(l)return l;let k=!1;for(;;){let b=await p(),T=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",b.id).executeTakeFirst();if(!T){if(!k&&s){k=!0,await s();continue}throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`)}return l={id:T.id,config:at(T.config),dek:T.dek??null},l}},updateAccount:async k=>{let b=await g.getAccount();await i.db.updateTable("corsair_accounts").set({...k.config!==void 0?{config:k.config}:{},...k.dek!==void 0?{dek:k.dek}:{},updated_at:new Date}).where("id","=",b.id).execute(),l=null}},d=null,f=null,y=async()=>{if(d)return d;let k=await g.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return d=await j(k.dek,o),d},m=async()=>{if(f)return f;let k=await g.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return f=await j(k.dek,o),f},h=async()=>{let k=await g.getAccount(),b=await y(),T=k.config;return!T||Object.keys(T).length===0?{}:ie(T,b)},v=async()=>{let k=await g.getIntegration(),b=await m(),T=k.config;return!T||Object.keys(T).length===0?{}:ie(T,b)},E={get_dek:y,issue_new_dek:async()=>{let k=await g.getAccount(),b=re(),T={};if(k.dek){let ee=await j(k.dek,o),D=k.config;D&&Object.keys(D).length>0&&(T=Ge(D,ee,b))}let x=await oe(b,o);return await g.updateAccount({config:T,dek:x}),d=b,b},...jr(h,async k=>{let b=await y(),T;try{T=await h()}catch(D){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,D),T={}}let x={...T};for(let[D,ce]of Object.entries(k))ce===null?delete x[D]:x[D]=ce;let ee=fe(x,b);await g.updateAccount({config:ee})},u)};return n==="oauth_2"&&(E.get_integration_credentials=async()=>{let k=await v();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),E}async function Wr(e,n,t){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!r)throw new Error(`Integration "${n}" not found.`);let o=re(),i=await oe(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function Kr(e,n,t,r){let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!o)throw new Error(`Integration "${n}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",o.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let a=re(),s=await oe(a,r);return await e.db.updateTable("corsair_accounts").set({dek:s,updated_at:new Date}).where("id","=",i.id).execute(),a}var Ai=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function _e(e){return Ai.has(e)}function xi(e,n){return _e(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function Ii(e){return!_e(e)}function Si(e){switch(e){case"oauth_2":case"managed":return["access_token","refresh_token"];case"api_key":return["api_key"];case"bot_token":return["bot_token"]}}function Ri(e,n){return Si(e).every(r=>n.find(i=>i.level==="account"&&i.name===r)?.configured??!1)}async function qr(e,n){if(!e)return!1;let t=U(e,`get_${n}`);if(!t)return!1;try{let r=await t();return typeof r=="string"&&r.length>0}catch{return!1}}function Ei(e,n){let r=e.authConfig?.[n]?.integration??[];return[...O[n].integration,...r]}function _i(e,n){let r=e.authConfig?.[n]?.account??[];return[...O[n].account,...r]}function Di(e,n,t){let r=t.filter(s=>s.required&&!s.configured).map(s=>s.name),o=t.filter(s=>s.level==="integration"&&s.required&&!s.configured).map(s=>s.name),i=t.filter(s=>s.level==="account"&&s.required&&s.configured),a;return o.length>0?a="missing_integration":r.length===0?a="ready":i.length>0?a="partial":a="not_started",{plugin:e,authType:n,status:a,connected:Ri(n,t),fields:t,missingRequiredFields:r}}async function De(e,n,t){let r=I(n);if(!r||!e.database||!e.kek)return null;let o=t.trim()||"default",i=n.authConfig,a=i?.[r]?.integration??[],s=i?.[r]?.account??[],u=S({authType:r,integrationName:n.id,kek:e.kek,database:e.database,extraIntegrationFields:a}),l=_({authType:r,integrationName:n.id,tenantId:o,kek:e.kek,database:e.database,extraAccountFields:s}),c=Ei(n,r),p=_i(n,r),g=[];for(let d of c)g.push({name:d,level:"integration",required:xi(r,d),configured:await qr(u,d)});for(let d of p)g.push({name:d,level:"account",required:Ii(d),configured:await qr(l,d)});return Di(n.id,r,g)}async function Je(e,n,t={}){let r=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,i=[];for(let a of e.plugins){if(o&&!o.has(a.id))continue;let s=await De(e,a,r);s&&i.push(s)}return i}function wn(e){return e.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}var Zr=Symbol.for("corsair:internal"),Gr=new WeakMap;function Oi(e){let n=Gr.get(e);return n||(n=new Map,Gr.set(e,n)),n}function Mi(e){return e.multiTenancy?{withTenant:()=>({}),[Zr]:e}:{[Zr]:e}}async function vn(e,n){if(!e.database)return;let t=n.trim()||"default",r=Oi(e),o=t,i=r.get(o);if(i){await i;return}let a=(async()=>{let{setupCorsair:s}=await import("./setup-37HYI2N6.js");await s(Mi(e),{tenantId:e.multiTenancy?t:void 0,silent:!0})})().finally(()=>{r.delete(o)});r.set(o,a),await a}import{ZodBoolean as Fi,ZodDate as Ui,ZodEnum as Bi,ZodNullable as Ni,ZodNumber as $i,ZodObject as Li,ZodOptional as ji,ZodRecord as Wi,ZodString as Ki,ZodType as qi}from"zod";var Hi={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},repositories:{list:{}}},discord:{guilds:{list:{}},channels:{list:{}}},hubspot:{contacts:{getMany:{}},companies:{getMany:{}},deals:{getMany:{}}},gmail:{messages:{list:{}},labels:{list:{}},drafts:{list:{}},threads:{list:{}}},googlecalendar:{events:{getMany:{}}},googlemeet:{conferenceRecords:{list:{}}},googledrive:{files:{list:{}},folders:{list:{}},sharedDrives:{list:{}}},notion:{databases:{getManyDatabases:{}},databasePages:{getManyDatabasePages:{}},users:{getManyUsers:{}}},airtable:{bases:{getMany:{}}},todoist:{projects:{getMany:{}},tasks:{getMany:{}}},cal:{bookings:{list:{}}},zohomail:{folders:{list:{}},messages:{list:{}}}},ut=Hi;async function Pn(e,n){let t=[],r=n?.silent??!1,o=d=>{t.push(d),r||console.log(d)},i=d=>{t.push(d),r||console.warn(d)},a=n?.caller??"script",s=Pr(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 u=Gi(e,s.plugins,n),l={...s,database:s.database},c=l.database.db;await Vi(c,i);let p=await Yi(c,l,u.tenantId,u.provisionAccounts,o);n?.credentials&&Object.keys(n.credentials).length>0&&await es(e,u,n.credentials,l,o,i);let g=await ts(p,u,o,a);if(n?.backfill){o("[corsair:setup] Starting backfill...");let d=Vr({plugins:s.plugins,database:c,kek:s.kek,multiTenancy:!0}).withTenant(u.tenantId);await rs(d,s.plugins,g,o,i),o("[corsair:setup] Backfill complete.")}return t.join(`
2
+ `)}function ct(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...O[n][t],...r])}function Zi(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let o=n.find(s=>s.id===t);if(!o)continue;let i=I(o);if(!i)continue;let a=ct(o,i,"account");for(let s of Object.keys(r))if(a.has(s))return!0}return!1}function Gi(e,n,t){let r=Ar(e),o=t?.tenantId?.trim(),i=o!==void 0&&o.length>0;if(r&&t?.backfill&&!i)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(r&&Zi(t?.credentials,n)&&!i)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(i&&!o)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:r,tenantIdProvided:i,tenantId:i?o:"default",provisionAccounts:!r||i}}function zr(e,n){return le(e)?n===0?!0:Object.values(e).every(t=>zr(t,n-1)):!1}function Ji(e){return zr(e,4)}var zi={...Sr};function Tn(e){if(e instanceof Li){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof qi?Tn(r):"unknown";return n}return e instanceof Ni?`${Tn(e.unwrap())} | null`:e instanceof ji?`${Tn(e.unwrap())} | undefined`:e instanceof Bi?e.options.join(" | "):e instanceof Ki?"string":e instanceof $i?"number":e instanceof Fi?"boolean":e instanceof Ui?"date":e instanceof Wi?"jsonb":"unknown"}async function Vi(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(o=>o.name));for(let[o,i]of Object.entries(zi))r.has(o)||n(`[corsair:setup] Table "${o}" does not exist. Run your database migrations before calling setupCorsair.
3
+ Schema: ${JSON.stringify(Tn(i),null,2)}`)}async function Yi(e,n,t,r,o){let i=new Date,a=new Map;for(let s of n.plugins){let u=s.id,l=I(s),c=await e.selectFrom("corsair_integrations").selectAll().where("name","=",u).executeTakeFirst();if(!c){let y=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:y,name:u,config:{},created_at:i,updated_at:i}).execute(),c=await e.selectFrom("corsair_integrations").selectAll().where("id","=",y).executeTakeFirst(),o(`[corsair:setup] Created integration: ${u}`)}let p=l?s.authConfig?.[l]?.integration??[]:[],g=l?s.authConfig?.[l]?.account??[]:[],d=l&&c?S({authType:l,integrationName:u,kek:n.kek,database:n.database,extraIntegrationFields:p}):void 0;if(c&&!c.dek&&d&&(await d.issue_new_dek(),o(`[corsair:setup] Issued integration DEK: ${u}`)),!c||!l||!d)continue;let f;if(r){let y=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",c.id).executeTakeFirst();if(!y){let m=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:m,tenant_id:t,integration_id:c.id,config:{},created_at:i,updated_at:i}).execute(),y=await e.selectFrom("corsair_accounts").selectAll().where("id","=",m).executeTakeFirst(),o(`[corsair:setup] Created account: ${u}`)}f=y&&_({authType:l,integrationName:u,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),y&&f&&!y.dek&&(await f.issue_new_dek(),o(`[corsair:setup] Issued account DEK: ${u}`))}a.set(u,{pluginId:u,authType:l,integration:d,account:f,integrationFields:[...O[l].integration,...p],accountFields:r?[...O[l].account,...g]:[]})}return a}function Qi(e){if(!le(e))return;let n=e.keys;return le(n)?n:void 0}function Xi(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function es(e,n,t,r,o,i){let a=Qi(e),s=n.provisionAccounts?Xi(e,n.tenantId):void 0;for(let[u,l]of Object.entries(t)){let c=r.plugins.find(h=>h.id===u);if(!c){i(`[corsair:setup] Unknown plugin '${u}' \u2014 skipping credentials.`);continue}let p=I(c);if(!p){i(`[corsair:setup] Plugin '${u}' has no auth type \u2014 skipping credentials.`);continue}let g=ct(c,p,"integration"),d=ct(c,p,"account"),f=a?.[u],y=s?.[u],m=le(y)?y.keys:void 0;for(let[h,v]of Object.entries(l))if(v){if(g.has(h)){if(n.multiTenant&&n.tenantIdProvided)throw new Error(`[corsair:setup] '${u}.${h}' is an integration-level credential shared across all tenants. You passed tenantId="${n.tenantId}", which only scopes account-level credentials. Run setup without --tenant if you intend to change this credential globally.`);let C=U(f,`set_${h}`);if(!C){i(`[corsair:setup] Cannot set integration field '${h}' for '${u}'.`);continue}await C(v),o(`[corsair:setup] Set ${u} integration.${h}`);continue}if(d.has(h)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${u}.${h}' on a multi-tenant instance`);let C=U(m,`set_${h}`);if(!C){i(`[corsair:setup] Cannot set account field '${h}' for '${u}'.`);continue}await C(v),o(`[corsair:setup] Set ${u} account.${h} (tenant=${n.tenantId})`);continue}i(`[corsair:setup] Unknown credential field '${h}' for plugin '${u}'.`)}}}var Jr=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function ns(e,n,t,r,o,i,a,s,u){let l=[],c=[];for(let g of o){if(Jr.has(g))continue;let d=U(t,`get_${g}`);if(!d)continue;let f=null;try{let y=await d();f=typeof y=="string"?y:null}catch{}f||l.push(g)}if(r&&i.length>0)for(let g of i){if(Jr.has(g))continue;let d=U(r,`get_${g}`);if(!d)continue;let f=null;try{let y=await d();f=typeof y=="string"?y:null}catch{}f||c.push(g)}let p=l.length===0&&c.length===0;if(p)s(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else if(n==="managed")s(`[corsair:setup] '${e}' (managed) is not connected yet. Use Connect in your app \u2014 Corsair Hub delivers OAuth tokens after authorization.`);else{let g=[...l,...c];if(u==="cli"){let d=g.map(f=>`${f}=VALUE`).join(" ");s(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
+ corsair setup --${e} ${d}`)}else{let d=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let f of l)d.push(` await corsair.keys.${e}.set_${f}(value)`);for(let f of c){let y=a.provisionAccounts?a.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(a.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;d.push(` await ${y}.keys.set_${f}(value)`)}s(d.join(`
5
+ `))}}return p}async function ts(e,n,t,r){let o=new Set;for(let i of e.values())await ns(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function rs(e,n,t,r,o){if(!Ji(ut)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=ut,a=new Set(n.map(s=>s.id));for(let[s,u]of Object.entries(i)){if(!a.has(s))continue;if(!t.has(s)){r(`[corsair:setup] Skipping backfill for '${s}' \u2014 auth not configured.`);continue}let l=le(e)?e[s]:void 0,c=le(l)?l.api:void 0;if(c)for(let[p,g]of Object.entries(u))for(let[d,f]of Object.entries(g)){r(`[corsair:setup] Backfilling ${s} \u203A ${p}.${d}...`);try{let y=le(c)?c[p]:void 0;await U(y,d)?.(f)}catch(y){o(`[corsair:setup] ${s} \u203A ${p}.${d} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Yr(e){if(!w(e).database)throw new Error("A database must be configured to provision Corsair integrations");await Pn(e,{silent:!0})}async function ve(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to provision Corsair for connect");await vn(t,n)}var os=Symbol.for("corsair:internal"),is=new Set(["access_token","refresh_token","expires_at","scope"]);function ss(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function as(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!_e(t)&&!is.has(t)):n.filter(t=>!_e(t))}function Qr(e){return{plugins:e.plugins,database:e.database,kek:e.kek,multiTenancy:!1}}function Xr(e){return{[os]:Qr(e)}}async function An(e,n,t={}){let r=pn(e.hub),o=[],i=t.pluginIds?new Set(t.pluginIds):null,a=Qr(e),s=Xr(e);for(let u of e.plugins){if(i&&!i.has(u.id))continue;let l=I(u);if(!l)continue;let c=ss(l),p=t.providerNameOverrides?.[u.id]??de(u.id),g=await De(a,u,n),d=cn(u,l),f=as(l,d),y={plugin:u.id,providerName:p,authKind:c,alreadyConfigured:g?.connected??!1};if(f.length>0&&(y.credentialFields=f),c==="oauth"){let h=t.oauthModeOverrides?.[u.id]??(l==="managed"?"managed":"byo");if(y.oauthMode=h,!t.skipOAuthUrlGeneration&&h!=="managed")try{let v=await lt(s,u.id,{tenantId:n,redirectUri:r,hubConnect:!0});y.oauthUrl=v.url}catch(v){y.setupError=v instanceof Error?v.message:`Could not prepare OAuth for ${u.id}`}}o.push(y)}return o}async function _u(e,n,t={}){let r=w(e),o=r.hub;if(!o)throw new Error("Hub is not configured");return An({plugins:r.plugins,database:r.database,kek:r.kek,hub:o},n,t)}async function dt(e,n){if(!e.database)throw new Error("A database must be configured to provision Corsair for connect");await ve(Xr(e),n)}async function Du(e,n){await ve(e,n)}async function eo(e,n){let t=Ee(e.projectApiKey),r={tenantId:n.tenantId,plugins:n.plugins};return t==="development"&&(r.deliveryUrl=ge({deliveryUrl:n.deliveryUrl})),z({hub:e,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:gn})}async function pt(e,n){let t={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await dt(t,n.tenantId);let r=await An(t,n.tenantId,{pluginIds:[n.plugin.id]});if(r.length===0)throw new Error(`Plugin '${n.plugin.id}' is not configured on this Corsair instance`);return eo(e,{tenantId:n.tenantId,plugins:r,deliveryUrl:n.deliveryUrl})}async function xn(e,n){let t=w(e),r=B(e),o={plugins:t.plugins,database:t.database,kek:t.kek,hub:r};await dt(o,n.tenantId);let i=n.plugin?[n.plugin]:void 0,a=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,s=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,u=await An(o,n.tenantId,{pluginIds:i,oauthModeOverrides:a,providerNameOverrides:s});if(u.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is not configured on this Corsair instance`:"No plugins are configured on this Corsair instance");return eo(r,{tenantId:n.tenantId,plugins:u,deliveryUrl:n.deliveryUrl})}function no(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function us(e,n){return n&&!n.has(e.id)?!1:I(e)!==null}async function to(e,n,t={}){let r=w(e),o=n.trim()||"default",i=t.pluginIds?.length?new Set(t.pluginIds):null,a=await Je(r,o,{pluginIds:t.pluginIds}),s=new Map(a.map(l=>[l.plugin,l])),u=r.plugins.filter(l=>us(l,i)).map(l=>{let c=I(l),p=s.get(l.id);return p?{plugin:l.id,providerName:de(l.id),authKind:no(c),status:p.status,connected:p.connected,fields:p.fields.map(g=>({name:g.name,level:g.level,required:g.required,configured:g.configured})),missingRequiredFields:p.missingRequiredFields}:{plugin:l.id,providerName:de(l.id),authKind:no(c),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:o,plugins:u}}async function ro(e,n){let t=B(e);return Ur({hub:t,path:`/projects/${encodeURIComponent(n.projectId)}/connections`,notFoundMessage:"Hub REST API not found at /projects/:id/connections. Check HUB_API_URL and ensure the Hub API is deployed.",parseResponse:fn})}import*as ze from"crypto";function ye(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function gt(e,{maxAgeMs:n}={}){try{let t=e.includes(".")?e.split(".")[0]:e,r=JSON.parse(Buffer.from(t,"base64url").toString("utf-8"));if(r!==null&&typeof r=="object"&&"plugin"in r&&"tenantId"in r&&typeof r.plugin=="string"&&typeof r.tenantId=="string"){let o=r;return n!==void 0&&typeof o.iat=="number"&&Date.now()-o.iat>n?null:o}return null}catch{return null}}function Oe(e,n){let t=ze.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var ft=600*1e3;function In(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),o=e.slice(t+1),i=ze.createHmac("sha256",n).update(r).digest("base64url"),a=Buffer.from(o,"base64url"),s=Buffer.from(i,"base64url");return a.length!==s.length||!ze.timingSafeEqual(a,s)?null:gt(r,{maxAgeMs:ft})}function Me(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}import*as oo from"querystring";function Te(e){let{oauthConfig:n,clientId:t,redirectUri:r,state:o}=e,i={...n.authParams,client_id:t,redirect_uri:r,response_type:"code",scope:n.scopes.join(" "),state:o};return`${n.authUrl}?${oo.stringify(i)}`}var W=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function cs(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 yt(e,n){let t=w(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 o=In(n,t.kek);if(!o)throw new W("invalid_state","Invalid or tampered state parameter");let{plugin:i,tenantId:a}=o,s=H(t,i,g=>new W("plugin_not_found",g)),u=cs(s),c=await S({authType:"oauth_2",integrationName:i,kek:t.kek,database:t.database}).get_client_id();if(!c)throw new W("client_id_not_configured",`client_id not configured for '${i}'`);let p=Te({oauthConfig:u,clientId:c,redirectUri:r,state:n});return{plugin:i,tenantId:a,providerName:u.providerName,oauthUrl:p,state:n}}import{randomBytes as ds}from"crypto";import{v4 as ps}from"uuid";async function Sn(e,n){let t=Ee(e.projectApiKey),r={permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,expiresAt:n.expiresAt};return t==="development"&&(r.deliveryUrl=ge({deliveryUrl:n.deliveryUrl})),z({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:yn})}function Rn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var mt="Permission approval required. Set manual.approvalBaseUrl (or use hub for hosted approval) so an approval URL can be generated. Optionally set manual.onApprovalRequired to customize the agent message.";function kt(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function io(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function ht(e){return Rn(e)}async function bt(e,n){if(kt(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?io(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await Sn(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:ls(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function ls(e){try{return JSON.parse(e)}catch{return e}}async function En(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await bt(e,n);return{...n,approvalUrl:r}}async function Ct(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:o,permissionToken:i,plugin:a,endpoint:s,args:u,tenantId:l,expiresAt:c,operationPath:p}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:i,id:o,plugin:a,endpoint:s,args:u});let d=await bt({manual:t,hub:r},{id:o,token:i,plugin:a,endpoint:s,args:JSON.stringify(u),tenant_id:l,expires_at:c});return kt(t)?d?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:d}):ht(d):mt:r?d?ht(d):`Action '${p}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:mt}var gs={open:{read:"allow",write:"allow",destructive:"allow"},cautious:{read:"allow",write:"allow",destructive:"require_approval"},strict:{read:"allow",write:"require_approval",destructive:"deny"},readonly:{read:"allow",write:"deny",destructive:"deny"}};function fs(e,n,t){return t!==void 0?t:gs[n][e]}function wt(e){let n=/(\d+)(d|h|m|s)/g,t=0,r;for(;(r=n.exec(e))!==null;){let o=parseInt(r[1],10);switch(r[2]){case"d":t+=o*864e5;break;case"h":t+=o*36e5;break;case"m":t+=o*6e4;break;case"s":t+=o*1e3;break}}return t>0?t:600*1e3}function ao(e){return{async find_by_permission_id(n){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst()},async find_by_token(n){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst()},async set_executing(n){e&&await e.db.updateTable("corsair_permissions").set({status:"executing",updated_at:new Date}).where("id","=",n).execute()},async set_completed(n){e&&await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}}}async function so(e,n,t){let r=Date.now()+t;for(;Date.now()<r;){let o=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!o)return{result:"blocked",reason:"pending"};if(o.status==="approved")return{result:"allow",onComplete:async()=>{await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}};if(o.status==="denied")return{result:"blocked",reason:"denied"};if(o.status==="expired"||o.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(i=>setTimeout(i,500))}return{result:"blocked",reason:"timeout"}}async function uo(e){let n=fs(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 o=JSON.stringify(e.args),i=new Date().toISOString(),a=e.tenantId??"default",s=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",o).where("tenant_id","=",a).where("expires_at",">",i).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(s){if(s.status==="approved"){let f=e.db,y=s.id;return{result:"allow",onComplete:async()=>{await f.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",y).execute()}}}return s.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
8
+ Action: ${r}`,`
9
+ Permission ID: ${s.id}`,`
10
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?so(e.db,s.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:s.id,token:s.token,expiresAt:s.expires_at})}let u=ps(),l=ds(32).toString("hex"),c=e.timeoutMs??600*1e3,p=new Date(Date.now()+c).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:u,created_at:new Date,updated_at:new Date,token:l,plugin:e.pluginId,endpoint:e.endpointPath,args:o,tenant_id:a,status:"pending",expires_at:p}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
11
+ Action: ${r}`,`
12
+ Permission ID: ${u}`,`
13
+ Permission token: ${l}`,`
14
+ Expires at: ${p}`,`
15
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?so(e.db,u,c):{result:"blocked",reason:"pending",id:u,token:l,expiresAt:p}}var A=class extends Error{status;code;extra;constructor(n,t,r,o={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=o}};function R(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function co(e){let n={error:e.code,message:e.message,...e.extra};return R(e.status,n)}function me(e){return new A(404,"not_found",e)}function se(e,n={}){return new A(400,"bad_request",e,n)}function lo(e,n){return H(e,n,t=>me(t))}async function po(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=S({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),o=O[t].integration,i=r,a;try{a=await Promise.all(o.map(l=>i[`get_${l}`]()))}catch{a=o.map(()=>null)}let s=o.filter((l,c)=>a[c]==null),u;return t==="oauth_2"?u=!s.includes("client_id")&&!s.includes("client_secret"):u=s.length===0,{configured:u,missingFields:s}}async function go(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:o,missingFields:i}=await po(e,n);return{id:e.id,authType:t,configured:o,missingFields:i,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function _n(){return{ok:!0}}async function He(e){return Promise.all(e.plugins.map(n=>go(n,e)))}async function Dn(e,n){let t=lo(e,n);return go(t,e)}async function ys(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 fo(e,n){let t=await ys(e,n),r=t.filter(o=>o.hasCredentials).map(o=>o.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function Fe(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let o=r.tenant_id;if(!o)continue;let i=n.get(o);i||(i={id:o,accounts:[],connectedPlugins:[]},n.set(o,i));let a=!!r.dek;i.accounts.push({integrationName:r.integrationName,hasCredentials:a}),a&&i.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function On(e,n){if(!n)throw se("Tenant id must be a non-empty string");return fo(e,n)}async function Mn(e,n){let t=n?.id?.trim();if(!t)throw se("Tenant id is required",{missingFields:["id"]});return fo(e,t)}async function Hn(e,n){let t=n?.trim()||"default",r={},o=await Je(e,t);for(let i of o)r[i.plugin]=wn(i);for(let i of e.plugins)i.id in r||(!i.options?.authType||!e.database||!e.kek?r[i.id]="missing_credentials":r[i.id]="not_connected");return r}async function vt(e,n){if(!e.database)throw me(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw me(`Permission '${n}' not found`);return En(e,t)}function ms(e){if(!e.oauthConfig)throw se(`Plugin '${e.id}' has no oauthConfig`)}function hs(e){if(!e.manual)throw new A(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function Tt(e){let n=hs(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new A(500,"connect_not_configured","Manual connect requires manual.baseUrl and manual.redirectUri. Use hub for hosted connect, or set both URLs for manual OAuth.");return n}function ks(e){let n=!!e.hub,t=Me(e.manual);if(!n&&!t)throw new A(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function yo(e){if(!e.database||!e.kek)throw new A(500,"database_not_configured","A database and kek are required to issue connect links.")}async function bs(e,n){let t=n?.plugin?.trim();if(!t)throw se("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",o=lo(e,t);ms(o);let i=Tt(e);yo(e);let a=await po(o,e);if(!a.configured)throw new A(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:a.missingFields});let s=Oe(ye(t,r),e.kek),u;try{u=new URL(i.baseUrl)}catch{throw new A(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return u.searchParams.set("state",s),{connectUrl:u.toString(),expiresAt:new Date(Date.now()+ft).toISOString()}}async function Cs(e,n,t){yo(n);let o={tenantId:t.tenantId?.trim()||"default",oauthMode:t.oauthMode},i=t.plugin?.trim();i&&(o.plugin=i);let a=t.providerName?.trim();a&&(o.providerName=a);let s=await xn(e,o);return{connectUrl:s.connectUrl,expiresAt:s.expiresAt}}async function Fn(e,n,t){return ks(n),n.hub?Cs(e,n,t):bs(n,t)}async function Un(e,n,t){if(n.hub&&!Me(n.manual))throw new A(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw se("state is required",{missingFields:["state"]});Tt(n);try{return await yt(e,r)}catch(o){if(o instanceof W)switch(o.code){case"invalid_state":throw se("Invalid or expired state");case"client_id_not_configured":throw new A(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new A(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function Bn(e,n,t){if(n.hub&&!Me(n.manual))throw new A(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),o=t?.state?.trim(),i=[];if(r||i.push("code"),o||i.push("state"),i.length)throw se("Missing required fields",{missingFields:i});let a=Tt(n),{processOAuthCallback:s}=await import("./oauth.js");try{return await s(e,{code:r,state:o,redirectUri:a.redirectUri})}catch(u){if(u instanceof Error&&u.name==="OAuthCallbackError")switch(u.code){case"invalid_state":throw se("Invalid or expired state");case"credentials_not_configured":throw new A(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new A(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function Pt(e,n){if(!e.database)throw me("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw me("Permission not found");return En(e,t)}async function mo(e,n){return"id"in n?vt(e,n.id):Pt(e,n.token)}import{createCipheriv as Is,createDecipheriv as Dc,randomBytes as wo,scryptSync as Ss}from"crypto";import{createHmac as At,randomUUID as ws,timingSafeEqual as bo}from"crypto";var ho=new Set(["oauth.callback","oauth.tokens","webhook","permission.approve","permission.deny","auth.credentials","integration.credentials","connect.create_link","connections.sync"]),he=60*1e3,Pe=300*1e3;function Co(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Nn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=At("sha256",e.signingSecret.trim()).update(n).digest("hex");return{body:n,headers:{"content-type":"application/json","x-corsair-signature":`sha256=${r}`,"x-corsair-timestamp":t,"x-corsair-project":e.projectId,"x-corsair-nonce":ws()}}}function xt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Co(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>Pe)return!1;let i=At("sha256",n).update(e.body).digest("hex");try{return bo(Buffer.from(i,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function Ue(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Co(e.signatureHeader);if(!t)return{ok:!1,error:"Invalid tunnel signature"};let r=Number(e.timestampHeader);if(!Number.isFinite(r))return{ok:!1,error:"Invalid or missing tunnel timestamp"};if(Math.abs(Date.now()-r*1e3)>Pe)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let i=At("sha256",n).update(e.body).digest("hex");try{if(!bo(Buffer.from(i,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function $n(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function It(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function Ln(e){let n=e.sync?.encrypted;return typeof n!="string"||!n.trim()?null:{encrypted:n.trim()}}function jn(e){return Ln($n(e))}function vs(e){let n=e;for(;n;){if(n instanceof Error){let t=n.code;if(typeof t=="string")return t;n=n.cause;continue}if(typeof n=="object"&&n!==null&&"code"in n){let t=n.code;if(typeof t=="string")return t}break}}function ko(e,n=200){let t=e.trim();return t.length<=n?t:`${t.slice(0,n)}\u2026`}var Ts="Verify hub.signingSecret in your app matches the signing secret shown in Hub project settings.",Ps="Check the delivery URL configured for this environment.";function As(e){return`${e.ack.error?`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`:`App rejected the signed delivery (HTTP ${e.status} from ${e.deliveryUrl})`}. ${Ts}`}function xs(e){return`${e.ack.error?`${e.ack.error} (HTTP 404 from ${e.deliveryUrl})`:`Delivery endpoint not found at ${e.deliveryUrl} (HTTP 404)`}. ${Ps}`}function Ve(e,n){let t=vs(n),r=n instanceof Error?n.message:"Delivery request failed",o;switch(t){case"ECONNREFUSED":o="connection refused \u2014 nothing accepted a TCP connection on that host and port";break;case"ENOTFOUND":o="host not found \u2014 DNS could not resolve the hostname";break;case"ETIMEDOUT":case"UND_ERR_CONNECT_TIMEOUT":o="connection timed out before the app responded";break;case"ECONNRESET":o="connection reset while talking to the app";break;case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":o=`TLS certificate error (${t})`;break;default:o=r==="fetch failed"&&t?`${r} (${t})`:r}return[`Could not reach ${e}`,o].join(". ")}function St(e){if(e.status===0)return e.ack.error?e.ack.error:e.body.startsWith("Could not reach")?e.body:Ve(e.deliveryUrl,new Error(e.body||"Delivery request failed"));if(e.status===401||e.status===403)return As(e);if(e.status===404)return xs(e);if(e.ack.error)return`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`;if(e.status>=500){let t=e.body.trim();return t?`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl}): ${ko(t)}`:`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl})`}let n=e.body.trim();return n?`${ko(n)} (HTTP ${e.status} from ${e.deliveryUrl})`:`Delivery failed with HTTP ${e.status} from ${e.deliveryUrl}`}async function Rt(e){let{body:n,headers:t}=Nn(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),o=await r.text();return{ok:r.ok,status:r.status,body:o}}catch(r){return{ok:!1,status:0,body:Ve(e.deliveryUrl,r)}}}var Rs="aes-256-gcm",Es=12,_s=16,Ds=16,Os=32;function Ms(e,n){return Ss(e.trim(),n,Os)}function Et(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required to encrypt sync manifest");let r=wo(Ds),o=Ms(t,r),i=wo(Es),a=Is(Rs,o,i,{authTagLength:_s}),s=JSON.stringify(e),u=Buffer.concat([a.update(s,"utf8"),a.final()]),l=a.getAuthTag();return[r.toString("base64"),i.toString("base64"),l.toString("base64"),u.toString("base64")].join(":")}var Hs=["invalid corsair instance","a database must be configured to sync connections from the app","a database must be configured on the corsair instance","signing secret is required to encrypt sync manifest"];function _t(e){if(e instanceof Tr)return!1;if(!(e instanceof Error))return!0;let n=e.message.toLowerCase();return!Hs.some(t=>n.includes(t))}async function Ye(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to sync connections from the app");await Pn(e,{silent:!0});let[r,o]=await Promise.all([Fe(t),He(t)]),i={tenants:r.map(a=>({id:a.id})),plugins:o.map(a=>({id:a.id,authType:a.authType,configured:a.configured,missingFields:a.missingFields})),syncedAt:new Date().toISOString()};return Et(i,n)}var Fs=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Dt(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Fs.has(n)}catch{return!1}}function Ot(e){return e==="development"?"browser":"server"}function vo(e){return Ot(e)==="browser"}function To(e){return Dt(e)?"Production delivery URL must be a public URL, not localhost":null}async function Po(e,n){let t=n.tenantId.trim();if(!t)throw new Error("tenantId is required");let r=n.plugins.map(a=>a.trim()).filter(Boolean);if(r.length===0)throw new Error("At least one plugin is required");let o=w(e);if(!o.hub)throw new Error("Hub is not configured on this Corsair instance");if(!o.database)throw new Error("Database not configured");let i=await Us(o.hub,{plugins:o.plugins,database:o.database,kek:o.kek},{tenantId:t,pluginIds:r});return{connectUrl:i.connectUrl,expiresAt:i.expiresAt}}async function Us(e,n,t){let{buildConnectPluginManifestFromContext:r,ensureConnectAccountRowsFromContext:o}=await import("./setup-introspect-EQWNN6M2.js"),{postHubConnectSession:i}=await import("./connect-MYF4XQQD.js"),a={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await o(a,t.tenantId);let s=await r(a,t.tenantId,{pluginIds:t.pluginIds});if(s.length===0)throw new Error("No connectable plugins found for this tenant");let u=s.find(l=>l.setupError);if(u)throw new Error(u.setupError??`Could not prepare connect link for ${u.plugin}`);return i(e,{tenantId:t.tenantId,plugins:s})}var V=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function Wn(e,n){let t=w(e,()=>new V("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new V("no_database","Database not configured");let r=H(t,n.plugin,c=>new V("plugin_not_found",c)),o=I(r);if(!o)throw new V("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(o==="oauth_2"||o==="managed")throw new V("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await ve(e,n.tenantId);let i=new Set(cn(r,o)),s=r.authConfig?.[o]?.account??[],u=_({authType:o,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:s}),l=0;for(let[c,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(c))throw new V("invalid_credentials",`Unknown credential field '${c}' for plugin '${n.plugin}'`);let g=U(u,`set_${c}`);if(!g)throw new V("invalid_credentials",`Cannot set credential field '${c}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new V("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var Y=class extends Error{code;constructor(n,t){super(t),this.name="IntegrationCredentialsDeliveryError",this.code=n}};async function Mt(e,n){let t=w(e,()=>new Y("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Y("no_database","Database not configured");let r=H(t,n.plugin,c=>new Y("plugin_not_found",c)),o=I(r);if(!o)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);await Yr(e);let i=new Set(xr(r,o)),s=r.authConfig?.[o]?.integration??[],u=S({authType:o,integrationName:n.plugin,kek:t.kek,database:t.database,extraIntegrationFields:s}),l=0;for(let[c,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(c))throw new Y("invalid_credentials",`Unknown integration credential field '${c}' for plugin '${n.plugin}'`);let g=U(u,`set_${c}`);if(!g)throw new Y("invalid_credentials",`Cannot set integration field '${c}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new Y("invalid_credentials","Provide at least one integration credential field to save");return{plugin:n.plugin}}var Kn=new Map;function Bs(e){for(let[n,t]of Kn)t<=e&&Kn.delete(n)}function qn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return Bs(r),Kn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(Kn.set(t,r+n),{ok:!0})}async function Zn(e,n,t){for(let r of e){if(r.id!==n)continue;let o=r.oauthWebhookTenantLinkResolver;return o?o(t):null}return null}var Ao=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function Ns(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 $s(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 j(n.dek,e.kek),r=Ao(n.config),o={};Object.keys(r).length>0&&(o=ie(r,t)),o[e.link.linkType]=e.link.externalId;let i=fe(o,t);await e.database.db.updateTable("corsair_accounts").set({config:i,updated_at:new Date}).where("id","=",n.id).execute()}async function Be(e){let{database:n,kek:t,pluginId:r,tenantId:o,link:i,authType:a,extraAccountFields:s=[]}=e,{accountId:u}=await Ns({database:n,pluginId:r,tenantId:o}),l=!1;if(a){let c=_({authType:a,integrationName:r,tenantId:o,kek:t,database:n,extraAccountFields:s}),p=`set_${i.linkType}`,g=c[p];typeof g=="function"&&(await g(i.externalId),l=!0)}l||await $s({database:n,kek:t,accountId:u,link:i})}async function Ht(e){let{database:n,kek:t,pluginId:r,linkType:o,externalId:i}=e,a=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let s of a)if(s.dek)try{let u=await j(s.dek,t),c=Ao(s.config)[o];if(!c)continue;if(Ze(c,u)===i)return s}catch{continue}return null}async function Gn(e){return(await Ht(e))?.tenant_id??null}async function xo(e){return Gn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var ke=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Ne(e,n){let{plugin:t,tenantId:r,accessToken:o,refreshToken:i,expiresIn:a,scope:s}=n;if(!o.trim())throw new ke("no_access_token","Managed OAuth delivery missing access_token");let u=w(e,()=>new ke("invalid_corsair_instance","Invalid corsair instance"));if(!u.database)throw new ke("no_database","No database configured on corsair instance");let l=H(u,t,p=>new ke("plugin_not_found",p));await ve(e,r);let c=_({authType:"managed",integrationName:t,tenantId:r,kek:u.kek,database:u.database});await c.set_access_token(o),i&&await c.set_refresh_token(i),a&&await c.set_expires_at(String(Math.floor(Date.now()/1e3)+a)),s&&await c.set_scope(s);try{let p=await Zn(u.plugins,t,{access_token:o,refresh_token:i,scope:s});if(p)try{let g=l.authConfig?.managed?.account??[];await Be({database:u.database,kek:u.kek,pluginId:t,tenantId:r,link:p,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(p){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,p)}return{plugin:t,tenantId:r}}function Ls(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Io(e,n,t=[]){for(let[r,o]of Object.entries(e))if(Ls(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=Io(o,n,[...t,r]);if(i)return i}return null}function js(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Ws(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 So(e,n,t,r){let o=js(n),i=typeof t=="string"?JSON.parse(t):t;(!i||typeof i=="object"&&Object.keys(i).length===0)&&o["x-goog-resource-uri"]&&(i=Ws(o)||i);let s={headers:o,body:i,...r?{query:r}:{}},u=r?.tenantId||"default",l=e.withTenant?e.withTenant(u):e,c=ln;for(let p of c){let g=l[p];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(s))continue;let d=Io(g.webhooks,s);if(!d)continue;let f=d.path.join("."),y={payload:i,headers:o,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let m=await d.webhook.handler(y),h=!!Object.keys(m.returnToSender||{})?.length;return{plugin:p,action:f,body:i,response:h?{...m?.returnToSender,success:!0}:{success:!0},...m.responseHeaders&&{responseHeaders:m.responseHeaders}}}catch(m){return console.error(`Error executing webhook handler for ${p}.${f}:`,m),{plugin:p,action:f,body:i,response:{success:!1,error:m instanceof Error?m.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{randomBytes as Gs}from"crypto";import{createHmac as Ks,randomBytes as qs,timingSafeEqual as Zs}from"crypto";function ae(){return qs(16).toString("base64url")}function Qe(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Ks("sha256",t).update(e).digest("base64url")}function Q(e,n){let t=n.trim();if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[o,i]=r;if(!o||!i)return null;let a=Qe(o,t);try{if(!Zs(Buffer.from(i,"utf8"),Buffer.from(a,"utf8")))return null}catch{return null}let s;try{s=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{return null}return s.exp*1e3<Date.now()?null:s}function Jn(e,n,t){let r=Math.floor(Date.now()/1e3),o={...e,iat:r,exp:t},i=Buffer.from(JSON.stringify(o)).toString("base64url"),a=Qe(i,n);return`${i}.${a}`}function Xe(e,n,t){let r=Math.floor(Date.now()/1e3);return Jn(e,n,r+Math.floor(t/1e3))}function Ae(e){return decodeURIComponent(e)}function Ft(e){return encodeURIComponent(e)}function Ro(e){let n=e.trim();return n.length>0?n:null}function zn(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Vn(e,n){if(!Ro(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??Gs(16).toString("base64url"),iat:t,exp:t+Math.floor(he/1e3)},o=Buffer.from(JSON.stringify(r)).toString("base64url"),i=Qe(o,n);return`${o}.${i}`}function be(e,n){return Ro(n)?Q(e,n):null}function xe(e){return e.deliveryMode==="auth.credentials"}function en(e){return e.deliveryMode==="connections.sync"}function nn(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function tn(e){return e.deliveryMode==="oauth.tokens"}function Yn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!xe(e)&&!en(e)&&!nn(e)&&!tn(e)}async function Js(e,n){try{return{status:"ok",webhookResponse:{status:200,body:{status:"ok",sync:{encrypted:await Ye(e,n)}}}}}catch(t){return{status:"failed",retryable:_t(t),error:t instanceof Error?t.message:"Connections sync delivery failed"}}}async function zs(e,n){try{return{status:"ok",connectLink:await Po(e,n)}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Connect link delivery failed"}}}function Ut(e,n){if(e instanceof Headers)return e.get(n)??void 0;let t=e[n]??e[n.toLowerCase()];return Array.isArray(t)?t[0]:typeof t=="string"?t:void 0}async function Vs(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 Gn({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function Ys(e,n,t){let r=await Vs(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await So(e,t.headers,t.body,o);if(!i.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(i.response&&i.response.success===!1)return{status:"failed",retryable:!1,error:typeof i.response.error=="string"?i.response.error:"Webhook handler failed"};let a=i.response?.returnToSender,s=a&&typeof a=="object"&&typeof a.validationToken=="string"&&Object.keys(a).length===1?a.validationToken:a||(i.response?.data??i.response);return{status:"ok",webhookResponse:{status:i.response?.statusCode??200,body:s,headers:i.responseHeaders}}}async function Qs(e,n){return await rn(e,n),{status:"ok"}}async function Xs(e,n){return await Ne(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function Nt(e,n,t){let r=await Bt(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function Bt(e,n,t){let r=w(e),o=n.token?.trim();if(!o)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let i=new Date().toISOString(),a=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",o).executeTakeFirst();return a?a.status!=="pending"?{status:"ok"}:a.expires_at<i?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",a.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",a.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function ea(e,n){try{return await Wn(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function na(e,n){try{return await Mt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Integration credential delivery failed"}}}async function $t(e,n,t={}){let r=w(e),o=Ut(n.headers,"x-corsair-signature"),i=Ut(n.headers,"x-corsair-timestamp"),a=Ut(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let u=Ue({body:n.body,signatureHeader:o,timestampHeader:i,signingSecret:t.signingSecret});if(!u.ok)return{status:"failed",retryable:!1,error:u.error};if(!a?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let l=qn(`nonce:${a.trim()}`,Pe);if(!l.ok)return{status:"failed",retryable:!1,error:l.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}if(s.type==="connect.status")return{status:"failed",retryable:!1,error:"connect.status is deprecated; use connections.sync signed delivery instead"};switch(s.type){case"webhook":return Ys(e,r,s.payload);case"oauth.callback":return Qs(e,s.payload);case"oauth.tokens":return Xs(e,s.payload);case"permission.approve":return Bt(e,s.payload,"approved");case"permission.deny":return Bt(e,s.payload,"denied");case"auth.credentials":return ea(e,s.payload);case"integration.credentials":return na(e,s.payload);case"connect.create_link":return zs(e,s.payload);case"connections.sync":{let u=t.signingSecret?.trim();return u?Js(e,u):{status:"failed",retryable:!1,error:"Tunnel signing secret is required for connections.sync"}}default:return ta(String(s.type))}}function ta(e){return ho.has(e)?{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}:{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}}var Lt=new Map;function Eo(e){let n;try{n=B(e)}catch{return}let t=it(n);t&&Lt.get(n.projectApiKey)!==t&&(Lt.set(n.projectApiKey,t),z({hub:n,path:"/apps/announce",body:{deliveryUrl:t},parseResponse:()=>({ok:!0})}).catch(()=>{Lt.delete(n.projectApiKey)}))}var ra="corsair:client-bridge";function Qn(e){let n=JSON.stringify({type:ra,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 oa=[".corsair.dev"];function ia(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function sa(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:ia(n)?!0:oa.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function _o(e){return!e||!sa(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 Do(e,n){if(!n)return e;let t=new Headers(e.headers);for(let[r,o]of Object.entries(n))t.set(r,o);return new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function jt(e,n){let t=new URL(e);return n.error?(t.searchParams.set("error",n.error),t.toString()):n.connectedPlugin?(t.searchParams.set("connected",n.connectedPlugin),t.toString()):(n.status!==void 0&&t.searchParams.set("status",Buffer.from(JSON.stringify(n.status)).toString("base64url")),t.toString())}async function Wt(e,n){let t=B(e),o=new URL(n).searchParams.get("d");if(!o)return{type:"json",status:200,body:{status:"ok",message:"Corsair tunnel endpoint is active",timestamp:new Date().toISOString()}};let i=be(o,t.signingSecret);if(!i)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let a=qn(`browser:${i.jti}`,he);if(!a.ok)return{type:"json",status:400,body:{error:a.error}};try{if(en(i)){if(!i.hubOrigin||!i.requestId)return{type:"json",status:400,body:{error:"Connections sync delivery requires hubOrigin and requestId for client bridge"}};let s=await Ye(e,t.signingSecret);return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:Qn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",sync:{encrypted:s}}})}}if(xe(i))return i.hubSuccessUrl?i.credentials?(await Wn(e,{plugin:i.plugin,tenantId:i.tenantId,credentials:i.credentials}),{type:"redirect",url:jt(i.hubSuccessUrl,{connectedPlugin:i.plugin})}):{type:"redirect",url:jt(i.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(nn(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await Nt(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(tn(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Ne(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!Yn(i)||!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await rn(e,{code:i.code,state:i.state,redirectUri:i.redirectUri})}}catch(s){let u=s instanceof Error?s.message:"Hub delivery failed";return en(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Qn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:u})}:xe(i)&&i.hubSuccessUrl?{type:"redirect",url:jt(i.hubSuccessUrl,{error:u})}:xe(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Qn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:u})}:{type:"json",status:400,body:{error:u}}}return{type:"redirect",url:i.hubSuccessUrl}}async function Kt(e,n){let t=B(e),r=await $t(e,n,{signingSecret:t.signingSecret});if(r.status!=="ok")return{type:"json",status:r.retryable===!1?400:502,body:{error:r.error??"Tunnel processing failed"}};let o=r.webhookResponse;if(r.connectLink)return{type:"json",status:200,body:{status:"ok",connectUrl:r.connectLink.connectUrl,expiresAt:r.connectLink.expiresAt}};if(!o)return{type:"json",status:200,body:{status:"ok"}};let i=o.status??200,a=o.headers;return o.body&&typeof o.body=="object"&&!(o.body instanceof ArrayBuffer)?{type:"json",status:i,body:o.body,headers:a}:{type:"text",status:i,body:typeof o.body=="string"?o.body:o.body?JSON.stringify(o.body):null,headers:a}}function qt(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 Zt(e,n){return n.method==="GET"?Wt(e,n.url):Kt(e,{headers:n.headers,body:n.body??""})}async function Gt(e,n){try{let t=await Zt(e,n);return qt(t)}catch(t){if(t instanceof pe)return Response.json({error:t.message},{status:503});throw t}}async function Ie(e,n){Eo(e);let t=n.method.toUpperCase(),r=_o(n.headers.get("origin"));if(t==="OPTIONS")return r?new Response(null,{status:204,headers:r}):Response.json({error:"Method not allowed"},{status:405});if(t!=="GET"&&t!=="POST")return Response.json({error:"Method not allowed"},{status:405});let o=await Gt(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return Do(o,r)}var X=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 Oo=300;async function Jt(e,n){let{keys:t,hub:r,plugin:o,tenantId:i}=e,a=n?.forceRefresh??!1,[s,u,l]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!s&&!l)throw new X(o,"managed");let c=Math.floor(Date.now()/1e3);if(!a&&s&&u&&Number(u)>c+Oo)return{accessToken:s,expiresAt:Number(u),refreshed:!1};if(!l&&s&&!a){let d=u?Number(u):null;if(d===null||d>c+Oo)return{accessToken:s,expiresAt:d??c+3600,refreshed:!1}}let p=await ua(r,o,i),g=p.expires_in?c+p.expires_in:u?Number(u):c+3600;return await t.set_access_token(p.access_token),await t.set_expires_at(String(g)),p.refresh_token&&await t.set_refresh_token(p.refresh_token),p.scope&&await t.set_scope(p.scope),{accessToken:p.access_token,expiresAt:g,refreshed:!0}}function aa(e){return e.includes("Managed OAuth connection not found")||e.includes("Managed OAuth connection has no tokens")}async function ua(e,n,t){try{return await z({hub:e,path:"/oauth/refresh",body:{plugin:n,tenantId:t},parseResponse:mn})}catch(r){let o=r instanceof Error?r.message:"";throw aa(o)?new X(n,"managed"):r}}async function Mo(e,n){e._refreshAuth=async()=>(await Jt(n,{forceRefresh:!0})).accessToken}function ca(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType,status:e.status,connected:e.connected,verified:e.verified,missingFields:e.missingFields}}async function la(e){if(!e.hub||!e.database||!e.kek)return;let n={database:e.database,kek:e.kek,plugins:e.plugins};if(!I(e.plugin))return;let r=e.tenantId?.trim()||"default",o=await De(n,e.plugin,r);o&&Ho(e.hub,ca({tenantId:r,plugin:e.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:e.verified??o.connected,missingFields:o.missingRequiredFields}))}function Ho(e,n){z({hub:e,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}function on(e){la(e).catch(()=>{})}function Fo(e){return{delivery:n=>Ie(e,n),deliveryOptions:n=>Ie(e,n)}}var Uo=1200*1e3;function zt(){return ae()}function Vt(){return Uo}function Yt(e,n){return Xe(e,n,Uo)}function Qt(e,n){return Q(e,n)}function Xt(e){return Ae(e)}var Bo=600*1e3;function er(){return ae()}function nr(){return Bo}function tr(e,n){return Xe(e,n,Bo)}function rr(e,n){return Q(e,n)}function or(e){return Ft(e)}function ir(e){return Ae(e)}function sr(){return ae()}function ar(e,n,t){return Jn(e,n,Math.floor(t.getTime()/1e3))}function ur(e,n){return Q(e,n)}function cr(e){return Ae(e)}function Xn(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(o,i){let a=t.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${t.join(" and ")} ${a?"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 ${qe}`)}})}async function da(e){let n=!1;for(;;){let t=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.integrationName).executeTakeFirst();if(!t){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Integration "${e.integrationName}" not found. Make sure to create the integration first.`)}let r=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",t.id).executeTakeFirst();if(!r){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Account not found for tenant "${e.tenantId}" and integration "${e.integrationName}". Make sure to create the account first.`)}return{integrationId:t.id,accountId:r.id,integration:{id:t.id,config:t.config,dek:t.dek??null},account:{id:r.id,config:r.config,dek:r.dek??null}}}}async function No(e){let{integrationId:n,accountId:t}=await da(e);return{integrationId:n,accountId:t}}function lr(e,n){return`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${n}`}async function pa(e,n){let t=e.hub;if(!t||!n.database||!n.kek)return null;try{return(await pt(t,{tenantId:n.tenantId,plugin:n.plugin,database:n.database,kek:n.kek,plugins:n.plugins})).connectUrl}catch{return null}}async function ga(e){let n=e.hub;if(n&&e.database&&e.kek)try{let r=await pt(n,{tenantId:e.tenantId,plugin:e.plugin,database:e.database,kek:e.kek,plugins:e.plugins});return e.manual?.onAuthMissing?e.manual.onAuthMissing({plugin:e.pluginId,connectUrl:r.connectUrl,state:r.token}):lr(e.pluginId,r.connectUrl)}catch{return`[auth-missing:${e.pluginId}:${e.authType}] Authentication required. Could not create connect link. Check hub configuration and server logs.`}let t=await pa({manual:e.manual,hub:e.hub},{plugin:e.plugin,tenantId:e.tenantId,database:e.database,kek:e.kek,plugins:e.plugins});return t?lr(e.pluginId,t):`[auth-missing:${e.pluginId}:${e.authType}]`}function fa(e,n,t){let r=Oe(ye(e,n.tenantId??t??"default"),n.kek),o=new URL(n.baseUrl);o.searchParams.set("state",r);let i=o.toString();return n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:i,state:r}):lr(e,i)}async function $o(e){let n=e.tenantId??"default",t=e.error.pluginId;return e.manual&&Me(e.manual)&&e.manual.oauthConfig&&e.manual.kek&&e.error.authType==="oauth_2"?fa(t,{...e.manual,baseUrl:e.manual.baseUrl,kek:e.manual.kek},e.tenantId):e.hub&&e.plugin&&e.kek&&e.database&&e.plugins?ga({manual:e.manual,hub:e.hub,plugin:e.plugin,pluginId:t,tenantId:n,authType:e.error.authType,database:e.database,kek:e.kek,plugins:e.plugins}):e.error.message}var ya=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Lo(e,n,t,r,o){let i={pluginId:n,operation:t,input:r,originalError:e},a=Object.keys(o).find(l=>o[l]?.match(e,i));return await(o[a||"DEFAULT"]?.handler||ya)(e,i)}function ma(e){return typeof e=="function"}function dr({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:o,errorHandlers:i,currentPath:a=[],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:c,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:f,plugin:y,kek:m,allPlugins:h}){for(let[v,C]of Object.entries(e)){let E=n?.[v];if(ma(C)){let k=E,b=[...a,v].join("."),T=async(x={})=>{let ee;if(u){let M=l?.[b],{result:un,reason:G,onComplete:We,token:te,id:we,expiresAt:L}=await uo({pluginId:o,endpointPath:b,args:x,mode:u.mode,override:u.overrides?.[b],riskLevel:M?.riskLevel??"write",meta:M,db:c,timeoutMs:p?wt(p.timeout):void 0,tenantId:g,approvalMode:p?.mode});if(un==="blocked"){let J;throw G==="denied"?J=`Action '${b}' was denied by the user. Await further instructions before proceeding.`:G==="policy"?J=`Action '${b}' is blocked by the permission policy. Update the corsair config to allow it.`:G==="timeout"?J=`Action '${b}' timed out waiting for approval.`:te&&we?J=await Ct({permissionsOptions:p,manual:d,hub:f,permissionId:we,permissionToken:te,plugin:o,endpoint:b,args:x,tenantId:g??"default",expiresAt:L??new Date(Date.now()+(p?wt(p.timeout):600*1e3)).toISOString(),operationPath:b}):J=`Action '${b}' requires user approval before it can run.`,new Error(J)}ee=We}let D=async(M,un,G)=>{try{return await C(un,G)}catch(We){if(We instanceof Error){let te=await Lo(We,o,b,typeof G=="object"&&G!==null?G:{args:G},i);if(M<(te.maxRetries||0)){let we=M+1;console.log(`Retrying (${we} / ${te.maxRetries})...`);let L;if(te.headersRetryAfterMs)L=te.headersRetryAfterMs;else switch(te.retryStrategy){case"exponential_backoff":L=Math.pow(2,we-1)*1e3;break;case"exponential_backoff_jitter":let J=Math.pow(2,we-1)*1e3,pi=(Math.random()-.5)*1e3;L=Math.max(0,J+pi);break;case"linear_1s":L=1e3;break;case"linear_2s":L=2e3;break;case"linear_3s":L=3e3;break;case"linear_4s":L=4e3;break;default:L=1e3;break}await new Promise(J=>setTimeout(J,L)),await D(we,un,G),console.log(`[corsair:${o}:${b}] Retry strategy:`,te)}}throw We}},ce;try{ce=s?await s(t,"endpoint"):void 0}catch(M){if(M instanceof X)return y&&f&&on({hub:f,database:c,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!1}),$o({error:M,manual:d,hub:f,plugin:y,tenantId:g,database:c,kek:m,plugins:h});throw M}if(!k?.before&&!k?.after){let M=await D(0,{...t,key:ce},x);return await ee?.(),y&&f&&on({hub:f,database:c,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!0}),M}let $={...t,key:ce},ne=k.before?await k.before($,x):{ctx:$,args:x,continue:!0,passToAfter:void 0};if(ne.continue===!1)return;let je=await D(0,ne.ctx,ne.args);return await k.after?.(ne.ctx,je,ne.passToAfter),await ee?.(),y&&f&&on({hub:f,database:c,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!0}),je};r[v]=T}else if(C&&typeof C=="object"){let k={};dr({endpoints:C,hooks:E,ctx:t,tree:k,pluginId:o,errorHandlers:i,currentPath:[...a,v],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:c,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:f,plugin:y,kek:m,allPlugins:h}),r[v]=k}}}function ha(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function pr({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:o}){for(let[i,a]of Object.entries(e)){let s=n?.[i];if(ha(a)){let u=s,l=async c=>{let p=(d,f)=>a.handler(d,f),g=o?await o(t,"webhook"):void 0;return!u?.before&&!u?.after?p({...t,key:g},c):(async()=>{let d={...t,key:g},f=u.before?await u.before(d,c):{ctx:d,args:c,continue:!0,passToAfter:void 0};if(f.continue===!1)return;let y=await p(f.ctx,f.args);return y?.success===!0&&await u.after?.(f.ctx,y,f.passToAfter),y})()};r[i]={match:a.match,handler:l}}else if(a&&typeof a=="object"){let u={};pr({webhooks:a,hooks:s,ctx:t,webhooksTree:u,keyBuilder:o}),r[i]=u}}}function ka(e,n,t,r){let o=null;return async()=>{if(o)return o;if(!e)throw new Error("Database not configured");let{accountId:i}=await No({database:e,integrationName:n,tenantId:t,ensureProvisioned:r});return o=i,o}}function ba(e,n,t,r,o){return e?ot(e.db,n,t,r,o):{findByEntityId:async()=>null,existsByEntityId:async()=>!1,findIdByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function gr(e,n){let{database:t,tenantId:r,kek:o,rootErrorHandlers:i,permissionsOptions:a,manualConfig:s,hubConfig:u,internalConfig:l}=n,c=l&&t?()=>vn(l,r??"default"):void 0,p={},g={};for(let d of e)p[d.id]={},g[d.id]={};for(let d of e){let f=d.schema,y=r??"default",m=ka(t,d.id,y,c);if(f?.entities){let $={};for(let[ne,je]of Object.entries(f.entities)){let M=t?ot(t.db,m,ne,f.version,je):ba(void 0,m,ne,f.version,je);$[ne]=M}g[d.id].db=$,p[d.id].db=$}let h=d.options,v=d.authConfig,C;if(t&&o&&h?.authType){let $=v?.[h.authType]?.account??[];C=_({authType:h.authType,integrationName:d.id,tenantId:y,kek:o,database:t,extraAccountFields:$,ensureProvisioned:c}),p[d.id].keys=C}let E={database:t,db:g[d.id]?.db??{},$getAccountId:m,...d.options?{options:d.options}:{},...C?{keys:C,authType:h?.authType}:{},tenantId:y,...u?{hub:u}:{}},k=d.endpoints??{},b=d.hooks,T={...i,...d.errorHandlers},x={},ee=d.options?.permissions;dr({endpoints:k,hooks:b,ctx:E,tree:x,pluginId:d.id,errorHandlers:T,currentPath:[],keyBuilder:d.keyBuilder,permissionsConfig:ee,endpointMeta:d.endpointMeta,database:t,permissionsOptions:a,tenantId:r,manualConfig:s?{...s,oauthConfig:d.oauthConfig,kek:o,tenantId:y}:void 0,hubConfig:u,plugin:d,kek:o,allPlugins:e}),Object.keys(x).length>0&&(p[d.id].api=x),E.endpoints=x;let D=d.webhooks??{},ce=d.webhookHooks;if(Object.keys(D).length>0){let $={};pr({webhooks:D,hooks:ce,ctx:E,webhooksTree:$,keyBuilder:d.keyBuilder}),p[d.id].webhooks=$,d.pluginWebhookMatcher&&(p[d.id].pluginWebhookMatcher=d.pluginWebhookMatcher),d.pluginTenantWebhookMatcher&&(p[d.id].pluginTenantWebhookMatcher=d.pluginTenantWebhookMatcher)}}return p}function jo(e,n,t){let r={};for(let o of e){let i=o.options,a=o.authConfig;if(i?.authType){let s=a?.[i.authType]?.integration??[],u=S({authType:i.authType,integrationName:o.id,kek:t,database:n,extraIntegrationFields:s});r[o.id]=u}}return r}var Ca="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function Wo(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] ${Ca}`),t):n}var Ko=[{method:"GET",pattern:"/ok",handler:async()=>R(200,_n())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>R(200,await Fe(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>R(201,await Mn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>R(200,await On(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>R(200,await He(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>R(200,await Dn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>R(200,await Hn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>R(200,await vt(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?R(200,await Pt(e,t)):R(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>R(200,await Fn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>R(200,await Un(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>R(200,await Bn(e,n,t))}];(()=>{let e=new Set;for(let n of Ko){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function wa(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let o={};for(let i=0;i<t.length;i++){let a=t[i],s=r[i];if(a.startsWith(":"))o[a.slice(1)]=decodeURIComponent(s);else if(a!==s)return null}return o}function va(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 Ta(e){if(!(e.method==="GET"||e.method==="HEAD"||!(e.headers.get("content-type")??"").includes("application/json")))try{let t=await e.text();return t?JSON.parse(t):void 0}catch{throw new A(400,"invalid_json","Request body is not valid JSON")}}var Pa="/api/corsair";function Se(e,n={}){let t=n.basePath??Pa,r=w(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async o=>{try{let i=new URL(o.url),a=va(i.pathname,t),s=o.method.toUpperCase();if(s==="OPTIONS"||a==="/"||a==="")return await Ie(e,o);if(s!=="GET"&&s!=="POST")return R(405,{error:"method_not_allowed",message:`Method ${s} not allowed`});let u=Object.fromEntries(i.searchParams);for(let l of Ko){if(l.method!==s)continue;let c=wa(l.pattern,a);if(!c)continue;let p=await Ta(o);return await l.handler({corsair:e,internal:r,req:o,params:c,query:u,body:p})}throw me(`No route for ${s} ${a}`)}catch(i){if(n.onError){let s=await n.onError(i,o);if(s)return s}if(i instanceof A)return co(i);let a=i instanceof Error?i.message:"Internal server error";return R(500,{error:"internal_error",message:a})}}}function Aa(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,o=`${t}://${n}${r}`,i=new Headers;for(let[u,l]of Object.entries(e.headers))if(l!=null)if(Array.isArray(l))for(let c of l)i.append(u,c);else i.set(u,l);let a=e.method!=="GET"&&e.method!=="HEAD",s={method:e.method,headers:i};return a&&e.body!==void 0&&(s.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),i.has("content-type")||i.set("content-type","application/json")),new Request(o,s)}async function xa(e,n){e.status(n.status),n.headers.forEach((r,o)=>e.setHeader(o,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function qo(e,n){let t=Se(e,n);return async(r,o,i)=>{try{let a=await t(Aa(r));await xa(o,a)}catch(a){i(a)}}}function Zo(e,n){let t=Se(e,n);return r=>t(r.req.raw)}function Go(e,n){let t=Se(e,n);return{GET:t,POST:t,OPTIONS:t}}function Jo(e){let n={[sn]:e};return{ok:_n,tenants:{list:()=>Fe(e),create:t=>Mn(e,t),get:t=>On(e,t)},plugins:{list:()=>He(e),get:t=>Dn(e,t)},connectionStatus:{get:t=>Hn(e,t?.tenantId)},permissions:{get:t=>mo(e,t)},connect:{createLink:t=>Fn(n,e,t),resolve:t=>Un(n,e,t),oauthCallback:t=>Bn(n,e,t)}}}async function zo(e,n,t,r,o="pending"){if(!e)return null;try{let i=Ir(),a=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:a,updated_at:a,account_id:n,event_type:t,payload:r,status:o}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function Ia(e,n,t,r="pending"){try{let o=await e.$getAccountId();return zo(e.database,o,n,t,r)}catch(o){return console.warn("Failed to log event:",o),null}}import*as Vo from"https";import*as Yo from"querystring";function et(e,n,t,r,o){let i=new URL(r.tokenUrl),a=r.tokenAuthMethod==="basic";return new Promise((s,u)=>{let l={code:e.trim(),redirect_uri:o,grant_type:"authorization_code"};a||(l.client_id=n,l.client_secret=t);let c=Yo.stringify(l),p={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(c).toString()};a&&(p.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=Vo.request({hostname:i.hostname,...i.port?{port:Number(i.port)}:{},path:i.pathname+i.search,method:"POST",headers:p},d=>{let f="";d.on("data",y=>{f+=y}),d.on("end",()=>{if(d.statusCode!==200){u(new Error(`Token exchange failed (${d.statusCode}): ${f}`));return}try{s(JSON.parse(f))}catch{u(new Error(`Token endpoint returned non-JSON response: ${f}`))}})});g.on("error",d=>u(new Error(`Request failed: ${d.message}`))),g.write(c),g.end()})}var Qo=" ";function q(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 ei(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 ni(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function tt(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function $e(e){return Array.isArray(e.options)?e.options:Array.isArray(e.values)?e.values:e.entries!==null&&typeof e.entries=="object"&&!Array.isArray(e.entries)?Object.values(e.entries):[]}function ti(e,n){return e.description??n.description}function Sa(e){let n=e;for(;n;){let t=q(n),r=ti(n,t);if(r)return r;let o=Z(t);if(kr(o)||o==="ZodPipe"||o==="ZodEffects"||o==="ZodTransform"){n=ei(t,o);continue}break}}function kr(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function F(e){let n=q(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??$e(n)[0]??"unknown");case"ZodEnum":return $e(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=K(n);return r?F(r):"unknown"}case"ZodNullable":{let r=K(n);return`${r?F(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=K(n);return r?F(r):"unknown"}case"ZodArray":{let r=ni(n);if(!r)return"unknown[]";let o=q(r),i=Z(o)==="ZodUnion",a=F(r);return`${i?`(${a})`:a}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=tt(e,n),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([a,s])=>{let u=Z(q(s));return`${u==="ZodOptional"||u==="ZodNullable"?a+"?":a}: ${F(s)}`}).join(", ")} }`}case"ZodUnion":return $e(n).map(r=>F(r)).join(" | ");case"ZodIntersection":return`${F(n.left)} & ${F(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=ei(n,t);return r?F(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function ue(e){let n=q(e),t=Z(n),r=ti(e,n);switch(t){case"ZodString":return{kind:"string",optional:!1,description:r};case"ZodNumber":return{kind:"number",optional:!1,description:r};case"ZodBoolean":return{kind:"boolean",optional:!1,description:r};case"ZodLiteral":{let o=n.value??$e(n)[0],i=typeof o=="string"||typeof o=="number"||typeof o=="boolean"?o:String(o??"");return{kind:"literal",optional:!1,description:r,value:i}}case"ZodEnum":{let o=$e(n).map(i=>String(i));return{kind:"string",optional:!1,description:r,enum:o}}case"ZodOptional":{let o=K(n),i=o?ue(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodNullable":{let o=K(n),i=o?ue(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodDefault":case"ZodCatch":{let o=K(n);return o?{...ue(o),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let o=ni(n);return{kind:"array",optional:!1,description:r,items:o?ue(o):{kind:"unknown",optional:!1}}}case"ZodObject":{let o=tt(e,n),i={};for(let[a,s]of Object.entries(o))i[a]=ue(s);return{kind:"object",optional:!1,description:r,fields:i}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let o=$e(n);for(let i of o){let a=q(i);if(Z(a)==="ZodObject")return{...ue(i),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let o=K(n);return o?{...ue(o),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function ag(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let o=t.slice(0,r),i=t.slice(r+1),a=e.find(c=>c.id===o);if(!a)return null;let s=i;s.startsWith("api.")&&(s=s.slice(4));let u=Ce(a.endpointMeta,s),l=Ce(a.endpointSchemas,s);return!u&&!l?null:{input:l?.input?ue(l.input):null,output:l?.output?ue(l.output):null,description:u?.description}}var br=["equals","contains","startsWith","endsWith","in"],Ra=["equals","gt","gte","lt","lte","in"],Ea=["equals"],_a=["equals","before","after","between"];function ri(e){let n=q(e);switch(Z(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=K(n);return r?ri(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Cr(e){let n=q(e),t=Z(n);if(kr(t)){let i=K(n);return i?Cr(i):{}}if(t!=="ZodObject")return{};let r=tt(e,n),o={};for(let[i,a]of Object.entries(r)){let s=ri(a);s==="string"?o[i]={type:"string",operators:br}:s==="number"?o[i]={type:"number",operators:Ra}:s==="boolean"?o[i]={type:"boolean",operators:Ea}:s==="date"&&(o[i]={type:"date",operators:_a})}return o}function oi(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function yr(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];typeof o=="function"?t.push(i.join(".")):o!==null&&typeof o=="object"&&yr(o,i,t)}}function mr(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function hr(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];mr(o)?t.push(i.join(".")):o!==null&&typeof o=="object"&&hr(o,i,t)}}function wr(e,n){if(n.length===0)return null;let[t,...r]=n,o=Object.entries(e).find(([s])=>s.toLowerCase()===t);if(!o)return null;let[i,a]=o;if(r.length===0)return mr(a)?[i]:null;if(a!==null&&typeof a=="object"&&!mr(a)){let s=wr(a,r);if(s!==null)return[i,...s]}return null}function ii(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let i=0;i<n.length;i++){let a=" ".repeat(i+2);t.push(`${a}${n[i]}: {`)}let r=" ".repeat(n.length+2),o=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${o}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let i=n.length-1;i>=0;i--){let a=" ".repeat(i+2);t.push(`${a}},`)}return t.push(" },"),t.push("})"),t.join(`
26
+ `)}var Da=new Set(ln);function Re(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let i=e.find(s=>s.id===r);if(!i)return Da.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:Re(e);if(t==="webhooks"){if(!i.webhooks)return[];let s=[];return hr(i.webhooks,[],s),s.map(u=>`${i.id}.webhooks.${u}`)}if(t==="db"){let s=i.schema?.entities;return s?Object.keys(s).map(u=>`${i.id}.db.${u}.search`):[]}if(!i.endpoints)return[];let a=[];return yr(i.endpoints,[],a),a.map(s=>`${i.id}.api.${s}`)}let o={};if(t==="webhooks")for(let i of e){if(!i.webhooks)continue;let a=[];hr(i.webhooks,[],a),o[i.id]=a.map(s=>`${i.id}.webhooks.${s}`)}else if(t==="db")for(let i of e){let a=i.schema?.entities;a&&(o[i.id]=Object.keys(a).map(s=>`${i.id}.db.${s}.search`))}else for(let i of e){if(!i.endpoints)continue;let a=[];yr(i.endpoints,[],a),o[i.id]=a.map(s=>`${i.id}.api.${s}`)}return o}function Ce(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function Oa(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let i=t.slice(n.length+1),a=i.startsWith(".")?i.slice(1):i;return a.startsWith("api.")&&(a=a.slice(4)),{shortPath:a,lookupKey:a}}let o=e.slice(n.length+1);return o.toLowerCase().startsWith("api.")&&(o=o.slice(4)),{shortPath:o,lookupKey:o.toLowerCase()}}function fr(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 ug(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let o=t.slice(0,r),i=t.slice(r+1),a=e.find(s=>s.id===o);if(a){if(i.startsWith("db.")){let c=i.slice(3),p=c.lastIndexOf(".");if(p!==-1){let g=c.slice(0,p),d=c.slice(p+1),f=a.schema?.entities;if(d==="search"&&f){let y=oi(f,g);if(y){let[m,h]=y,v=Cr(h),C=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${br.join(", ")}]`];for(let[E,k]of Object.entries(v))C.push(` ${E}?: ${k.type} [${k.operators.join(", ")}]`);return C.push("}"),C.join(`
30
+ `)}}}return fr(Re(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let c=i.slice(9);if(a.webhooks){let p=wr(a.webhooks,c.split("."));if(p!==null){let g=p.join("."),d=Ce(a.webhookSchemas,g.toLowerCase()),f=d?.response?F(d.response):null,y=[];return d?.description&&y.push(d.description),d?.payload&&y.push(`payload ${nt(Le(d.payload))}`),f&&y.push(`response: ${f}`),y.push(`usage:
31
+ ${ii(o,p)}`),y.join(`
32
+
33
+ `)}}return fr(Re(e,{type:"webhooks"}),"Path not found. Available webhooks")}let s=i;s.startsWith("api.")&&(s=s.slice(4));let u=Ce(a.endpointMeta,s),l=Ce(a.endpointSchemas,s);if(u||l){let c=[],p=[u?.riskLevel?`[${u.riskLevel}]`:"",u?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),g=[u?.description,p].filter(Boolean).join(" ");return g&&c.push(g),l?.input&&c.push(`input ${nt(Le(l.input))}`),l?.output&&c.push(`output ${nt(Le(l.output))}`),c.join(`
34
+
35
+ `)}}}return fr(Re(e),"Path not found. Available operations")}function Xo(e){let n=e;for(;;){let t=q(n),r=Z(t);if(kr(r)){let o=K(t);if(!o)return n;n=o;continue}return n}}function Le(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=Xo(e),t=q(n);if(Z(t)==="ZodObject"){let o=tt(n,t),i=[];for(let[a,s]of Object.entries(o)){let u=q(s),l=Z(u),c=l==="ZodOptional"||l==="ZodNullable",p=Xo(s),g=Sa(s);i.push({key:a,optional:c,type:F(p),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:i}}return{kind:"inline",type:F(n)}}function nt(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=Qo.repeat(n+1),r=Qo.repeat(n);return`{
36
+ ${e.fields.map(i=>{let a=i.optional?`${i.key}?`:i.key,s=i.description?` // ${i.description}`:"";return`${t}${a}: ${i.type}${s}`}).join(`
37
+ `)}
38
+ ${r}}`}return"unknown"}function Ma(e,n){let t=Re(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(c=>c.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let o=[];for(let c of t){let{shortPath:p,lookupKey:g}=Oa(c,n),d=Ce(r.endpointMeta,g),f=Ce(r.endpointSchemas,g);!d&&!f||o.push({path:c,shortPath:p,description:d?.description,riskLevel:d?.riskLevel,irreversible:d?.irreversible,input:Le(f?.input),output:Le(f?.output)})}o.sort((c,p)=>c.path.localeCompare(p.path));let i=[],a=Re(e,{plugin:n,type:"webhooks"});if(Array.isArray(a)&&r.webhooks)for(let c of a){let g=c.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("webhooks."))continue;let f=d.slice(9),y=wr(r.webhooks,f.split("."));if(y===null)continue;let m=y.join("."),h=Ce(r.webhookSchemas,m.toLowerCase()),v=h?.response?F(h.response):void 0;i.push({path:c,description:h?.description,payload:Le(h?.payload),responseType:v,usageExample:ii(n,y)})}i.sort((c,p)=>c.path.localeCompare(p.path));let s=[],u=Re(e,{plugin:n,type:"db"}),l=r.schema?.entities;if(Array.isArray(u)&&l)for(let c of u){let g=c.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("db."))continue;let f=d.slice(3),y=f.lastIndexOf(".");if(y===-1)continue;let m=f.slice(0,y);if(f.slice(y+1)!=="search")continue;let v=oi(l,m);if(!v)continue;let[C,E]=v,k=Cr(E),b=Object.entries(k).map(([T,x])=>({field:T,type:x.type,operators:x.operators}));s.push({path:c,entityName:C,filters:[{field:"entity_id",type:"string",operators:br},...b]})}return s.sort((c,p)=>c.path.localeCompare(p.path)),{ok:!0,data:{pluginId:n,api:o,webhooks:i,db:s}}}function si(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function Ha(e,n){let t=si(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let o=r.pluginTenantWebhookMatcher(n);return o?{plugin:t,tenantMatch:o}:null}function Fa(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function ai(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function ui(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 an(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function Ua(e){return an(e.body)}function ci(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return rt(Array.isArray(r)?r:[r])}function li(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let u of t){let l=rt(Array.isArray(u)?u:[u]);if(l)return decodeURIComponent(l)}let r=ci({query:e.query},"validationToken");if(r)return r;let o=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let u of o){let l=n[u],c=Array.isArray(l)?l[0]:l;if(!(!c||typeof c!="string"))try{let g=(c.startsWith("http")?new URL(c):new URL(`https://example.invalid${c.startsWith("/")?c:`/${c}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let i=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,a=an(typeof i=="string"?(()=>{try{return JSON.parse(i)}catch{return i}})():i);return rt([a?.validationToken])??null}function Ba(e){if(li(e))return!0;let n=an(e.body??e.payload);return ai(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function rt(e){for(let n of e){let t=ui(n);if(t)return t}}function Na(e){let t=an(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var sn=Symbol.for("corsair:internal");function Vr(e){let n=e.database?vr(e.database):void 0,t=n&&e.kek?jo(e.plugins,n,e.kek):Xn(!!n,!!e.kek),r=Wo(e),o={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?dn(e.hub):void 0},i=ao(n),a=Jo(o);if(e.multiTenancy)return Object.assign({withTenant:u=>{if(!u)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let l=gr(e.plugins,{database:n,tenantId:u,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign(l,{[sn]:o})},keys:t,permissions:i,manage:a},{[sn]:o});let s=gr(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign({},s,{keys:t,permissions:i,manage:a,[sn]:o})}var N=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function di(e){let n=e.oauthConfig;if(!n)throw new N("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function $a(e,n,t,r){let o=Rr(e),i=await o.integrations.findByName(n);if(!i)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await o.accounts.findOne({tenant_id:t,integration_id:i.id}))return;let s=re(),u=await oe(s,r);await o.accounts.create({tenant_id:t,integration_id:i.id,config:{},dek:u})}async function lt(e,n,t){let{tenantId:r,redirectUri:o,hubConnect:i=!1}=t,a=w(e,()=>new N("invalid_corsair_instance","Invalid corsair instance"));if(!a.database)throw new Error("No database configured on corsair instance");let s=H(a,n,g=>new N("plugin_not_found",g)),u=di(s),c=await S({authType:"oauth_2",integrationName:n,kek:a.kek,database:a.database}).get_client_id();if(!c)throw new Error(`client_id not configured for '${n}'`);if(i){let g=new URL(Te({oauthConfig:u,clientId:c,redirectUri:o,state:""}));return g.searchParams.delete("state"),{url:g.toString(),state:""}}let p=Oe(ye(n,r),a.kek);return{url:Te({oauthConfig:u,clientId:c,redirectUri:o,state:p}),state:p}}async function rn(e,n){let{code:t,state:r,redirectUri:o}=n,i=w(e,()=>new N("invalid_corsair_instance","Invalid corsair instance")),a=In(r,i.kek);if(!a)throw new N("invalid_state","Invalid or tampered state parameter");let{plugin:s,tenantId:u}=a;if(!i.database)throw new N("no_database","No database configured on corsair instance");let l=H(i,s,m=>new N("plugin_not_found",m)),c=di(l),p=S({authType:"oauth_2",integrationName:s,kek:i.kek,database:i.database}),g=await p.get_client_id(),d=await p.get_client_secret();if(!g||!d)throw new N("credentials_not_configured",`Credentials not configured for '${s}'`);await $a(i.database,s,u,i.kek);let f=await et(t,g,d,c,o);if(!f.access_token)throw new N("no_access_token",`No access_token returned from ${c.providerName}`);let y=_({authType:"oauth_2",integrationName:s,tenantId:u,kek:i.kek,database:i.database});await y.set_access_token(f.access_token),f.refresh_token&&await y.set_refresh_token(f.refresh_token),f.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+f.expires_in));try{let m=await Zn(i.plugins,s,f);if(m)try{let h=l.authConfig?.oauth_2?.account??[];await Be({database:i.database,kek:i.kek,pluginId:s,tenantId:u,link:m,authType:"oauth_2",extraAccountFields:h})}catch(h){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${s}' tenant '${u}':`,h)}}catch(m){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${s}' tenant '${u}':`,m)}return{plugin:s,tenantId:u}}export{Er as a,de as b,Ke as c,pe as d,dn as e,B as f,pn as g,Ee as h,gn as i,fn as j,yn as k,mn as l,Dr as m,hn as n,ge as o,re as p,oe as q,j as r,st as s,Ze as t,fe as u,ie as v,Ge as w,S as x,_ as y,Wr as z,Kr as A,ye as B,gt as C,Be as D,Ht as E,Gn as F,xo as G,Te as H,N as I,lt as J,rn as K,Pn as L,es as M,An as N,_u as O,dt as P,Du as Q,eo as R,pt as S,xn as T,to as U,ro as V,yt as W,Sn as X,Rn as Y,he as Z,Pe as _,Nn as $,xt as aa,Ue as ba,$n as ca,It as da,Ln as ea,jn as fa,Ve as ga,St as ha,Rt as ia,Dt as ja,Ot as ka,vo as la,To as ma,ke as na,Ne as oa,So as pa,ae as qa,zn as ra,Vn as sa,be as ta,xe as ua,nn as va,tn as wa,Yn as xa,Nt as ya,$t as za,Wt as Aa,Kt as Ba,qt as Ca,Zt as Da,Gt as Ea,Ie as Fa,X as Ga,Jt as Ha,Mo as Ia,Fo as Ja,zt as Ka,Vt as La,Yt as Ma,Qt as Na,Xt as Oa,er as Pa,nr as Qa,tr as Ra,rr as Sa,or as Ta,ir as Ua,sr as Va,ar as Wa,ur as Xa,cr as Ya,Se as Za,qo as _a,Zo as $a,Go as ab,zo as bb,Ia as cb,et as db,ag as eb,Re as fb,ug as gb,nt as hb,Ma as ib,si as jb,Ha as kb,Fa as lb,ai as mb,ui as nb,an as ob,Ua as pb,ci as qb,li as rb,Ba as sb,rt as tb,Na as ub,sn as vb,Vr as wb};
@@ -1 +1 @@
1
- import{R as a,S as b,T as c}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as createHubConnectSession,b as createHubConnectSessionForPlugin,a as postHubConnectSession};
1
+ import{R as a,S as b,T as c}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as createHubConnectSession,b as createHubConnectSessionForPlugin,a as postHubConnectSession};
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{A as o,Ga as q,W as p,a,b,bb as r,cb as s,db as t,hb as u,ib as v,jb as w,kb as x,lb as y,mb as z,nb as A,ob as B,p as d,pb as C,q as e,qb as D,r as f,rb as E,s as g,sb as F,t as h,tb as G,u as i,ub as H,v as j,vb as I,w as k,wb as J,x as l,y as m,z as n}from"./chunk-VT7FIN7U.js";import{h as c}from"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,p as resolveConnectLink,A as toExternalId};
1
+ import{A as o,Ga as q,W as p,a,b,bb as r,cb as s,db as t,hb as u,ib as v,jb as w,kb as x,lb as y,mb as z,nb as A,ob as B,p as d,pb as C,q as e,qb as D,r as f,rb as E,s as g,sb as F,t as h,tb as G,u as i,ub as H,v as j,vb as I,w as k,wb as J,x as l,y as m,z as n}from"./chunk-3CCCHQ7N.js";import{h as c}from"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,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
@@ -331,9 +331,13 @@ declare function processManagedOAuthDelivery(corsair: unknown, options: ProcessM
331
331
  declare function createHubPermissionSession(hub: HubConfig, input: HubPermissionSessionInput): Promise<HubPermissionSessionResult>;
332
332
  declare function formatHubApprovalMessage(approvalUrl: string): string;
333
333
 
334
+ /**
335
+ * One knob: `CORSAIR_DELIVERY_URL` (full endpoint, wins over everything).
336
+ * Without it, auto-detects `http://localhost:{PORT}/api/corsair` — PORT is
337
+ * set by the runtime, not something users configure for Corsair.
338
+ */
334
339
  declare function resolveHubDeliveryUrl(input?: {
335
340
  deliveryUrl?: string;
336
- deliveryPath?: string;
337
341
  }): string;
338
342
 
339
343
  declare function createHubRouteHandlers(corsair: unknown): {
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as v,Aa as P,Ba as Q,Ca as R,Da as S,Ea as T,Fa as U,Ha as V,Ia as W,Ja as X,Ka as Y,La as Z,Ma as _,Na as $,Oa as aa,Pa as ba,Qa as ca,Ra as da,Sa as ea,T as o,Ta as fa,U as p,Ua as ga,V as q,Va as ha,Wa as ia,X as r,Xa as ja,Y as s,Ya as ka,Z as t,_ as u,aa as w,b as a,ba as x,c as b,ca as y,d as c,da as z,e as d,ea as A,f as e,fa as B,g as f,ga as C,h as g,ha as D,i as h,ia as E,j as i,ja as F,k as j,ka as G,l as k,la as H,m as l,ma as I,n as m,na as J,o as n,oa as K,qa as L,ra as M,sa as N,ta as O}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{t as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,J as ManagedOAuthDeliveryError,u as SIGNED_TUNNEL_REPLAY_WINDOW_MS,W as attachManagedRefreshAuth,M as buildBrowserDeliveryRedirectUrl,Y as createConnectSessionJti,ba as createConnectTokenJti,o as createHubConnectSession,r as createHubPermissionSession,X as createHubRouteHandlers,ha as createPermissionSessionJti,L as createSignedTokenJti,aa as decodeConnectSessionTokenFromPath,ga as decodeConnectTokenFromPath,ka as decodePermissionTokenFromPath,E as deliverSignedEnvelope,C as describeDeliveryNetworkError,fa as encodeConnectTokenForPath,A as extractSyncFromDeliveryAck,s as formatHubApprovalMessage,a as formatProviderDisplayName,D as formatServerDeliveryError,Z as getConnectSessionExpiryMs,p as getConnectStatusForTenant,ca as getConnectTokenExpiryMs,e as getHubConfig,V as getManagedAccessToken,P as handleHubDeliveryGet,Q as handleHubDeliveryPost,S as handleHubDeliveryRequest,R as hubDeliveryToResponse,g as inferHubEnvironmentSlug,F as isLoopbackUrl,z as isServerDeliveryAckSuccessful,q as listHubProjectConnections,d as normalizeHubConfig,h as parseConnectSessionResponse,l as parseConnectStatusResponse,m as parseHubApiErrorBody,k as parseOAuthRefreshResponse,j as parsePermissionSessionResponse,i as parseProjectConnectionsResponse,y as parseServerDeliveryAckBody,B as parseSyncFromDeliveryBody,K as processManagedOAuthDelivery,G as resolveDeliveryTransport,n as resolveHubDeliveryUrl,f as resolveHubOAuthCallbackUrl,T as respondToHubDelivery,U as respondToHubDeliveryFromRequest,N as signBrowserDeliveryToken,_ as signConnectSessionToken,da as signConnectToken,v as signDeliveryEnvelope,ia as signPermissionToken,H as usesBrowserDelivery,I as validateProductionDeliveryUrl,O as verifyBrowserDeliveryToken,$ as verifyConnectSessionToken,ea as verifyConnectToken,w as verifyDeliveryEnvelope,ja as verifyPermissionToken,x as verifySignedTunnelDelivery};
1
+ import{$ as v,Aa as P,Ba as Q,Ca as R,Da as S,Ea as T,Fa as U,Ha as V,Ia as W,Ja as X,Ka as Y,La as Z,Ma as _,Na as $,Oa as aa,Pa as ba,Qa as ca,Ra as da,Sa as ea,T as o,Ta as fa,U as p,Ua as ga,V as q,Va as ha,Wa as ia,X as r,Xa as ja,Y as s,Ya as ka,Z as t,_ as u,aa as w,b as a,ba as x,c as b,ca as y,d as c,da as z,e as d,ea as A,f as e,fa as B,g as f,ga as C,h as g,ha as D,i as h,ia as E,j as i,ja as F,k as j,ka as G,l as k,la as H,m as l,ma as I,n as m,na as J,o as n,oa as K,qa as L,ra as M,sa as N,ta as O}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{t as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,J as ManagedOAuthDeliveryError,u as SIGNED_TUNNEL_REPLAY_WINDOW_MS,W as attachManagedRefreshAuth,M as buildBrowserDeliveryRedirectUrl,Y as createConnectSessionJti,ba as createConnectTokenJti,o as createHubConnectSession,r as createHubPermissionSession,X as createHubRouteHandlers,ha as createPermissionSessionJti,L as createSignedTokenJti,aa as decodeConnectSessionTokenFromPath,ga as decodeConnectTokenFromPath,ka as decodePermissionTokenFromPath,E as deliverSignedEnvelope,C as describeDeliveryNetworkError,fa as encodeConnectTokenForPath,A as extractSyncFromDeliveryAck,s as formatHubApprovalMessage,a as formatProviderDisplayName,D as formatServerDeliveryError,Z as getConnectSessionExpiryMs,p as getConnectStatusForTenant,ca as getConnectTokenExpiryMs,e as getHubConfig,V as getManagedAccessToken,P as handleHubDeliveryGet,Q as handleHubDeliveryPost,S as handleHubDeliveryRequest,R as hubDeliveryToResponse,g as inferHubEnvironmentSlug,F as isLoopbackUrl,z as isServerDeliveryAckSuccessful,q as listHubProjectConnections,d as normalizeHubConfig,h as parseConnectSessionResponse,l as parseConnectStatusResponse,m as parseHubApiErrorBody,k as parseOAuthRefreshResponse,j as parsePermissionSessionResponse,i as parseProjectConnectionsResponse,y as parseServerDeliveryAckBody,B as parseSyncFromDeliveryBody,K as processManagedOAuthDelivery,G as resolveDeliveryTransport,n as resolveHubDeliveryUrl,f as resolveHubOAuthCallbackUrl,T as respondToHubDelivery,U as respondToHubDeliveryFromRequest,N as signBrowserDeliveryToken,_ as signConnectSessionToken,da as signConnectToken,v as signDeliveryEnvelope,ia as signPermissionToken,H as usesBrowserDelivery,I as validateProductionDeliveryUrl,O as verifyBrowserDeliveryToken,$ as verifyConnectSessionToken,ea as verifyConnectToken,w as verifyDeliveryEnvelope,ja as verifyPermissionToken,x as verifySignedTunnelDelivery};
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{a as N,b as j}from"./chunk-XLNT2UI2.js";import{$a as T,D as y,E as h,F as k,G as x,Ga as I,L as P,W as b,Za as O,_a as R,ab as A,eb as l,fb as c,gb as d,hb as m,jb as L,kb as W,lb as F,mb as v,nb as E,ob as _,pa as S,pb as $,tb as M,ub as D,vb as g,wb as H,za as w}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";function s(n){let t=n[g];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function B(n,t){let r=c(s(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
1
+ import{a as N,b as j}from"./chunk-XLNT2UI2.js";import{$a as T,D as y,E as h,F as k,G as x,Ga as I,L as P,W as b,Za as O,_a as R,ab as A,eb as l,fb as c,gb as d,hb as m,jb as L,kb as W,lb as F,mb as v,nb as E,ob as _,pa as S,pb as $,tb as M,ub as D,vb as g,wb as H,za as w}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";function s(n){let t=n[g];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function B(n,t){let r=c(s(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
2
2
  `):Object.values(r).flat().join(`
3
3
  `)}function J(n,t){return d(s(n),t)}function q(n,t){return l(s(n),t)}var Y=Symbol.for("corsair:internal");function z(n,t){let r=n;for(let e of t){if(!r||typeof r!="object")return null;r=r[e]}return typeof r=="function"?r:null}function C(n){return n[Y]?.database}async function G(n,t){let r=new Date().toISOString(),e=await n.permissions.find_by_token(t);if(!e)return console.error("executePermission: no permission found for token."),{error:"executePermission: no permission found for token."};if(e.status!=="approved")return console.error(`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`};if(e.expires_at<r){let o=C(n);return o&&await o.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",e.id).execute(),console.error(`executePermission: permission '${e.id}' has expired.`),{error:`executePermission: permission '${e.id}' has expired.`,endpoint:e.endpoint,plugin:e.plugin,result:null}}let f=e.tenant_id??"default",a=(n.withTenant?n.withTenant(f):n)[e.plugin];if(!a?.api)return console.error(`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`),{error:`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`,plugin:e.plugin,endpoint:e.endpoint,result:null};let p=z(a.api,e.endpoint.split("."));if(!p)return console.error(`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`};await n.permissions.set_executing(e.id);try{let o=typeof e.args=="string"?JSON.parse(e.args):e.args,i=await p(o);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:i}}catch(o){let i=o instanceof Error?o.message:String(o),u=C(n);return u&&await u.db.updateTable("corsair_permissions").set({status:"failed",error:i,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:i}}}export{I as AuthMissingError,N as CorsairClientError,_ as asRecord,F as collectPluginWebhookMatchers,H as createCorsair,j as createCorsairClient,D as decodePubSubData,G as executePermission,M as firstString,m as formatDocSchemaShape,v as getHeader,J as getSchema,q as getStructuredSchema,B as listOperations,O as managementHandler,L as matchWebhookPlugin,W as matchWebhookPluginAndTenant,w as processCorsair,S as processWebhook,$ as readBodyRecord,h as resolveAccountFromWebhookLink,b as resolveConnectLink,x as resolveTenantFromWebhookLink,k as resolveTenantIdFromWebhookLink,y as setWebhookTenantLink,P as setupCorsair,R as toExpressHandler,E as toExternalId,T as toHonoHandler,A as toNextJsHandler};
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{B as a,C as b,H as c,I as d,J as e,K as f}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{d as OAuthCallbackError,c as buildOAuthAuthorizeUrl,b as decodeOAuthState,a as encodeOAuthState,e as generateOAuthUrl,f as processOAuthCallback};
1
+ import{B as a,C as b,H as c,I as d,J as e,K as f}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{d as OAuthCallbackError,c as buildOAuthAuthorizeUrl,b as decodeOAuthState,a as encodeOAuthState,e as generateOAuthUrl,f as processOAuthCallback};
@@ -1 +1 @@
1
- import{L as a,M as b}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{L as a,M as b}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
@@ -1 +1 @@
1
- import{N as a,O as b,P as c,Q as d}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as buildConnectPluginManifest,a as buildConnectPluginManifestFromContext,d as ensureConnectAccountRows,c as ensureConnectAccountRowsFromContext};
1
+ import{N as a,O as b,P as c,Q as d}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as buildConnectPluginManifest,a as buildConnectPluginManifestFromContext,d as ensureConnectAccountRows,c as ensureConnectAccountRowsFromContext};
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{L as a,M as b}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{L as a,M as b}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
package/dist/tunnel.js CHANGED
@@ -1 +1 @@
1
- import{D as a,E as b,F as c,G as d,ta as e,ua as f,va as g,wa as h,xa as i,ya as j,za as k}from"./chunk-VT7FIN7U.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{j as applyPermissionDecision,f as isAuthCredentialsBrowserDelivery,i as isByoOAuthBrowserDelivery,h as isManagedBrowserDelivery,g as isPermissionBrowserDelivery,k as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,e as verifyBrowserDeliveryToken};
1
+ import{D as a,E as b,F as c,G as d,ta as e,ua as f,va as g,wa as h,xa as i,ya as j,za as k}from"./chunk-3CCCHQ7N.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{j as applyPermissionDecision,f as isAuthCredentialsBrowserDelivery,i as isByoOAuthBrowserDelivery,h as isManagedBrowserDelivery,g as isPermissionBrowserDelivery,k as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,e as verifyBrowserDeliveryToken};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.101",
3
+ "version": "0.1.102",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,38 +0,0 @@
1
- import{a as vr,b as ue,c as Pr,d as w,e as H,f as Tr,g as U,h as O,i as I,j as un,k as Ar,l as xr,m as ot,n as Ir,o as Sr}from"./chunk-BPFUYXOD.js";import{a as wr}from"./chunk-IGGCNGU2.js";var ln=["agentql","ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gitlab","gmail","googlecalendar","googledrive","googlemeet","googlesheets","grafana","hackernews","hubspot","instagram","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","supabase","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],Rr={agentql:"AgentQL",ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",cursor:"Cursor",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledrive:"Google Drive",googlemeet:"Google Meet",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",instagram:"Instagram",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",supabase:"Supabase",tally:"Tally",tavily:"Tavily",teams:"Teams",telegram:"Telegram",todoist:"Todoist",trello:"Trello",twilio:"Twilio",twitter:"Twitter",twitterapiio:"Twitter API IO",typeform:"Typeform",vapi:"Vapi",xquik:"XQuik",youtube:"YouTube",zendesk:"Zendesk",zohomail:"Zoho Mail",zoom:"Zoom"};function le(e){let n=Rr[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var Ke="https://auth.corsair.dev";var de=class extends Error{constructor(){super("Hub is not configured. Pass hub: { projectApiKey, signingSecret } to createCorsair()."),this.name="HubNotConfiguredError"}};function dn(e){let n=(e.apiUrl?.trim()||Ke).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim();if(!t||!r)throw new Error("Hub config requires non-empty projectApiKey and signingSecret");return{apiUrl:n,projectApiKey:t,signingSecret:r,oauthCallbackUrl:e.oauthCallbackUrl?.trim().replace(/\/$/,"")}}function di(e){return e.apiUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function J(e){let n=w(e).hub;if(!n||!di(n))throw new de;return n}function Er(e){return e.replace(/\/$/,"")}function pn(e){return e.oauthCallbackUrl?Er(e.oauthCallbackUrl.trim()):`${Er(e.apiUrl)}/oauth/callback`}function Re(e){if(e.startsWith("ck_dev_"))return"development";if(e.startsWith("ck_prod_"))return"production";throw new Error("Hub API key must start with ck_dev_ (development) or ck_prod_ (production)")}function T(e){return typeof e=="string"&&e.length>0}function pi(e){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"}function gi(e){return e==="oauth_2"||e==="api_key"||e==="bot_token"||e==="managed"}function gn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty connect session");let n=e;if(!T(n.connectUrl)||!T(n.token)||!T(n.projectId))throw new Error("Hub API returned an incomplete connect session (expected connectUrl, token, and projectId)");let t={connectUrl:n.connectUrl,token:n.token,projectId:n.projectId,environmentId:T(n.environmentId)?n.environmentId:n.projectId};return T(n.expiresAt)&&(t.expiresAt=n.expiresAt),t}function fn(e){if(!Array.isArray(e))throw new Error("Hub API returned an invalid connections response (expected array)");let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;if(!T(r.tenantId)||!T(r.plugin)||!pi(r.status)||!gi(r.authType)||typeof r.connected!="boolean"||typeof r.verified!="boolean")continue;let o=Array.isArray(r.missingFields)?r.missingFields.filter(i=>typeof i=="string"):[];n.push({tenantId:r.tenantId,plugin:r.plugin,status:r.status,authType:r.authType,connected:r.connected,verified:r.verified,missingFields:o,reportedAt:T(r.reportedAt)?r.reportedAt:new Date().toISOString()})}return n}function yn(e){if(!e||typeof e!="object")throw new Error("Hub API returned an empty permission session");let n=e;if(!T(n.approvalUrl)||!T(n.token)||!T(n.projectId)||!T(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 mn(e){if(!e||typeof e!="object")throw new Error("Hub token refresh returned an empty response");let n=e;if(T(n.access_token))return{access_token:n.access_token,refresh_token:T(n.refresh_token)?n.refresh_token:void 0,expires_in:(()=>{if(typeof n.expires_in=="number")return n.expires_in;if(typeof n.expires_in=="string"&&n.expires_in.trim().length>0){let t=Number(n.expires_in);return Number.isFinite(t)?t:void 0}})(),scope:T(n.scope)?n.scope:void 0};throw new Error(T(n.error)?T(n.error_description)?n.error_description:n.error:"Hub token refresh returned no access_token")}function fi(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function yi(e){if(!Array.isArray(e))return[];let n=[];for(let t of e){if(!t||typeof t!="object")continue;let r=t;T(r.name)&&n.push({name:r.name,level:r.level==="integration"||r.level==="account"?r.level:"account",required:r.required===!0,configured:r.configured===!0})}return n}function mi(e,n,t,r){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"?e:n?"ready":t.some(i=>i.level==="integration"&&i.required&&!i.configured)?"missing_integration":t.some(i=>i.level==="account"&&i.required&&i.configured)?"partial":(r.length>0,"not_started")}function _r(e){if(!e||typeof e!="object")throw new Error("Connect status response was empty");let n=e;if(!T(n.tenantId)||!Array.isArray(n.plugins))throw new Error("Connect status response was incomplete (expected tenantId and plugins)");let t=[];for(let r of n.plugins){if(!r||typeof r!="object")continue;let o=r;if(!T(o.plugin)||typeof o.connected!="boolean")continue;let i=o.authKind==="oauth"||o.authKind==="api_key"||o.authKind==="bot_token"?o.authKind:"api_key",a=yi(o.fields),s=fi(o.missingRequiredFields),c=mi(o.status,o.connected,a,s);t.push({plugin:o.plugin,providerName:T(o.providerName)?o.providerName:o.plugin,authKind:i,status:c,connected:o.connected,fields:a,missingRequiredFields:s})}return{tenantId:n.tenantId,plugins:t}}function hn(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}function Dr(e){return e.replace(/\/$/,"")}async function Or(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 Mr(e,n,t){if(n===404&&t)return t;let r=hn(e);return r||`Hub API returned HTTP ${n}`}async function pe(e){let n=Dr(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 Or(t);if(!t.ok)throw new Error(Mr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function Hr(e){let n=Dr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`}}),r=await Or(t);if(!t.ok)throw new Error(Mr(r,t.status,e.notFoundMessage));return e.parseResponse(r)}var hi="3000",ki="/api/corsair";function it(e){return e.replace(/\/$/,"")}function bi(e,n){return`${it(e)}${n}`}function Fr(e){return e.startsWith("http")?e:`https://${e}`}function Ee(e){let n=e?.deliveryUrl?.trim();if(n)return it(n);let t=e?.deliveryPath?.trim()||ki,r=t.startsWith("/")?t:`/${t}`,o=process.env.CORSAIR_DELIVERY_URL?.trim();if(o)return it(Fr(o));let i=process.env.APP_URL?.trim()||process.env.NEXT_PUBLIC_APP_URL?.trim()||process.env.VERCEL_URL?.trim();return i?bi(Fr(i),r):`http://localhost:${process.env.PORT?.trim()||hi}${r}`}import{createCipheriv as Ur,createDecipheriv as Br,randomBytes as kn,scrypt as Ci}from"crypto";import{promisify as wi}from"util";var Nr=wi(Ci),bn="aes-256-gcm",Lr=12,Cn=16,vi=16,qe=32;function te(){return kn(qe).toString("base64")}async function re(e,n){let t=kn(vi),r=await Nr(n,t,qe),o=kn(Lr),i=Ur(bn,r,o,{authTagLength:Cn}),a=Buffer.concat([i.update(e,"utf8"),i.final()]),s=i.getAuthTag();return[t.toString("base64"),o.toString("base64"),s.toString("base64"),a.toString("base64")].join(":")}async function $(e,n){let[t,r,o,i]=e.split(":");if(!t||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let a=Buffer.from(t,"base64"),s=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),l=Buffer.from(i,"base64"),u=await Nr(n,a,qe),p=Br(bn,u,s,{authTagLength:Cn});return p.setAuthTag(c),Buffer.concat([p.update(l),p.final()]).toString("utf8")}function st(e,n){let t=Buffer.from(n,"base64"),r=kn(Lr),o=Ur(bn,t,r,{authTagLength:Cn}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),a=o.getAuthTag();return[r.toString("base64"),a.toString("base64"),i.toString("base64")].join(":")}function Ze(e,n){let[t,r,o]=e.split(":");if(!t||!r||!o)throw new Error("Invalid encrypted data format");let i=Buffer.from(n,"base64"),a=Buffer.from(t,"base64"),s=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),l=Br(bn,i,a,{authTagLength:Cn});return l.setAuthTag(s),Buffer.concat([l.update(c),l.final()]).toString("utf8")}function ge(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=st(o,n);return t}function oe(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Ze(o,n);return t}function Ge(e,n,t){let r=oe(e,n);return ge(r,t)}function $r(e,n,t){let r={};for(let o of t)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let a=[null,void 0,""].includes(i)?null:i;await n({[o]:a})};return r}var at=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function S(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,a=[...O[n].integration,...i],s=null,c={kek:r,integrationName:t,getIntegration:async()=>{if(s)return s;let f=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!f)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return s={id:f.id,config:at(f.config),dek:f.dek??null},s},updateIntegration:async f=>{let y=await c.getIntegration();await o.db.updateTable("corsair_integrations").set({...f.config!==void 0?{config:f.config}:{},...f.dek!==void 0?{dek:f.dek}:{},updated_at:new Date}).where("id","=",y.id).execute(),s=null}},l=null,u=async()=>{if(l)return l;let f=await c.getIntegration();if(!f.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return l=await $(f.dek,r),l},p=async()=>{let f=await c.getIntegration(),y=await u(),m=f.config;return!m||Object.keys(m).length===0?{}:oe(m,y)};return{get_dek:u,issue_new_dek:async()=>{let f=await c.getIntegration(),y=te(),m={};if(f.dek){let v=await $(f.dek,r),C=f.config;C&&Object.keys(C).length>0&&(m=Ge(C,v,y))}let h=await re(y,r);return await c.updateIntegration({config:m,dek:h}),l=y,y},...$r(p,async f=>{let y=await u(),m;try{m=await p()}catch(C){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,C),m={}}let h={...m};for(let[C,E]of Object.entries(f))E===null?delete h[C]:h[C]=E;let v=ge(h,y);await c.updateIntegration({config:v})},a)}}function _(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:a=[],ensureProvisioned:s}=e,c=[...O[n].account,...a],l=null,u=null,p=async()=>{if(u)return u;let k=!1;for(;;){let b=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!b){if(!k&&s){k=!0,await s();continue}throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`)}return u={id:b.id,config:at(b.config),dek:b.dek??null},u}},g={kek:o,integrationName:t,tenantId:r,getIntegration:p,getAccount:async()=>{if(l)return l;let k=!1;for(;;){let b=await p(),P=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",b.id).executeTakeFirst();if(!P){if(!k&&s){k=!0,await s();continue}throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`)}return l={id:P.id,config:at(P.config),dek:P.dek??null},l}},updateAccount:async k=>{let b=await g.getAccount();await i.db.updateTable("corsair_accounts").set({...k.config!==void 0?{config:k.config}:{},...k.dek!==void 0?{dek:k.dek}:{},updated_at:new Date}).where("id","=",b.id).execute(),l=null}},d=null,f=null,y=async()=>{if(d)return d;let k=await g.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return d=await $(k.dek,o),d},m=async()=>{if(f)return f;let k=await g.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return f=await $(k.dek,o),f},h=async()=>{let k=await g.getAccount(),b=await y(),P=k.config;return!P||Object.keys(P).length===0?{}:oe(P,b)},v=async()=>{let k=await g.getIntegration(),b=await m(),P=k.config;return!P||Object.keys(P).length===0?{}:oe(P,b)},E={get_dek:y,issue_new_dek:async()=>{let k=await g.getAccount(),b=te(),P={};if(k.dek){let X=await $(k.dek,o),D=k.config;D&&Object.keys(D).length>0&&(P=Ge(D,X,b))}let x=await re(b,o);return await g.updateAccount({config:P,dek:x}),d=b,b},...$r(h,async k=>{let b=await y(),P;try{P=await h()}catch(D){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,D),P={}}let x={...P};for(let[D,ce]of Object.entries(k))ce===null?delete x[D]:x[D]=ce;let X=ge(x,b);await g.updateAccount({config:X})},c)};return n==="oauth_2"&&(E.get_integration_credentials=async()=>{let k=await v();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),E}async function jr(e,n,t){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!r)throw new Error(`Integration "${n}" not found.`);let o=te(),i=await re(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function Wr(e,n,t,r){let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!o)throw new Error(`Integration "${n}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",o.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${t}" and integration "${n}".`);let a=te(),s=await re(a,r);return await e.db.updateTable("corsair_accounts").set({dek:s,updated_at:new Date}).where("id","=",i.id).execute(),a}var Pi=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function _e(e){return Pi.has(e)}function Ti(e,n){return _e(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function Ai(e){return!_e(e)}function xi(e){switch(e){case"oauth_2":case"managed":return["access_token","refresh_token"];case"api_key":return["api_key"];case"bot_token":return["bot_token"]}}function Ii(e,n){return xi(e).every(r=>n.find(i=>i.level==="account"&&i.name===r)?.configured??!1)}async function Kr(e,n){if(!e)return!1;let t=U(e,`get_${n}`);if(!t)return!1;try{let r=await t();return typeof r=="string"&&r.length>0}catch{return!1}}function Si(e,n){let r=e.authConfig?.[n]?.integration??[];return[...O[n].integration,...r]}function Ri(e,n){let r=e.authConfig?.[n]?.account??[];return[...O[n].account,...r]}function Ei(e,n,t){let r=t.filter(s=>s.required&&!s.configured).map(s=>s.name),o=t.filter(s=>s.level==="integration"&&s.required&&!s.configured).map(s=>s.name),i=t.filter(s=>s.level==="account"&&s.required&&s.configured),a;return o.length>0?a="missing_integration":r.length===0?a="ready":i.length>0?a="partial":a="not_started",{plugin:e,authType:n,status:a,connected:Ii(n,t),fields:t,missingRequiredFields:r}}async function De(e,n,t){let r=I(n);if(!r||!e.database||!e.kek)return null;let o=t.trim()||"default",i=n.authConfig,a=i?.[r]?.integration??[],s=i?.[r]?.account??[],c=S({authType:r,integrationName:n.id,kek:e.kek,database:e.database,extraIntegrationFields:a}),l=_({authType:r,integrationName:n.id,tenantId:o,kek:e.kek,database:e.database,extraAccountFields:s}),u=Si(n,r),p=Ri(n,r),g=[];for(let d of u)g.push({name:d,level:"integration",required:Ti(r,d),configured:await Kr(c,d)});for(let d of p)g.push({name:d,level:"account",required:Ai(d),configured:await Kr(l,d)});return Ei(n.id,r,g)}async function Je(e,n,t={}){let r=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,i=[];for(let a of e.plugins){if(o&&!o.has(a.id))continue;let s=await De(e,a,r);s&&i.push(s)}return i}function wn(e){return e.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}var qr=Symbol.for("corsair:internal"),Zr=new WeakMap;function _i(e){let n=Zr.get(e);return n||(n=new Map,Zr.set(e,n)),n}function Di(e){return e.multiTenancy?{withTenant:()=>({}),[qr]:e}:{[qr]:e}}async function vn(e,n){if(!e.database)return;let t=n.trim()||"default",r=_i(e),o=t,i=r.get(o);if(i){await i;return}let a=(async()=>{let{setupCorsair:s}=await import("./setup-NVGQHCCO.js");await s(Di(e),{tenantId:e.multiTenancy?t:void 0,silent:!0})})().finally(()=>{r.delete(o)});r.set(o,a),await a}import{ZodBoolean as Mi,ZodDate as Hi,ZodEnum as Fi,ZodNullable as Ui,ZodNumber as Bi,ZodObject as Ni,ZodOptional as Li,ZodRecord as $i,ZodString as ji,ZodType as Wi}from"zod";var Oi={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},repositories:{list:{}}},discord:{guilds:{list:{}},channels:{list:{}}},hubspot:{contacts:{getMany:{}},companies:{getMany:{}},deals:{getMany:{}}},gmail:{messages:{list:{}},labels:{list:{}},drafts:{list:{}},threads:{list:{}}},googlecalendar:{events:{getMany:{}}},googlemeet:{conferenceRecords:{list:{}}},googledrive:{files:{list:{}},folders:{list:{}},sharedDrives:{list:{}}},notion:{databases:{getManyDatabases:{}},databasePages:{getManyDatabasePages:{}},users:{getManyUsers:{}}},airtable:{bases:{getMany:{}}},todoist:{projects:{getMany:{}},tasks:{getMany:{}}},cal:{bookings:{list:{}}},zohomail:{folders:{list:{}},messages:{list:{}}}},ct=Oi;async function Tn(e,n){let t=[],r=n?.silent??!1,o=d=>{t.push(d),r||console.log(d)},i=d=>{t.push(d),r||console.warn(d)},a=n?.caller??"script",s=Pr(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 c=qi(e,s.plugins,n),l={...s,database:s.database},u=l.database.db;await Ji(u,i);let p=await zi(u,l,c.tenantId,c.provisionAccounts,o);n?.credentials&&Object.keys(n.credentials).length>0&&await Qi(e,c,n.credentials,l,o,i);let g=await es(p,c,o,a);if(n?.backfill){o("[corsair:setup] Starting backfill...");let d=zr({plugins:s.plugins,database:u,kek:s.kek,multiTenancy:!0}).withTenant(c.tenantId);await ns(d,s.plugins,g,o,i),o("[corsair:setup] Backfill complete.")}return t.join(`
2
- `)}function ut(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...O[n][t],...r])}function Ki(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let o=n.find(s=>s.id===t);if(!o)continue;let i=I(o);if(!i)continue;let a=ut(o,i,"account");for(let s of Object.keys(r))if(a.has(s))return!0}return!1}function qi(e,n,t){let r=Tr(e),o=t?.tenantId?.trim(),i=o!==void 0&&o.length>0;if(r&&t?.backfill&&!i)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(r&&Ki(t?.credentials,n)&&!i)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(i&&!o)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:r,tenantIdProvided:i,tenantId:i?o:"default",provisionAccounts:!r||i}}function Jr(e,n){return ue(e)?n===0?!0:Object.values(e).every(t=>Jr(t,n-1)):!1}function Zi(e){return Jr(e,4)}var Gi={...Ir};function Pn(e){if(e instanceof Ni){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Wi?Pn(r):"unknown";return n}return e instanceof Ui?`${Pn(e.unwrap())} | null`:e instanceof Li?`${Pn(e.unwrap())} | undefined`:e instanceof Fi?e.options.join(" | "):e instanceof ji?"string":e instanceof Bi?"number":e instanceof Mi?"boolean":e instanceof Hi?"date":e instanceof $i?"jsonb":"unknown"}async function Ji(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(o=>o.name));for(let[o,i]of Object.entries(Gi))r.has(o)||n(`[corsair:setup] Table "${o}" does not exist. Run your database migrations before calling setupCorsair.
3
- Schema: ${JSON.stringify(Pn(i),null,2)}`)}async function zi(e,n,t,r,o){let i=new Date,a=new Map;for(let s of n.plugins){let c=s.id,l=I(s),u=await e.selectFrom("corsair_integrations").selectAll().where("name","=",c).executeTakeFirst();if(!u){let y=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:y,name:c,config:{},created_at:i,updated_at:i}).execute(),u=await e.selectFrom("corsair_integrations").selectAll().where("id","=",y).executeTakeFirst(),o(`[corsair:setup] Created integration: ${c}`)}let p=l?s.authConfig?.[l]?.integration??[]:[],g=l?s.authConfig?.[l]?.account??[]:[],d=l&&u?S({authType:l,integrationName:c,kek:n.kek,database:n.database,extraIntegrationFields:p}):void 0;if(u&&!u.dek&&d&&(await d.issue_new_dek(),o(`[corsair:setup] Issued integration DEK: ${c}`)),!u||!l||!d)continue;let f;if(r){let y=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",u.id).executeTakeFirst();if(!y){let m=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:m,tenant_id:t,integration_id:u.id,config:{},created_at:i,updated_at:i}).execute(),y=await e.selectFrom("corsair_accounts").selectAll().where("id","=",m).executeTakeFirst(),o(`[corsair:setup] Created account: ${c}`)}f=y&&_({authType:l,integrationName:c,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),y&&f&&!y.dek&&(await f.issue_new_dek(),o(`[corsair:setup] Issued account DEK: ${c}`))}a.set(c,{pluginId:c,authType:l,integration:d,account:f,integrationFields:[...O[l].integration,...p],accountFields:r?[...O[l].account,...g]:[]})}return a}function Vi(e){if(!ue(e))return;let n=e.keys;return ue(n)?n:void 0}function Yi(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function Qi(e,n,t,r,o,i){let a=Vi(e),s=n.provisionAccounts?Yi(e,n.tenantId):void 0;for(let[c,l]of Object.entries(t)){let u=r.plugins.find(h=>h.id===c);if(!u){i(`[corsair:setup] Unknown plugin '${c}' \u2014 skipping credentials.`);continue}let p=I(u);if(!p){i(`[corsair:setup] Plugin '${c}' has no auth type \u2014 skipping credentials.`);continue}let g=ut(u,p,"integration"),d=ut(u,p,"account"),f=a?.[c],y=s?.[c],m=ue(y)?y.keys:void 0;for(let[h,v]of Object.entries(l))if(v){if(g.has(h)){if(n.multiTenant&&n.tenantIdProvided)throw new Error(`[corsair:setup] '${c}.${h}' is an integration-level credential shared across all tenants. You passed tenantId="${n.tenantId}", which only scopes account-level credentials. Run setup without --tenant if you intend to change this credential globally.`);let C=U(f,`set_${h}`);if(!C){i(`[corsair:setup] Cannot set integration field '${h}' for '${c}'.`);continue}await C(v),o(`[corsair:setup] Set ${c} integration.${h}`);continue}if(d.has(h)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${c}.${h}' on a multi-tenant instance`);let C=U(m,`set_${h}`);if(!C){i(`[corsair:setup] Cannot set account field '${h}' for '${c}'.`);continue}await C(v),o(`[corsair:setup] Set ${c} account.${h} (tenant=${n.tenantId})`);continue}i(`[corsair:setup] Unknown credential field '${h}' for plugin '${c}'.`)}}}var Gr=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function Xi(e,n,t,r,o,i,a,s,c){let l=[],u=[];for(let g of o){if(Gr.has(g))continue;let d=U(t,`get_${g}`);if(!d)continue;let f=null;try{let y=await d();f=typeof y=="string"?y:null}catch{}f||l.push(g)}if(r&&i.length>0)for(let g of i){if(Gr.has(g))continue;let d=U(r,`get_${g}`);if(!d)continue;let f=null;try{let y=await d();f=typeof y=="string"?y:null}catch{}f||u.push(g)}let p=l.length===0&&u.length===0;if(p)s(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else if(n==="managed")s(`[corsair:setup] '${e}' (managed) is not connected yet. Use Connect in your app \u2014 Corsair Hub delivers OAuth tokens after authorization.`);else{let g=[...l,...u];if(c==="cli"){let d=g.map(f=>`${f}=VALUE`).join(" ");s(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
- corsair setup --${e} ${d}`)}else{let d=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let f of l)d.push(` await corsair.keys.${e}.set_${f}(value)`);for(let f of u){let y=a.provisionAccounts?a.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(a.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;d.push(` await ${y}.keys.set_${f}(value)`)}s(d.join(`
5
- `))}}return p}async function es(e,n,t,r){let o=new Set;for(let i of e.values())await Xi(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function ns(e,n,t,r,o){if(!Zi(ct)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=ct,a=new Set(n.map(s=>s.id));for(let[s,c]of Object.entries(i)){if(!a.has(s))continue;if(!t.has(s)){r(`[corsair:setup] Skipping backfill for '${s}' \u2014 auth not configured.`);continue}let l=ue(e)?e[s]:void 0,u=ue(l)?l.api:void 0;if(u)for(let[p,g]of Object.entries(c))for(let[d,f]of Object.entries(g)){r(`[corsair:setup] Backfilling ${s} \u203A ${p}.${d}...`);try{let y=ue(u)?u[p]:void 0;await U(y,d)?.(f)}catch(y){o(`[corsair:setup] ${s} \u203A ${p}.${d} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Vr(e){if(!w(e).database)throw new Error("A database must be configured to provision Corsair integrations");await Tn(e,{silent:!0})}async function we(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to provision Corsair for connect");await vn(t,n)}var ts=Symbol.for("corsair:internal"),rs=new Set(["access_token","refresh_token","expires_at","scope"]);function os(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function is(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!_e(t)&&!rs.has(t)):n.filter(t=>!_e(t))}function Yr(e){return{plugins:e.plugins,database:e.database,kek:e.kek,multiTenancy:!1}}function Qr(e){return{[ts]:Yr(e)}}async function An(e,n,t={}){let r=pn(e.hub),o=[],i=t.pluginIds?new Set(t.pluginIds):null,a=Yr(e),s=Qr(e);for(let c of e.plugins){if(i&&!i.has(c.id))continue;let l=I(c);if(!l)continue;let u=os(l),p=t.providerNameOverrides?.[c.id]??le(c.id),g=await De(a,c,n),d=un(c,l),f=is(l,d),y={plugin:c.id,providerName:p,authKind:u,alreadyConfigured:g?.connected??!1};if(f.length>0&&(y.credentialFields=f),u==="oauth"){let h=t.oauthModeOverrides?.[c.id]??(l==="managed"?"managed":"byo");if(y.oauthMode=h,!t.skipOAuthUrlGeneration&&h!=="managed")try{let v=await lt(s,c.id,{tenantId:n,redirectUri:r,hubConnect:!0});y.oauthUrl=v.url}catch(v){y.setupError=v instanceof Error?v.message:`Could not prepare OAuth for ${c.id}`}}o.push(y)}return o}async function Sc(e,n,t={}){let r=w(e),o=r.hub;if(!o)throw new Error("Hub is not configured");return An({plugins:r.plugins,database:r.database,kek:r.kek,hub:o},n,t)}async function dt(e,n){if(!e.database)throw new Error("A database must be configured to provision Corsair for connect");await we(Qr(e),n)}async function Rc(e,n){await we(e,n)}async function Xr(e,n){let t=Re(e.projectApiKey),r={tenantId:n.tenantId,plugins:n.plugins};return t==="development"&&(r.deliveryUrl=Ee({deliveryUrl:n.deliveryUrl})),pe({hub:e,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:gn})}async function pt(e,n){let t={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await dt(t,n.tenantId);let r=await An(t,n.tenantId,{pluginIds:[n.plugin.id]});if(r.length===0)throw new Error(`Plugin '${n.plugin.id}' is not configured on this Corsair instance`);return Xr(e,{tenantId:n.tenantId,plugins:r,deliveryUrl:n.deliveryUrl})}async function xn(e,n){let t=w(e),r=J(e),o={plugins:t.plugins,database:t.database,kek:t.kek,hub:r};await dt(o,n.tenantId);let i=n.plugin?[n.plugin]:void 0,a=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,s=n.plugin&&n.providerName?{[n.plugin]:n.providerName}:void 0,c=await An(o,n.tenantId,{pluginIds:i,oauthModeOverrides:a,providerNameOverrides:s});if(c.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is not configured on this Corsair instance`:"No plugins are configured on this Corsair instance");return Xr(r,{tenantId:n.tenantId,plugins:c,deliveryUrl:n.deliveryUrl})}function eo(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function ss(e,n){return n&&!n.has(e.id)?!1:I(e)!==null}async function no(e,n,t={}){let r=w(e),o=n.trim()||"default",i=t.pluginIds?.length?new Set(t.pluginIds):null,a=await Je(r,o,{pluginIds:t.pluginIds}),s=new Map(a.map(l=>[l.plugin,l])),c=r.plugins.filter(l=>ss(l,i)).map(l=>{let u=I(l),p=s.get(l.id);return p?{plugin:l.id,providerName:le(l.id),authKind:eo(u),status:p.status,connected:p.connected,fields:p.fields.map(g=>({name:g.name,level:g.level,required:g.required,configured:g.configured})),missingRequiredFields:p.missingRequiredFields}:{plugin:l.id,providerName:le(l.id),authKind:eo(u),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:o,plugins:c}}async function to(e,n){let t=J(e);return Hr({hub:t,path:`/projects/${encodeURIComponent(n.projectId)}/connections`,notFoundMessage:"Hub REST API not found at /projects/:id/connections. Check HUB_API_URL and ensure the Hub API is deployed.",parseResponse:fn})}import*as ze from"crypto";function fe(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function gt(e,{maxAgeMs:n}={}){try{let t=e.includes(".")?e.split(".")[0]:e,r=JSON.parse(Buffer.from(t,"base64url").toString("utf-8"));if(r!==null&&typeof r=="object"&&"plugin"in r&&"tenantId"in r&&typeof r.plugin=="string"&&typeof r.tenantId=="string"){let o=r;return n!==void 0&&typeof o.iat=="number"&&Date.now()-o.iat>n?null:o}return null}catch{return null}}function Oe(e,n){let t=ze.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var ft=600*1e3;function In(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),o=e.slice(t+1),i=ze.createHmac("sha256",n).update(r).digest("base64url"),a=Buffer.from(o,"base64url"),s=Buffer.from(i,"base64url");return a.length!==s.length||!ze.timingSafeEqual(a,s)?null:gt(r,{maxAgeMs:ft})}function Me(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}import*as ro from"querystring";function ve(e){let{oauthConfig:n,clientId:t,redirectUri:r,state:o}=e,i={...n.authParams,client_id:t,redirect_uri:r,response_type:"code",scope:n.scopes.join(" "),state:o};return`${n.authUrl}?${ro.stringify(i)}`}var j=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function as(e){let n=e.oauthConfig;if(!n)throw new j("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function yt(e,n){let t=w(e,()=>new j("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new j("no_database","No database configured on corsair instance");let r=t.manual?.redirectUri;if(!r)throw new j("no_redirect_uri","No redirectUri configured. Set manual.redirectUri in createCorsair().");let o=In(n,t.kek);if(!o)throw new j("invalid_state","Invalid or tampered state parameter");let{plugin:i,tenantId:a}=o,s=H(t,i,g=>new j("plugin_not_found",g)),c=as(s),u=await S({authType:"oauth_2",integrationName:i,kek:t.kek,database:t.database}).get_client_id();if(!u)throw new j("client_id_not_configured",`client_id not configured for '${i}'`);let p=ve({oauthConfig:c,clientId:u,redirectUri:r,state:n});return{plugin:i,tenantId:a,providerName:c.providerName,oauthUrl:p,state:n}}import{randomBytes as us}from"crypto";import{v4 as ls}from"uuid";async function Sn(e,n){let t=Re(e.projectApiKey),r={permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,expiresAt:n.expiresAt};return t==="development"&&(r.deliveryUrl=Ee({deliveryUrl:n.deliveryUrl})),pe({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:yn})}function Rn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var mt="Permission approval required. Set manual.approvalBaseUrl (or use hub for hosted approval) so an approval URL can be generated. Optionally set manual.onApprovalRequired to customize the agent message.";function kt(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function oo(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function ht(e){return Rn(e)}async function bt(e,n){if(kt(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?oo(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await Sn(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:cs(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function cs(e){try{return JSON.parse(e)}catch{return e}}async function En(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await bt(e,n);return{...n,approvalUrl:r}}async function Ct(e){let{permissionsOptions:n,manual:t,hub:r,permissionId:o,permissionToken:i,plugin:a,endpoint:s,args:c,tenantId:l,expiresAt:u,operationPath:p}=e;if(n?.formatAsyncMessage)return n.formatAsyncMessage({token:i,id:o,plugin:a,endpoint:s,args:c});let d=await bt({manual:t,hub:r},{id:o,token:i,plugin:a,endpoint:s,args:JSON.stringify(c),tenant_id:l,expires_at:u});return kt(t)?d?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:d}):ht(d):mt:r?d?ht(d):`Action '${p}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:mt}var ds={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 ps(e,n,t){return t!==void 0?t:ds[n][e]}function wt(e){let n=/(\d+)(d|h|m|s)/g,t=0,r;for(;(r=n.exec(e))!==null;){let o=parseInt(r[1],10);switch(r[2]){case"d":t+=o*864e5;break;case"h":t+=o*36e5;break;case"m":t+=o*6e4;break;case"s":t+=o*1e3;break}}return t>0?t:600*1e3}function so(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 io(e,n,t){let r=Date.now()+t;for(;Date.now()<r;){let o=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!o)return{result:"blocked",reason:"pending"};if(o.status==="approved")return{result:"allow",onComplete:async()=>{await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",n).execute()}};if(o.status==="denied")return{result:"blocked",reason:"denied"};if(o.status==="expired"||o.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(i=>setTimeout(i,500))}return{result:"blocked",reason:"timeout"}}async function ao(e){let n=ps(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 o=JSON.stringify(e.args),i=new Date().toISOString(),a=e.tenantId??"default",s=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",o).where("tenant_id","=",a).where("expires_at",">",i).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(s){if(s.status==="approved"){let f=e.db,y=s.id;return{result:"allow",onComplete:async()=>{await f.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",y).execute()}}}return s.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
8
- Action: ${r}`,`
9
- Permission ID: ${s.id}`,`
10
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?io(e.db,s.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:s.id,token:s.token,expiresAt:s.expires_at})}let c=ls(),l=us(32).toString("hex"),u=e.timeoutMs??600*1e3,p=new Date(Date.now()+u).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:c,created_at:new Date,updated_at:new Date,token:l,plugin:e.pluginId,endpoint:e.endpointPath,args:o,tenant_id:a,status:"pending",expires_at:p}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
11
- Action: ${r}`,`
12
- Permission ID: ${c}`,`
13
- Permission token: ${l}`,`
14
- Expires at: ${p}`,`
15
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?io(e.db,c,u):{result:"blocked",reason:"pending",id:c,token:l,expiresAt:p}}var A=class extends Error{status;code;extra;constructor(n,t,r,o={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=o}};function R(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function co(e){let n={error:e.code,message:e.message,...e.extra};return R(e.status,n)}function ye(e){return new A(404,"not_found",e)}function ie(e,n={}){return new A(400,"bad_request",e,n)}function uo(e,n){return H(e,n,t=>ye(t))}async function lo(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=S({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),o=O[t].integration,i=r,a;try{a=await Promise.all(o.map(l=>i[`get_${l}`]()))}catch{a=o.map(()=>null)}let s=o.filter((l,u)=>a[u]==null),c;return t==="oauth_2"?c=!s.includes("client_id")&&!s.includes("client_secret"):c=s.length===0,{configured:c,missingFields:s}}async function po(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:o,missingFields:i}=await lo(e,n);return{id:e.id,authType:t,configured:o,missingFields:i,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function _n(){return{ok:!0}}async function He(e){return Promise.all(e.plugins.map(n=>po(n,e)))}async function Dn(e,n){let t=uo(e,n);return po(t,e)}async function gs(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 go(e,n){let t=await gs(e,n),r=t.filter(o=>o.hasCredentials).map(o=>o.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function Fe(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let o=r.tenant_id;if(!o)continue;let i=n.get(o);i||(i={id:o,accounts:[],connectedPlugins:[]},n.set(o,i));let a=!!r.dek;i.accounts.push({integrationName:r.integrationName,hasCredentials:a}),a&&i.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function On(e,n){if(!n)throw ie("Tenant id must be a non-empty string");return go(e,n)}async function Mn(e,n){let t=n?.id?.trim();if(!t)throw ie("Tenant id is required",{missingFields:["id"]});return go(e,t)}async function Hn(e,n){let t=n?.trim()||"default",r={},o=await Je(e,t);for(let i of o)r[i.plugin]=wn(i);for(let i of e.plugins)i.id in r||(!i.options?.authType||!e.database||!e.kek?r[i.id]="missing_credentials":r[i.id]="not_connected");return r}async function vt(e,n){if(!e.database)throw ye(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ye(`Permission '${n}' not found`);return En(e,t)}function fs(e){if(!e.oauthConfig)throw ie(`Plugin '${e.id}' has no oauthConfig`)}function ys(e){if(!e.manual)throw new A(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function Pt(e){let n=ys(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new A(500,"connect_not_configured","Manual connect requires manual.baseUrl and manual.redirectUri. Use hub for hosted connect, or set both URLs for manual OAuth.");return n}function ms(e){let n=!!e.hub,t=Me(e.manual);if(!n&&!t)throw new A(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function fo(e){if(!e.database||!e.kek)throw new A(500,"database_not_configured","A database and kek are required to issue connect links.")}async function hs(e,n){let t=n?.plugin?.trim();if(!t)throw ie("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",o=uo(e,t);fs(o);let i=Pt(e);fo(e);let a=await lo(o,e);if(!a.configured)throw new A(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:a.missingFields});let s=Oe(fe(t,r),e.kek),c;try{c=new URL(i.baseUrl)}catch{throw new A(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return c.searchParams.set("state",s),{connectUrl:c.toString(),expiresAt:new Date(Date.now()+ft).toISOString()}}async function ks(e,n,t){fo(n);let o={tenantId:t.tenantId?.trim()||"default",oauthMode:t.oauthMode},i=t.plugin?.trim();i&&(o.plugin=i);let a=t.providerName?.trim();a&&(o.providerName=a);let s=await xn(e,o);return{connectUrl:s.connectUrl,expiresAt:s.expiresAt}}async function Fn(e,n,t){return ms(n),n.hub?ks(e,n,t):hs(n,t)}async function Un(e,n,t){if(n.hub&&!Me(n.manual))throw new A(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw ie("state is required",{missingFields:["state"]});Pt(n);try{return await yt(e,r)}catch(o){if(o instanceof j)switch(o.code){case"invalid_state":throw ie("Invalid or expired state");case"client_id_not_configured":throw new A(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new A(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function Bn(e,n,t){if(n.hub&&!Me(n.manual))throw new A(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),o=t?.state?.trim(),i=[];if(r||i.push("code"),o||i.push("state"),i.length)throw ie("Missing required fields",{missingFields:i});let a=Pt(n),{processOAuthCallback:s}=await import("./oauth.js");try{return await s(e,{code:r,state:o,redirectUri:a.redirectUri})}catch(c){if(c instanceof Error&&c.name==="OAuthCallbackError")switch(c.code){case"invalid_state":throw ie("Invalid or expired state");case"credentials_not_configured":throw new A(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new A(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function Tt(e,n){if(!e.database)throw ye("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ye("Permission not found");return En(e,t)}async function yo(e,n){return"id"in n?vt(e,n.id):Tt(e,n.token)}import{createCipheriv as As,createDecipheriv as Ru,randomBytes as Co,scryptSync as xs}from"crypto";import{createHmac as At,randomUUID as bs,timingSafeEqual as ko}from"crypto";var mo=new Set(["oauth.callback","oauth.tokens","webhook","permission.approve","permission.deny","auth.credentials","integration.credentials","connect.create_link","connections.sync"]),me=60*1e3,Pe=300*1e3;function bo(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Nn(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=At("sha256",e.signingSecret.trim()).update(n).digest("hex");return{body:n,headers:{"content-type":"application/json","x-corsair-signature":`sha256=${r}`,"x-corsair-timestamp":t,"x-corsair-project":e.projectId,"x-corsair-nonce":bs()}}}function xt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=bo(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>Pe)return!1;let i=At("sha256",n).update(e.body).digest("hex");try{return ko(Buffer.from(i,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function Ue(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)>Pe)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let i=At("sha256",n).update(e.body).digest("hex");try{if(!ko(Buffer.from(i,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function Ln(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function It(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function $n(e){let n=e.sync?.encrypted;return typeof n!="string"||!n.trim()?null:{encrypted:n.trim()}}function jn(e){return $n(Ln(e))}function Cs(e){let n=e;for(;n;){if(n instanceof Error){let t=n.code;if(typeof t=="string")return t;n=n.cause;continue}if(typeof n=="object"&&n!==null&&"code"in n){let t=n.code;if(typeof t=="string")return t}break}}function ho(e,n=200){let t=e.trim();return t.length<=n?t:`${t.slice(0,n)}\u2026`}var ws="Verify hub.signingSecret in your app matches the signing secret shown in Hub project settings.",vs="Check the delivery URL configured for this environment.";function Ps(e){return`${e.ack.error?`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`:`App rejected the signed delivery (HTTP ${e.status} from ${e.deliveryUrl})`}. ${ws}`}function Ts(e){return`${e.ack.error?`${e.ack.error} (HTTP 404 from ${e.deliveryUrl})`:`Delivery endpoint not found at ${e.deliveryUrl} (HTTP 404)`}. ${vs}`}function Ve(e,n){let t=Cs(n),r=n instanceof Error?n.message:"Delivery request failed",o;switch(t){case"ECONNREFUSED":o="connection refused \u2014 nothing accepted a TCP connection on that host and port";break;case"ENOTFOUND":o="host not found \u2014 DNS could not resolve the hostname";break;case"ETIMEDOUT":case"UND_ERR_CONNECT_TIMEOUT":o="connection timed out before the app responded";break;case"ECONNRESET":o="connection reset while talking to the app";break;case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":o=`TLS certificate error (${t})`;break;default:o=r==="fetch failed"&&t?`${r} (${t})`:r}return[`Could not reach ${e}`,o].join(". ")}function St(e){if(e.status===0)return e.ack.error?e.ack.error:e.body.startsWith("Could not reach")?e.body:Ve(e.deliveryUrl,new Error(e.body||"Delivery request failed"));if(e.status===401||e.status===403)return Ps(e);if(e.status===404)return Ts(e);if(e.ack.error)return`${e.ack.error} (HTTP ${e.status} from ${e.deliveryUrl})`;if(e.status>=500){let t=e.body.trim();return t?`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl}): ${ho(t)}`:`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl})`}let n=e.body.trim();return n?`${ho(n)} (HTTP ${e.status} from ${e.deliveryUrl})`:`Delivery failed with HTTP ${e.status} from ${e.deliveryUrl}`}async function Rt(e){let{body:n,headers:t}=Nn(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),o=await r.text();return{ok:r.ok,status:r.status,body:o}}catch(r){return{ok:!1,status:0,body:Ve(e.deliveryUrl,r)}}}var Is="aes-256-gcm",Ss=12,Rs=16,Es=16,_s=32;function Ds(e,n){return xs(e.trim(),n,_s)}function Et(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required to encrypt sync manifest");let r=Co(Es),o=Ds(t,r),i=Co(Ss),a=As(Is,o,i,{authTagLength:Rs}),s=JSON.stringify(e),c=Buffer.concat([a.update(s,"utf8"),a.final()]),l=a.getAuthTag();return[r.toString("base64"),i.toString("base64"),l.toString("base64"),c.toString("base64")].join(":")}var Os=["invalid corsair instance","a database must be configured to sync connections from the app","a database must be configured on the corsair instance","signing secret is required to encrypt sync manifest"];function _t(e){if(e instanceof vr)return!1;if(!(e instanceof Error))return!0;let n=e.message.toLowerCase();return!Os.some(t=>n.includes(t))}async function Ye(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to sync connections from the app");await Tn(e,{silent:!0});let[r,o]=await Promise.all([Fe(t),He(t)]),i={tenants:r.map(a=>({id:a.id})),plugins:o.map(a=>({id:a.id,authType:a.authType,configured:a.configured,missingFields:a.missingFields})),syncedAt:new Date().toISOString()};return Et(i,n)}var Ms=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Dt(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Ms.has(n)}catch{return!1}}function Ot(e){return e==="development"?"browser":"server"}function wo(e){return Ot(e)==="browser"}function vo(e){return Dt(e)?"Production delivery URL must be a public URL, not localhost":null}async function Po(e,n){let t=n.tenantId.trim();if(!t)throw new Error("tenantId is required");let r=n.plugins.map(a=>a.trim()).filter(Boolean);if(r.length===0)throw new Error("At least one plugin is required");let o=w(e);if(!o.hub)throw new Error("Hub is not configured on this Corsair instance");if(!o.database)throw new Error("Database not configured");let i=await Hs(o.hub,{plugins:o.plugins,database:o.database,kek:o.kek},{tenantId:t,pluginIds:r});return{connectUrl:i.connectUrl,expiresAt:i.expiresAt}}async function Hs(e,n,t){let{buildConnectPluginManifestFromContext:r,ensureConnectAccountRowsFromContext:o}=await import("./setup-introspect-U3GFH2A4.js"),{postHubConnectSession:i}=await import("./connect-HAVE4UFR.js"),a={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await o(a,t.tenantId);let s=await r(a,t.tenantId,{pluginIds:t.pluginIds});if(s.length===0)throw new Error("No connectable plugins found for this tenant");let c=s.find(l=>l.setupError);if(c)throw new Error(c.setupError??`Could not prepare connect link for ${c.plugin}`);return i(e,{tenantId:t.tenantId,plugins:s})}var z=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function Wn(e,n){let t=w(e,()=>new z("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new z("no_database","Database not configured");let r=H(t,n.plugin,u=>new z("plugin_not_found",u)),o=I(r);if(!o)throw new z("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(o==="oauth_2"||o==="managed")throw new z("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await we(e,n.tenantId);let i=new Set(un(r,o)),s=r.authConfig?.[o]?.account??[],c=_({authType:o,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:s}),l=0;for(let[u,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(u))throw new z("invalid_credentials",`Unknown credential field '${u}' for plugin '${n.plugin}'`);let g=U(c,`set_${u}`);if(!g)throw new z("invalid_credentials",`Cannot set credential field '${u}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new z("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var V=class extends Error{code;constructor(n,t){super(t),this.name="IntegrationCredentialsDeliveryError",this.code=n}};async function Mt(e,n){let t=w(e,()=>new V("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new V("no_database","Database not configured");let r=H(t,n.plugin,u=>new V("plugin_not_found",u)),o=I(r);if(!o)throw new V("invalid_credentials",`Plugin '${r.id}' has no authType configured`);await Vr(e);let i=new Set(Ar(r,o)),s=r.authConfig?.[o]?.integration??[],c=S({authType:o,integrationName:n.plugin,kek:t.kek,database:t.database,extraIntegrationFields:s}),l=0;for(let[u,p]of Object.entries(n.credentials)){if(!p.trim())continue;if(!i.has(u))throw new V("invalid_credentials",`Unknown integration credential field '${u}' for plugin '${n.plugin}'`);let g=U(c,`set_${u}`);if(!g)throw new V("invalid_credentials",`Cannot set integration field '${u}' for plugin '${n.plugin}'`);await g(p.trim()),l+=1}if(l===0)throw new V("invalid_credentials","Provide at least one integration credential field to save");return{plugin:n.plugin}}var Kn=new Map;function Fs(e){for(let[n,t]of Kn)t<=e&&Kn.delete(n)}function qn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return Fs(r),Kn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(Kn.set(t,r+n),{ok:!0})}async function Zn(e,n,t){for(let r of e){if(r.id!==n)continue;let o=r.oauthWebhookTenantLinkResolver;return o?o(t):null}return null}var To=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function Us(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 Bs(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 $(n.dek,e.kek),r=To(n.config),o={};Object.keys(r).length>0&&(o=oe(r,t)),o[e.link.linkType]=e.link.externalId;let i=ge(o,t);await e.database.db.updateTable("corsair_accounts").set({config:i,updated_at:new Date}).where("id","=",n.id).execute()}async function Be(e){let{database:n,kek:t,pluginId:r,tenantId:o,link:i,authType:a,extraAccountFields:s=[]}=e,{accountId:c}=await Us({database:n,pluginId:r,tenantId:o}),l=!1;if(a){let u=_({authType:a,integrationName:r,tenantId:o,kek:t,database:n,extraAccountFields:s}),p=`set_${i.linkType}`,g=u[p];typeof g=="function"&&(await g(i.externalId),l=!0)}l||await Bs({database:n,kek:t,accountId:c,link:i})}async function Ht(e){let{database:n,kek:t,pluginId:r,linkType:o,externalId:i}=e,a=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let s of a)if(s.dek)try{let c=await $(s.dek,t),u=To(s.config)[o];if(!u)continue;if(Ze(u,c)===i)return s}catch{continue}return null}async function Gn(e){return(await Ht(e))?.tenant_id??null}async function Ao(e){return Gn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var he=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Ne(e,n){let{plugin:t,tenantId:r,accessToken:o,refreshToken:i,expiresIn:a,scope:s}=n;if(!o.trim())throw new he("no_access_token","Managed OAuth delivery missing access_token");let c=w(e,()=>new he("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new he("no_database","No database configured on corsair instance");let l=H(c,t,p=>new he("plugin_not_found",p));await we(e,r);let u=_({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await u.set_access_token(o),i&&await u.set_refresh_token(i),a&&await u.set_expires_at(String(Math.floor(Date.now()/1e3)+a)),s&&await u.set_scope(s);try{let p=await Zn(c.plugins,t,{access_token:o,refresh_token:i,scope:s});if(p)try{let g=l.authConfig?.managed?.account??[];await Be({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:p,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(p){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,p)}return{plugin:t,tenantId:r}}function Ns(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function xo(e,n,t=[]){for(let[r,o]of Object.entries(e))if(Ns(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=xo(o,n,[...t,r]);if(i)return i}return null}function Ls(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function $s(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 Io(e,n,t,r){let o=Ls(n),i=typeof t=="string"?JSON.parse(t):t;(!i||typeof i=="object"&&Object.keys(i).length===0)&&o["x-goog-resource-uri"]&&(i=$s(o)||i);let s={headers:o,body:i,...r?{query:r}:{}},c=r?.tenantId||"default",l=e.withTenant?e.withTenant(c):e,u=ln;for(let p of u){let g=l[p];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(s))continue;let d=xo(g.webhooks,s);if(!d)continue;let f=d.path.join("."),y={payload:i,headers:o,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let m=await d.webhook.handler(y),h=!!Object.keys(m.returnToSender||{})?.length;return{plugin:p,action:f,body:i,response:h?{...m?.returnToSender,success:!0}:{success:!0},...m.responseHeaders&&{responseHeaders:m.responseHeaders}}}catch(m){return console.error(`Error executing webhook handler for ${p}.${f}:`,m),{plugin:p,action:f,body:i,response:{success:!1,error:m instanceof Error?m.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{randomBytes as qs}from"crypto";import{createHmac as js,randomBytes as Ws,timingSafeEqual as Ks}from"crypto";function se(){return Ws(16).toString("base64url")}function Qe(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return js("sha256",t).update(e).digest("base64url")}function Y(e,n){let t=n.trim();if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[o,i]=r;if(!o||!i)return null;let a=Qe(o,t);try{if(!Ks(Buffer.from(i,"utf8"),Buffer.from(a,"utf8")))return null}catch{return null}let s;try{s=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{return null}return s.exp*1e3<Date.now()?null:s}function Jn(e,n,t){let r=Math.floor(Date.now()/1e3),o={...e,iat:r,exp:t},i=Buffer.from(JSON.stringify(o)).toString("base64url"),a=Qe(i,n);return`${i}.${a}`}function Xe(e,n,t){let r=Math.floor(Date.now()/1e3);return Jn(e,n,r+Math.floor(t/1e3))}function Te(e){return decodeURIComponent(e)}function Ft(e){return encodeURIComponent(e)}function So(e){let n=e.trim();return n.length>0?n:null}function zn(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Vn(e,n){if(!So(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??qs(16).toString("base64url"),iat:t,exp:t+Math.floor(me/1e3)},o=Buffer.from(JSON.stringify(r)).toString("base64url"),i=Qe(o,n);return`${o}.${i}`}function ke(e,n){return So(n)?Y(e,n):null}function Ae(e){return e.deliveryMode==="auth.credentials"}function en(e){return e.deliveryMode==="connections.sync"}function nn(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function tn(e){return e.deliveryMode==="oauth.tokens"}function Yn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!Ae(e)&&!en(e)&&!nn(e)&&!tn(e)}async function Zs(e,n){try{return{status:"ok",webhookResponse:{status:200,body:{status:"ok",sync:{encrypted:await Ye(e,n)}}}}}catch(t){return{status:"failed",retryable:_t(t),error:t instanceof Error?t.message:"Connections sync delivery failed"}}}async function Gs(e,n){try{return{status:"ok",connectLink:await Po(e,n)}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Connect link delivery failed"}}}function Ut(e,n){if(e instanceof Headers)return e.get(n)??void 0;let t=e[n]??e[n.toLowerCase()];return Array.isArray(t)?t[0]:typeof t=="string"?t:void 0}async function Js(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 Gn({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function zs(e,n,t){let r=await Js(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await Io(e,t.headers,t.body,o);if(!i.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(i.response&&i.response.success===!1)return{status:"failed",retryable:!1,error:typeof i.response.error=="string"?i.response.error:"Webhook handler failed"};let a=i.response?.returnToSender,s=a&&typeof a=="object"&&typeof a.validationToken=="string"&&Object.keys(a).length===1?a.validationToken:a||(i.response?.data??i.response);return{status:"ok",webhookResponse:{status:i.response?.statusCode??200,body:s,headers:i.responseHeaders}}}async function Vs(e,n){return await rn(e,n),{status:"ok"}}async function Ys(e,n){return await Ne(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function Nt(e,n,t){let r=await Bt(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function Bt(e,n,t){let r=w(e),o=n.token?.trim();if(!o)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let i=new Date().toISOString(),a=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",o).executeTakeFirst();return a?a.status!=="pending"?{status:"ok"}:a.expires_at<i?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",a.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",a.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Qs(e,n){try{return await Wn(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function Xs(e,n){try{return await Mt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Integration credential delivery failed"}}}async function Lt(e,n,t={}){let r=w(e),o=Ut(n.headers,"x-corsair-signature"),i=Ut(n.headers,"x-corsair-timestamp"),a=Ut(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let c=Ue({body:n.body,signatureHeader:o,timestampHeader:i,signingSecret:t.signingSecret});if(!c.ok)return{status:"failed",retryable:!1,error:c.error};if(!a?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let l=qn(`nonce:${a.trim()}`,Pe);if(!l.ok)return{status:"failed",retryable:!1,error:l.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}if(s.type==="connect.status")return{status:"failed",retryable:!1,error:"connect.status is deprecated; use connections.sync signed delivery instead"};switch(s.type){case"webhook":return zs(e,r,s.payload);case"oauth.callback":return Vs(e,s.payload);case"oauth.tokens":return Ys(e,s.payload);case"permission.approve":return Bt(e,s.payload,"approved");case"permission.deny":return Bt(e,s.payload,"denied");case"auth.credentials":return Qs(e,s.payload);case"integration.credentials":return Xs(e,s.payload);case"connect.create_link":return Gs(e,s.payload);case"connections.sync":{let c=t.signingSecret?.trim();return c?Zs(e,c):{status:"failed",retryable:!1,error:"Tunnel signing secret is required for connections.sync"}}default:return ea(String(s.type))}}function ea(e){return mo.has(e)?{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}:{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}}var na="corsair:client-bridge";function Qn(e){let n=JSON.stringify({type:na,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 ta=[".corsair.dev"];function ra(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function oa(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:ra(n)?!0:ta.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Ro(e){return!e||!oa(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 Eo(e,n){if(!n)return e;let t=new Headers(e.headers);for(let[r,o]of Object.entries(n))t.set(r,o);return new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function $t(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 jt(e,n){let t=J(e),o=new URL(n).searchParams.get("d");if(!o)return{type:"json",status:200,body:{status:"ok",message:"Corsair tunnel endpoint is active",timestamp:new Date().toISOString()}};let i=ke(o,t.signingSecret);if(!i)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};let a=qn(`browser:${i.jti}`,me);if(!a.ok)return{type:"json",status:400,body:{error:a.error}};try{if(en(i)){if(!i.hubOrigin||!i.requestId)return{type:"json",status:400,body:{error:"Connections sync delivery requires hubOrigin and requestId for client bridge"}};let s=await Ye(e,t.signingSecret);return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:Qn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",sync:{encrypted:s}}})}}if(Ae(i))return i.hubSuccessUrl?i.credentials?(await Wn(e,{plugin:i.plugin,tenantId:i.tenantId,credentials:i.credentials}),{type:"redirect",url:$t(i.hubSuccessUrl,{connectedPlugin:i.plugin})}):{type:"redirect",url:$t(i.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(nn(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await Nt(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(tn(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Ne(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!Yn(i)||!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await rn(e,{code:i.code,state:i.state,redirectUri:i.redirectUri})}}catch(s){let c=s instanceof Error?s.message:"Hub delivery failed";return en(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Qn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:Ae(i)&&i.hubSuccessUrl?{type:"redirect",url:$t(i.hubSuccessUrl,{error:c})}:Ae(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Qn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:c})}:{type:"json",status:400,body:{error:c}}}return{type:"redirect",url:i.hubSuccessUrl}}async function Wt(e,n){let t=J(e),r=await Lt(e,n,{signingSecret:t.signingSecret});if(r.status!=="ok")return{type:"json",status:r.retryable===!1?400:502,body:{error:r.error??"Tunnel processing failed"}};let o=r.webhookResponse;if(r.connectLink)return{type:"json",status:200,body:{status:"ok",connectUrl:r.connectLink.connectUrl,expiresAt:r.connectLink.expiresAt}};if(!o)return{type:"json",status:200,body:{status:"ok"}};let i=o.status??200,a=o.headers;return o.body&&typeof o.body=="object"&&!(o.body instanceof ArrayBuffer)?{type:"json",status:i,body:o.body,headers:a}:{type:"text",status:i,body:typeof o.body=="string"?o.body:o.body?JSON.stringify(o.body):null,headers:a}}function Kt(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 qt(e,n){return n.method==="GET"?jt(e,n.url):Wt(e,{headers:n.headers,body:n.body??""})}async function Zt(e,n){try{let t=await qt(e,n);return Kt(t)}catch(t){if(t instanceof de)return Response.json({error:t.message},{status:503});throw t}}async function xe(e,n){let t=n.method.toUpperCase(),r=Ro(n.headers.get("origin"));if(t==="OPTIONS")return r?new Response(null,{status:204,headers:r}):Response.json({error:"Method not allowed"},{status:405});if(t!=="GET"&&t!=="POST")return Response.json({error:"Method not allowed"},{status:405});let o=await Zt(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0});return Eo(o,r)}var Q=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 _o=300;async function Gt(e,n){let{keys:t,hub:r,plugin:o,tenantId:i}=e,a=n?.forceRefresh??!1,[s,c,l]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!s&&!l)throw new Q(o,"managed");let u=Math.floor(Date.now()/1e3);if(!a&&s&&c&&Number(c)>u+_o)return{accessToken:s,expiresAt:Number(c),refreshed:!1};if(!l&&s&&!a){let d=c?Number(c):null;if(d===null||d>u+_o)return{accessToken:s,expiresAt:d??u+3600,refreshed:!1}}let p=await sa(r,o,i),g=p.expires_in?u+p.expires_in:c?Number(c):u+3600;return await t.set_access_token(p.access_token),await t.set_expires_at(String(g)),p.refresh_token&&await t.set_refresh_token(p.refresh_token),p.scope&&await t.set_scope(p.scope),{accessToken:p.access_token,expiresAt:g,refreshed:!0}}function ia(e){return e.includes("Managed OAuth connection not found")||e.includes("Managed OAuth connection has no tokens")}async function sa(e,n,t){try{return await pe({hub:e,path:"/oauth/refresh",body:{plugin:n,tenantId:t},parseResponse:mn})}catch(r){let o=r instanceof Error?r.message:"";throw ia(o)?new Q(n,"managed"):r}}async function Do(e,n){e._refreshAuth=async()=>(await Gt(n,{forceRefresh:!0})).accessToken}function aa(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType,status:e.status,connected:e.connected,verified:e.verified,missingFields:e.missingFields}}async function ca(e){if(!e.hub||!e.database||!e.kek)return;let n={database:e.database,kek:e.kek,plugins:e.plugins};if(!I(e.plugin))return;let r=e.tenantId?.trim()||"default",o=await De(n,e.plugin,r);o&&Oo(e.hub,aa({tenantId:r,plugin:e.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:e.verified??o.connected,missingFields:o.missingRequiredFields}))}function Oo(e,n){pe({hub:e,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}function on(e){ca(e).catch(()=>{})}function Mo(e){return{delivery:n=>xe(e,n),deliveryOptions:n=>xe(e,n)}}var Ho=1200*1e3;function Jt(){return se()}function zt(){return Ho}function Vt(e,n){return Xe(e,n,Ho)}function Yt(e,n){return Y(e,n)}function Qt(e){return Te(e)}var Fo=600*1e3;function Xt(){return se()}function er(){return Fo}function nr(e,n){return Xe(e,n,Fo)}function tr(e,n){return Y(e,n)}function rr(e){return Ft(e)}function or(e){return Te(e)}function ir(){return se()}function sr(e,n,t){return Jn(e,n,Math.floor(t.getTime()/1e3))}function ar(e,n){return Y(e,n)}function cr(e){return Te(e)}function Xn(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(o,i){let a=t.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${t.join(" and ")} ${a?"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 ${qe}`)}})}async function ua(e){let n=!1;for(;;){let t=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.integrationName).executeTakeFirst();if(!t){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Integration "${e.integrationName}" not found. Make sure to create the integration first.`)}let r=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",t.id).executeTakeFirst();if(!r){if(!n&&e.ensureProvisioned){n=!0,await e.ensureProvisioned();continue}throw new Error(`Account not found for tenant "${e.tenantId}" and integration "${e.integrationName}". Make sure to create the account first.`)}return{integrationId:t.id,accountId:r.id,integration:{id:t.id,config:t.config,dek:t.dek??null},account:{id:r.id,config:r.config,dek:r.dek??null}}}}async function Uo(e){let{integrationId:n,accountId:t}=await ua(e);return{integrationId:n,accountId:t}}function ur(e,n){return`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${n}`}async function la(e,n){let t=e.hub;if(!t||!n.database||!n.kek)return null;try{return(await pt(t,{tenantId:n.tenantId,plugin:n.plugin,database:n.database,kek:n.kek,plugins:n.plugins})).connectUrl}catch{return null}}async function da(e){let n=e.hub;if(n&&e.database&&e.kek)try{let r=await pt(n,{tenantId:e.tenantId,plugin:e.plugin,database:e.database,kek:e.kek,plugins:e.plugins});return e.manual?.onAuthMissing?e.manual.onAuthMissing({plugin:e.pluginId,connectUrl:r.connectUrl,state:r.token}):ur(e.pluginId,r.connectUrl)}catch{return`[auth-missing:${e.pluginId}:${e.authType}] Authentication required. Could not create connect link. Check hub configuration and server logs.`}let t=await la({manual:e.manual,hub:e.hub},{plugin:e.plugin,tenantId:e.tenantId,database:e.database,kek:e.kek,plugins:e.plugins});return t?ur(e.pluginId,t):`[auth-missing:${e.pluginId}:${e.authType}]`}function pa(e,n,t){let r=Oe(fe(e,n.tenantId??t??"default"),n.kek),o=new URL(n.baseUrl);o.searchParams.set("state",r);let i=o.toString();return n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:i,state:r}):ur(e,i)}async function Bo(e){let n=e.tenantId??"default",t=e.error.pluginId;return e.manual&&Me(e.manual)&&e.manual.oauthConfig&&e.manual.kek&&e.error.authType==="oauth_2"?pa(t,{...e.manual,baseUrl:e.manual.baseUrl,kek:e.manual.kek},e.tenantId):e.hub&&e.plugin&&e.kek&&e.database&&e.plugins?da({manual:e.manual,hub:e.hub,plugin:e.plugin,pluginId:t,tenantId:n,authType:e.error.authType,database:e.database,kek:e.kek,plugins:e.plugins}):e.error.message}var ga=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function No(e,n,t,r,o){let i={pluginId:n,operation:t,input:r,originalError:e},a=Object.keys(o).find(l=>o[l]?.match(e,i));return await(o[a||"DEFAULT"]?.handler||ga)(e,i)}function fa(e){return typeof e=="function"}function lr({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:o,errorHandlers:i,currentPath:a=[],keyBuilder:s,permissionsConfig:c,endpointMeta:l,database:u,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:f,plugin:y,kek:m,allPlugins:h}){for(let[v,C]of Object.entries(e)){let E=n?.[v];if(fa(C)){let k=E,b=[...a,v].join("."),P=async(x={})=>{let X;if(c){let M=l?.[b],{result:cn,reason:Z,onComplete:We,token:ne,id:Ce,expiresAt:L}=await ao({pluginId:o,endpointPath:b,args:x,mode:c.mode,override:c.overrides?.[b],riskLevel:M?.riskLevel??"write",meta:M,db:u,timeoutMs:p?wt(p.timeout):void 0,tenantId:g,approvalMode:p?.mode});if(cn==="blocked"){let G;throw Z==="denied"?G=`Action '${b}' was denied by the user. Await further instructions before proceeding.`:Z==="policy"?G=`Action '${b}' is blocked by the permission policy. Update the corsair config to allow it.`:Z==="timeout"?G=`Action '${b}' timed out waiting for approval.`:ne&&Ce?G=await Ct({permissionsOptions:p,manual:d,hub:f,permissionId:Ce,permissionToken:ne,plugin:o,endpoint:b,args:x,tenantId:g??"default",expiresAt:L??new Date(Date.now()+(p?wt(p.timeout):600*1e3)).toISOString(),operationPath:b}):G=`Action '${b}' requires user approval before it can run.`,new Error(G)}X=We}let D=async(M,cn,Z)=>{try{return await C(cn,Z)}catch(We){if(We instanceof Error){let ne=await No(We,o,b,typeof Z=="object"&&Z!==null?Z:{args:Z},i);if(M<(ne.maxRetries||0)){let Ce=M+1;console.log(`Retrying (${Ce} / ${ne.maxRetries})...`);let L;if(ne.headersRetryAfterMs)L=ne.headersRetryAfterMs;else switch(ne.retryStrategy){case"exponential_backoff":L=Math.pow(2,Ce-1)*1e3;break;case"exponential_backoff_jitter":let G=Math.pow(2,Ce-1)*1e3,li=(Math.random()-.5)*1e3;L=Math.max(0,G+li);break;case"linear_1s":L=1e3;break;case"linear_2s":L=2e3;break;case"linear_3s":L=3e3;break;case"linear_4s":L=4e3;break;default:L=1e3;break}await new Promise(G=>setTimeout(G,L)),await D(Ce,cn,Z),console.log(`[corsair:${o}:${b}] Retry strategy:`,ne)}}throw We}},ce;try{ce=s?await s(t,"endpoint"):void 0}catch(M){if(M instanceof Q)return y&&f&&on({hub:f,database:u,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!1}),Bo({error:M,manual:d,hub:f,plugin:y,tenantId:g,database:u,kek:m,plugins:h});throw M}if(!k?.before&&!k?.after){let M=await D(0,{...t,key:ce},x);return await X?.(),y&&f&&on({hub:f,database:u,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!0}),M}let N={...t,key:ce},ee=k.before?await k.before(N,x):{ctx:N,args:x,continue:!0,passToAfter:void 0};if(ee.continue===!1)return;let je=await D(0,ee.ctx,ee.args);return await k.after?.(ee.ctx,je,ee.passToAfter),await X?.(),y&&f&&on({hub:f,database:u,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!0}),je};r[v]=P}else if(C&&typeof C=="object"){let k={};lr({endpoints:C,hooks:E,ctx:t,tree:k,pluginId:o,errorHandlers:i,currentPath:[...a,v],keyBuilder:s,permissionsConfig:c,endpointMeta:l,database:u,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:f,plugin:y,kek:m,allPlugins:h}),r[v]=k}}}function ya(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function dr({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:o}){for(let[i,a]of Object.entries(e)){let s=n?.[i];if(ya(a)){let c=s,l=async u=>{let p=(d,f)=>a.handler(d,f),g=o?await o(t,"webhook"):void 0;return!c?.before&&!c?.after?p({...t,key:g},u):(async()=>{let d={...t,key:g},f=c.before?await c.before(d,u):{ctx:d,args:u,continue:!0,passToAfter:void 0};if(f.continue===!1)return;let y=await p(f.ctx,f.args);return y?.success===!0&&await c.after?.(f.ctx,y,f.passToAfter),y})()};r[i]={match:a.match,handler:l}}else if(a&&typeof a=="object"){let c={};dr({webhooks:a,hooks:s,ctx:t,webhooksTree:c,keyBuilder:o}),r[i]=c}}}function ma(e,n,t,r){let o=null;return async()=>{if(o)return o;if(!e)throw new Error("Database not configured");let{accountId:i}=await Uo({database:e,integrationName:n,tenantId:t,ensureProvisioned:r});return o=i,o}}function ha(e,n,t,r,o){return e?ot(e.db,n,t,r,o):{findByEntityId:async()=>null,existsByEntityId:async()=>!1,findIdByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function pr(e,n){let{database:t,tenantId:r,kek:o,rootErrorHandlers:i,permissionsOptions:a,manualConfig:s,hubConfig:c,internalConfig:l}=n,u=l&&t?()=>vn(l,r??"default"):void 0,p={},g={};for(let d of e)p[d.id]={},g[d.id]={};for(let d of e){let f=d.schema,y=r??"default",m=ma(t,d.id,y,u);if(f?.entities){let N={};for(let[ee,je]of Object.entries(f.entities)){let M=t?ot(t.db,m,ee,f.version,je):ha(void 0,m,ee,f.version,je);N[ee]=M}g[d.id].db=N,p[d.id].db=N}let h=d.options,v=d.authConfig,C;if(t&&o&&h?.authType){let N=v?.[h.authType]?.account??[];C=_({authType:h.authType,integrationName:d.id,tenantId:y,kek:o,database:t,extraAccountFields:N,ensureProvisioned:u}),p[d.id].keys=C}let E={database:t,db:g[d.id]?.db??{},$getAccountId:m,...d.options?{options:d.options}:{},...C?{keys:C,authType:h?.authType}:{},tenantId:y,...c?{hub:c}:{}},k=d.endpoints??{},b=d.hooks,P={...i,...d.errorHandlers},x={},X=d.options?.permissions;lr({endpoints:k,hooks:b,ctx:E,tree:x,pluginId:d.id,errorHandlers:P,currentPath:[],keyBuilder:d.keyBuilder,permissionsConfig:X,endpointMeta:d.endpointMeta,database:t,permissionsOptions:a,tenantId:r,manualConfig:s?{...s,oauthConfig:d.oauthConfig,kek:o,tenantId:y}:void 0,hubConfig:c,plugin:d,kek:o,allPlugins:e}),Object.keys(x).length>0&&(p[d.id].api=x),E.endpoints=x;let D=d.webhooks??{},ce=d.webhookHooks;if(Object.keys(D).length>0){let N={};dr({webhooks:D,hooks:ce,ctx:E,webhooksTree:N,keyBuilder:d.keyBuilder}),p[d.id].webhooks=N,d.pluginWebhookMatcher&&(p[d.id].pluginWebhookMatcher=d.pluginWebhookMatcher),d.pluginTenantWebhookMatcher&&(p[d.id].pluginTenantWebhookMatcher=d.pluginTenantWebhookMatcher)}}return p}function Lo(e,n,t){let r={};for(let o of e){let i=o.options,a=o.authConfig;if(i?.authType){let s=a?.[i.authType]?.integration??[],c=S({authType:i.authType,integrationName:o.id,kek:t,database:n,extraIntegrationFields:s});r[o.id]=c}}return r}var ka="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function $o(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] ${ka}`),t):n}var jo=[{method:"GET",pattern:"/ok",handler:async()=>R(200,_n())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>R(200,await Fe(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>R(201,await Mn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>R(200,await On(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>R(200,await He(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>R(200,await Dn(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>R(200,await Hn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>R(200,await vt(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?R(200,await Tt(e,t)):R(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}},{method:"POST",pattern:"/connect/links",handler:async({corsair:e,internal:n,body:t})=>R(200,await Fn(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>R(200,await Un(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>R(200,await Bn(e,n,t))}];(()=>{let e=new Set;for(let n of jo){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function ba(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let o={};for(let i=0;i<t.length;i++){let a=t[i],s=r[i];if(a.startsWith(":"))o[a.slice(1)]=decodeURIComponent(s);else if(a!==s)return null}return o}function Ca(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 wa(e){if(!(e.method==="GET"||e.method==="HEAD"||!(e.headers.get("content-type")??"").includes("application/json")))try{let t=await e.text();return t?JSON.parse(t):void 0}catch{throw new A(400,"invalid_json","Request body is not valid JSON")}}var va="/api/corsair";function Ie(e,n={}){let t=n.basePath??va,r=w(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async o=>{try{let i=new URL(o.url),a=Ca(i.pathname,t),s=o.method.toUpperCase();if(s==="OPTIONS"||a==="/"||a==="")return await xe(e,o);if(s!=="GET"&&s!=="POST")return R(405,{error:"method_not_allowed",message:`Method ${s} not allowed`});let c=Object.fromEntries(i.searchParams);for(let l of jo){if(l.method!==s)continue;let u=ba(l.pattern,a);if(!u)continue;let p=await wa(o);return await l.handler({corsair:e,internal:r,req:o,params:u,query:c,body:p})}throw ye(`No route for ${s} ${a}`)}catch(i){if(n.onError){let s=await n.onError(i,o);if(s)return s}if(i instanceof A)return co(i);let a=i instanceof Error?i.message:"Internal server error";return R(500,{error:"internal_error",message:a})}}}function Pa(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,o=`${t}://${n}${r}`,i=new Headers;for(let[c,l]of Object.entries(e.headers))if(l!=null)if(Array.isArray(l))for(let u of l)i.append(c,u);else i.set(c,l);let a=e.method!=="GET"&&e.method!=="HEAD",s={method:e.method,headers:i};return a&&e.body!==void 0&&(s.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),i.has("content-type")||i.set("content-type","application/json")),new Request(o,s)}async function Ta(e,n){e.status(n.status),n.headers.forEach((r,o)=>e.setHeader(o,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function Wo(e,n){let t=Ie(e,n);return async(r,o,i)=>{try{let a=await t(Pa(r));await Ta(o,a)}catch(a){i(a)}}}function Ko(e,n){let t=Ie(e,n);return r=>t(r.req.raw)}function qo(e,n){let t=Ie(e,n);return{GET:t,POST:t,OPTIONS:t}}function Zo(e){let n={[sn]:e};return{ok:_n,tenants:{list:()=>Fe(e),create:t=>Mn(e,t),get:t=>On(e,t)},plugins:{list:()=>He(e),get:t=>Dn(e,t)},connectionStatus:{get:t=>Hn(e,t?.tenantId)},permissions:{get:t=>yo(e,t)},connect:{createLink:t=>Fn(n,e,t),resolve:t=>Un(n,e,t),oauthCallback:t=>Bn(n,e,t)}}}async function Go(e,n,t,r,o="pending"){if(!e)return null;try{let i=xr(),a=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:a,updated_at:a,account_id:n,event_type:t,payload:r,status:o}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function Aa(e,n,t,r="pending"){try{let o=await e.$getAccountId();return Go(e.database,o,n,t,r)}catch(o){return console.warn("Failed to log event:",o),null}}import*as Jo from"https";import*as zo from"querystring";function et(e,n,t,r,o){let i=new URL(r.tokenUrl),a=r.tokenAuthMethod==="basic";return new Promise((s,c)=>{let l={code:e.trim(),redirect_uri:o,grant_type:"authorization_code"};a||(l.client_id=n,l.client_secret=t);let u=zo.stringify(l),p={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(u).toString()};a&&(p.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=Jo.request({hostname:i.hostname,...i.port?{port:Number(i.port)}:{},path:i.pathname+i.search,method:"POST",headers:p},d=>{let f="";d.on("data",y=>{f+=y}),d.on("end",()=>{if(d.statusCode!==200){c(new Error(`Token exchange failed (${d.statusCode}): ${f}`));return}try{s(JSON.parse(f))}catch{c(new Error(`Token endpoint returned non-JSON response: ${f}`))}})});g.on("error",d=>c(new Error(`Request failed: ${d.message}`))),g.write(u),g.end()})}var Vo=" ";function K(e){let n=e;return n._def??n.def??{}}function q(e){let n=e.typeName;if(n)return n;let t=e.type;if(t)return`Zod${t.split("_").map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("")}`}function W(e){return e.innerType??e.schema??e.out??e.in}function Qo(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 W(e)}}function Xo(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function tt(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function Le(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 ei(e,n){return e.description??n.description}function xa(e){let n=e;for(;n;){let t=K(n),r=ei(n,t);if(r)return r;let o=q(t);if(hr(o)||o==="ZodPipe"||o==="ZodEffects"||o==="ZodTransform"){n=Qo(t,o);continue}break}}function hr(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function F(e){let n=K(e),t=q(n);switch(t){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"Date";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(n.value??Le(n)[0]??"unknown");case"ZodEnum":return Le(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=W(n);return r?F(r):"unknown"}case"ZodNullable":{let r=W(n);return`${r?F(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=W(n);return r?F(r):"unknown"}case"ZodArray":{let r=Xo(n);if(!r)return"unknown[]";let o=K(r),i=q(o)==="ZodUnion",a=F(r);return`${i?`(${a})`:a}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=tt(e,n),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([a,s])=>{let c=q(K(s));return`${c==="ZodOptional"||c==="ZodNullable"?a+"?":a}: ${F(s)}`}).join(", ")} }`}case"ZodUnion":return Le(n).map(r=>F(r)).join(" | ");case"ZodIntersection":return`${F(n.left)} & ${F(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=Qo(n,t);return r?F(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function ae(e){let n=K(e),t=q(n),r=ei(e,n);switch(t){case"ZodString":return{kind:"string",optional:!1,description:r};case"ZodNumber":return{kind:"number",optional:!1,description:r};case"ZodBoolean":return{kind:"boolean",optional:!1,description:r};case"ZodLiteral":{let o=n.value??Le(n)[0],i=typeof o=="string"||typeof o=="number"||typeof o=="boolean"?o:String(o??"");return{kind:"literal",optional:!1,description:r,value:i}}case"ZodEnum":{let o=Le(n).map(i=>String(i));return{kind:"string",optional:!1,description:r,enum:o}}case"ZodOptional":{let o=W(n),i=o?ae(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodNullable":{let o=W(n),i=o?ae(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodDefault":case"ZodCatch":{let o=W(n);return o?{...ae(o),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let o=Xo(n);return{kind:"array",optional:!1,description:r,items:o?ae(o):{kind:"unknown",optional:!1}}}case"ZodObject":{let o=tt(e,n),i={};for(let[a,s]of Object.entries(o))i[a]=ae(s);return{kind:"object",optional:!1,description:r,fields:i}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let o=Le(n);for(let i of o){let a=K(i);if(q(a)==="ZodObject")return{...ae(i),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let o=W(n);return o?{...ae(o),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function eg(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let o=t.slice(0,r),i=t.slice(r+1),a=e.find(u=>u.id===o);if(!a)return null;let s=i;s.startsWith("api.")&&(s=s.slice(4));let c=be(a.endpointMeta,s),l=be(a.endpointSchemas,s);return!c&&!l?null:{input:l?.input?ae(l.input):null,output:l?.output?ae(l.output):null,description:c?.description}}var kr=["equals","contains","startsWith","endsWith","in"],Ia=["equals","gt","gte","lt","lte","in"],Sa=["equals"],Ra=["equals","before","after","between"];function ni(e){let n=K(e);switch(q(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=W(n);return r?ni(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function br(e){let n=K(e),t=q(n);if(hr(t)){let i=W(n);return i?br(i):{}}if(t!=="ZodObject")return{};let r=tt(e,n),o={};for(let[i,a]of Object.entries(r)){let s=ni(a);s==="string"?o[i]={type:"string",operators:kr}:s==="number"?o[i]={type:"number",operators:Ia}:s==="boolean"?o[i]={type:"boolean",operators:Sa}:s==="date"&&(o[i]={type:"date",operators:Ra})}return o}function ti(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function fr(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];typeof o=="function"?t.push(i.join(".")):o!==null&&typeof o=="object"&&fr(o,i,t)}}function yr(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function mr(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];yr(o)?t.push(i.join(".")):o!==null&&typeof o=="object"&&mr(o,i,t)}}function Cr(e,n){if(n.length===0)return null;let[t,...r]=n,o=Object.entries(e).find(([s])=>s.toLowerCase()===t);if(!o)return null;let[i,a]=o;if(r.length===0)return yr(a)?[i]:null;if(a!==null&&typeof a=="object"&&!yr(a)){let s=Cr(a,r);if(s!==null)return[i,...s]}return null}function ri(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let i=0;i<n.length;i++){let a=" ".repeat(i+2);t.push(`${a}${n[i]}: {`)}let r=" ".repeat(n.length+2),o=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${o}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let i=n.length-1;i>=0;i--){let a=" ".repeat(i+2);t.push(`${a}},`)}return t.push(" },"),t.push("})"),t.join(`
26
- `)}var Ea=new Set(ln);function Se(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let i=e.find(s=>s.id===r);if(!i)return Ea.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:Se(e);if(t==="webhooks"){if(!i.webhooks)return[];let s=[];return mr(i.webhooks,[],s),s.map(c=>`${i.id}.webhooks.${c}`)}if(t==="db"){let s=i.schema?.entities;return s?Object.keys(s).map(c=>`${i.id}.db.${c}.search`):[]}if(!i.endpoints)return[];let a=[];return fr(i.endpoints,[],a),a.map(s=>`${i.id}.api.${s}`)}let o={};if(t==="webhooks")for(let i of e){if(!i.webhooks)continue;let a=[];mr(i.webhooks,[],a),o[i.id]=a.map(s=>`${i.id}.webhooks.${s}`)}else if(t==="db")for(let i of e){let a=i.schema?.entities;a&&(o[i.id]=Object.keys(a).map(s=>`${i.id}.db.${s}.search`))}else for(let i of e){if(!i.endpoints)continue;let a=[];fr(i.endpoints,[],a),o[i.id]=a.map(s=>`${i.id}.api.${s}`)}return o}function be(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function _a(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let i=t.slice(n.length+1),a=i.startsWith(".")?i.slice(1):i;return a.startsWith("api.")&&(a=a.slice(4)),{shortPath:a,lookupKey:a}}let o=e.slice(n.length+1);return o.toLowerCase().startsWith("api.")&&(o=o.slice(4)),{shortPath:o,lookupKey:o.toLowerCase()}}function gr(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 ng(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let o=t.slice(0,r),i=t.slice(r+1),a=e.find(s=>s.id===o);if(a){if(i.startsWith("db.")){let u=i.slice(3),p=u.lastIndexOf(".");if(p!==-1){let g=u.slice(0,p),d=u.slice(p+1),f=a.schema?.entities;if(d==="search"&&f){let y=ti(f,g);if(y){let[m,h]=y,v=br(h),C=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${kr.join(", ")}]`];for(let[E,k]of Object.entries(v))C.push(` ${E}?: ${k.type} [${k.operators.join(", ")}]`);return C.push("}"),C.join(`
30
- `)}}}return gr(Se(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let u=i.slice(9);if(a.webhooks){let p=Cr(a.webhooks,u.split("."));if(p!==null){let g=p.join("."),d=be(a.webhookSchemas,g.toLowerCase()),f=d?.response?F(d.response):null,y=[];return d?.description&&y.push(d.description),d?.payload&&y.push(`payload ${nt($e(d.payload))}`),f&&y.push(`response: ${f}`),y.push(`usage:
31
- ${ri(o,p)}`),y.join(`
32
-
33
- `)}}return gr(Se(e,{type:"webhooks"}),"Path not found. Available webhooks")}let s=i;s.startsWith("api.")&&(s=s.slice(4));let c=be(a.endpointMeta,s),l=be(a.endpointSchemas,s);if(c||l){let u=[],p=[c?.riskLevel?`[${c.riskLevel}]`:"",c?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),g=[c?.description,p].filter(Boolean).join(" ");return g&&u.push(g),l?.input&&u.push(`input ${nt($e(l.input))}`),l?.output&&u.push(`output ${nt($e(l.output))}`),u.join(`
34
-
35
- `)}}}return gr(Se(e),"Path not found. Available operations")}function Yo(e){let n=e;for(;;){let t=K(n),r=q(t);if(hr(r)){let o=W(t);if(!o)return n;n=o;continue}return n}}function $e(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=Yo(e),t=K(n);if(q(t)==="ZodObject"){let o=tt(n,t),i=[];for(let[a,s]of Object.entries(o)){let c=K(s),l=q(c),u=l==="ZodOptional"||l==="ZodNullable",p=Yo(s),g=xa(s);i.push({key:a,optional:u,type:F(p),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:i}}return{kind:"inline",type:F(n)}}function nt(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=Vo.repeat(n+1),r=Vo.repeat(n);return`{
36
- ${e.fields.map(i=>{let a=i.optional?`${i.key}?`:i.key,s=i.description?` // ${i.description}`:"";return`${t}${a}: ${i.type}${s}`}).join(`
37
- `)}
38
- ${r}}`}return"unknown"}function Da(e,n){let t=Se(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(u=>u.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let o=[];for(let u of t){let{shortPath:p,lookupKey:g}=_a(u,n),d=be(r.endpointMeta,g),f=be(r.endpointSchemas,g);!d&&!f||o.push({path:u,shortPath:p,description:d?.description,riskLevel:d?.riskLevel,irreversible:d?.irreversible,input:$e(f?.input),output:$e(f?.output)})}o.sort((u,p)=>u.path.localeCompare(p.path));let i=[],a=Se(e,{plugin:n,type:"webhooks"});if(Array.isArray(a)&&r.webhooks)for(let u of a){let g=u.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("webhooks."))continue;let f=d.slice(9),y=Cr(r.webhooks,f.split("."));if(y===null)continue;let m=y.join("."),h=be(r.webhookSchemas,m.toLowerCase()),v=h?.response?F(h.response):void 0;i.push({path:u,description:h?.description,payload:$e(h?.payload),responseType:v,usageExample:ri(n,y)})}i.sort((u,p)=>u.path.localeCompare(p.path));let s=[],c=Se(e,{plugin:n,type:"db"}),l=r.schema?.entities;if(Array.isArray(c)&&l)for(let u of c){let g=u.toLowerCase().slice(n.length+1),d=g.startsWith(".")?g.slice(1):g;if(!d.startsWith("db."))continue;let f=d.slice(3),y=f.lastIndexOf(".");if(y===-1)continue;let m=f.slice(0,y);if(f.slice(y+1)!=="search")continue;let v=ti(l,m);if(!v)continue;let[C,E]=v,k=br(E),b=Object.entries(k).map(([P,x])=>({field:P,type:x.type,operators:x.operators}));s.push({path:u,entityName:C,filters:[{field:"entity_id",type:"string",operators:kr},...b]})}return s.sort((u,p)=>u.path.localeCompare(p.path)),{ok:!0,data:{pluginId:n,api:o,webhooks:i,db:s}}}function oi(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function Oa(e,n){let t=oi(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let o=r.pluginTenantWebhookMatcher(n);return o?{plugin:t,tenantMatch:o}:null}function Ma(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function ii(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function si(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 an(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function Ha(e){return an(e.body)}function ai(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return rt(Array.isArray(r)?r:[r])}function ci(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let c of t){let l=rt(Array.isArray(c)?c:[c]);if(l)return decodeURIComponent(l)}let r=ai({query:e.query},"validationToken");if(r)return r;let o=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let c of o){let l=n[c],u=Array.isArray(l)?l[0]:l;if(!(!u||typeof u!="string"))try{let g=(u.startsWith("http")?new URL(u):new URL(`https://example.invalid${u.startsWith("/")?u:`/${u}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let i=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,a=an(typeof i=="string"?(()=>{try{return JSON.parse(i)}catch{return i}})():i);return rt([a?.validationToken])??null}function Fa(e){if(ci(e))return!0;let n=an(e.body??e.payload);return ii(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function rt(e){for(let n of e){let t=si(n);if(t)return t}}function Ua(e){let t=an(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var sn=Symbol.for("corsair:internal");function zr(e){let n=e.database?wr(e.database):void 0,t=n&&e.kek?Lo(e.plugins,n,e.kek):Xn(!!n,!!e.kek),r=$o(e),o={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?dn(e.hub):void 0},i=so(n),a=Zo(o);if(e.multiTenancy)return Object.assign({withTenant:c=>{if(!c)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let l=pr(e.plugins,{database:n,tenantId:c,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign(l,{[sn]:o})},keys:t,permissions:i,manage:a},{[sn]:o});let s=pr(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:o.hub,internalConfig:o});return Object.assign({},s,{keys:t,permissions:i,manage:a,[sn]:o})}var B=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function ui(e){let n=e.oauthConfig;if(!n)throw new B("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Ba(e,n,t,r){let o=Sr(e),i=await o.integrations.findByName(n);if(!i)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await o.accounts.findOne({tenant_id:t,integration_id:i.id}))return;let s=te(),c=await re(s,r);await o.accounts.create({tenant_id:t,integration_id:i.id,config:{},dek:c})}async function lt(e,n,t){let{tenantId:r,redirectUri:o,hubConnect:i=!1}=t,a=w(e,()=>new B("invalid_corsair_instance","Invalid corsair instance"));if(!a.database)throw new Error("No database configured on corsair instance");let s=H(a,n,g=>new B("plugin_not_found",g)),c=ui(s),u=await S({authType:"oauth_2",integrationName:n,kek:a.kek,database:a.database}).get_client_id();if(!u)throw new Error(`client_id not configured for '${n}'`);if(i){let g=new URL(ve({oauthConfig:c,clientId:u,redirectUri:o,state:""}));return g.searchParams.delete("state"),{url:g.toString(),state:""}}let p=Oe(fe(n,r),a.kek);return{url:ve({oauthConfig:c,clientId:u,redirectUri:o,state:p}),state:p}}async function rn(e,n){let{code:t,state:r,redirectUri:o}=n,i=w(e,()=>new B("invalid_corsair_instance","Invalid corsair instance")),a=In(r,i.kek);if(!a)throw new B("invalid_state","Invalid or tampered state parameter");let{plugin:s,tenantId:c}=a;if(!i.database)throw new B("no_database","No database configured on corsair instance");let l=H(i,s,m=>new B("plugin_not_found",m)),u=ui(l),p=S({authType:"oauth_2",integrationName:s,kek:i.kek,database:i.database}),g=await p.get_client_id(),d=await p.get_client_secret();if(!g||!d)throw new B("credentials_not_configured",`Credentials not configured for '${s}'`);await Ba(i.database,s,c,i.kek);let f=await et(t,g,d,u,o);if(!f.access_token)throw new B("no_access_token",`No access_token returned from ${u.providerName}`);let y=_({authType:"oauth_2",integrationName:s,tenantId:c,kek:i.kek,database:i.database});await y.set_access_token(f.access_token),f.refresh_token&&await y.set_refresh_token(f.refresh_token),f.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+f.expires_in));try{let m=await Zn(i.plugins,s,f);if(m)try{let h=l.authConfig?.oauth_2?.account??[];await Be({database:i.database,kek:i.kek,pluginId:s,tenantId:c,link:m,authType:"oauth_2",extraAccountFields:h})}catch(h){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${s}' tenant '${c}':`,h)}}catch(m){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${s}' tenant '${c}':`,m)}return{plugin:s,tenantId:c}}export{Rr as a,le as b,Ke as c,de as d,dn as e,J as f,pn as g,Re as h,gn as i,fn as j,yn as k,mn as l,_r as m,hn as n,Ee as o,te as p,re as q,$ as r,st as s,Ze as t,ge as u,oe as v,Ge as w,S as x,_ as y,jr as z,Wr as A,fe as B,gt as C,Be as D,Ht as E,Gn as F,Ao as G,ve as H,B as I,lt as J,rn as K,Tn as L,Qi as M,An as N,Sc as O,dt as P,Rc as Q,Xr as R,pt as S,xn as T,no as U,to as V,yt as W,Sn as X,Rn as Y,me as Z,Pe as _,Nn as $,xt as aa,Ue as ba,Ln as ca,It as da,$n as ea,jn as fa,Ve as ga,St as ha,Rt as ia,Dt as ja,Ot as ka,wo as la,vo as ma,he as na,Ne as oa,Io as pa,se as qa,zn as ra,Vn as sa,ke as ta,Ae as ua,nn as va,tn as wa,Yn as xa,Nt as ya,Lt as za,jt as Aa,Wt as Ba,Kt as Ca,qt as Da,Zt as Ea,xe as Fa,Q as Ga,Gt as Ha,Do as Ia,Mo as Ja,Jt as Ka,zt as La,Vt as Ma,Yt as Na,Qt as Oa,Xt as Pa,er as Qa,nr as Ra,tr as Sa,rr as Ta,or as Ua,ir as Va,sr as Wa,ar as Xa,cr as Ya,Ie as Za,Wo as _a,Ko as $a,qo as ab,Go as bb,Aa as cb,et as db,eg as eb,Se as fb,ng as gb,nt as hb,Da as ib,oi as jb,Oa as kb,Ma as lb,ii as mb,si as nb,an as ob,Ha as pb,ai as qb,ci as rb,Fa as sb,rt as tb,Ua as ub,sn as vb,zr as wb};