corsair 0.1.101 → 0.1.103

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.
Files changed (34) hide show
  1. package/dist/{browser-delivery-S1jgUS7n.d.ts → browser-delivery-DE71IK5C.d.ts} +1 -1
  2. package/dist/chunk-3ELEU4KA.js +38 -0
  3. package/dist/client/react/index.d.ts +4 -5
  4. package/dist/{connect-HAVE4UFR.js → connect-YUGW4GB5.js} +1 -1
  5. package/dist/core.d.ts +7 -9
  6. package/dist/core.js +1 -1
  7. package/dist/db.d.ts +2 -2
  8. package/dist/hub.d.ts +32 -9
  9. package/dist/hub.js +1 -1
  10. package/dist/{index-BL_Wze86.d.ts → index-CXpDAEOf.d.ts} +51 -1
  11. package/dist/{index-BwQsXpxI.d.ts → index-DKIQbeNM.d.ts} +187 -5
  12. package/dist/{index-CY6fUO8K.d.ts → index-WqJfKVqn.d.ts} +1 -2
  13. package/dist/{index-ggMa1Rj6.d.ts → index-eydqYIn0.d.ts} +1 -1
  14. package/dist/index.d.ts +11 -13
  15. package/dist/index.js +1 -1
  16. package/dist/oauth.d.ts +14 -5
  17. package/dist/oauth.js +1 -1
  18. package/dist/orm.d.ts +2 -2
  19. package/dist/{setup-NVGQHCCO.js → setup-OYRFEDUS.js} +1 -1
  20. package/dist/{setup-introspect-U3GFH2A4.js → setup-introspect-P674L2XG.js} +1 -1
  21. package/dist/setup.d.ts +4 -6
  22. package/dist/setup.js +1 -1
  23. package/dist/{tenant-match-utils-mRNSoG3k.d.ts → tenant-match-utils-C5Jn0opu.d.ts} +2 -2
  24. package/dist/tests.d.ts +1 -1
  25. package/dist/tunnel.d.ts +6 -9
  26. package/dist/tunnel.js +1 -1
  27. package/dist/{types-Cy9zP96e.d.ts → types-Br272VqS.d.ts} +1 -1
  28. package/dist/types-FOY4YYJo.d.ts +152 -0
  29. package/package.json +1 -1
  30. package/dist/chunk-VT7FIN7U.js +0 -38
  31. package/dist/constants-CQtdZMk5.d.ts +0 -77
  32. package/dist/tenant-links-Cz5ra6BJ.d.ts +0 -44
  33. package/dist/types-CzXqyIs-.d.ts +0 -69
  34. package/dist/types-DpJORHx2.d.ts +0 -187
@@ -1,4 +1,4 @@
1
- import { B as BrowserDeliveryPayload } from './index-BL_Wze86.js';
1
+ import { B as BrowserDeliveryPayload } from './index-CXpDAEOf.js';
2
2
 
3
3
  /**
4
4
  * Browser (client) delivery — hub redirects the user's browser to the app with `?d=<token>`.
@@ -0,0 +1,38 @@
1
+ import{a as Ar,b as le,c as xr,d as w,e as H,f as Ir,g as B,h as O,i as I,j as ln,k as Sr,l as Rr,m as st,n as Er,o as _r}from"./chunk-BPFUYXOD.js";import{a as Pr}from"./chunk-IGGCNGU2.js";var dn=["agentql","ahrefs","airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","deepseek","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","gemini","github","gitlab","gmail","googlecalendar","googledocs","googledrive","googlemeet","googlesheets","grafana","hackernews","hubspot","insightoai","instagram","intercom","jira","linear","linkedin","monday","neon","notion","onedrive","openai","openweathermap","oura","outlook","pagerduty","perplexityai","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","supabase","tally","tavily","teams","telegram","todoist","trello","twilio","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"],Dr={agentql:"AgentQL",ahrefs:"Ahrefs",airtable:"Airtable",amplitude:"Amplitude",asana:"Asana",bitwarden:"Bitwarden",bluesky:"Bluesky",box:"Box",cal:"Cal",calendly:"Calendly",cloudflare:"Cloudflare",cursor:"Cursor",deepseek:"DeepSeek",discord:"Discord",dodopayments:"Dodo Payments",dropbox:"Dropbox",exa:"Exa",figma:"Figma",firecrawl:"Firecrawl",fireflies:"Fireflies",gemini:"Gemini",github:"GitHub",gitlab:"GitLab",gmail:"Gmail",googlecalendar:"Google Calendar",googledocs:"Google Docs",googledrive:"Google Drive",googlemeet:"Google Meet",googlesheets:"Google Sheets",grafana:"Grafana",hackernews:"Hacker News",hubspot:"HubSpot",insightoai:"Insighto.ai",instagram:"Instagram",intercom:"Intercom",jira:"Jira",linear:"Linear",linkedin:"LinkedIn",monday:"Monday",neon:"Neon",notion:"Notion",onedrive:"OneDrive",openai:"OpenAI",openweathermap:"OpenWeatherMap",oura:"Oura",outlook:"Outlook",pagerduty:"PagerDuty",posthog:"PostHog",razorpay:"Razorpay",reddit:"Reddit",resend:"Resend",sentry:"Sentry",sharepoint:"SharePoint",slack:"Slack",spotify:"Spotify",strava:"Strava",stripe:"Stripe",supabase:"Supabase",tally:"Tally",tavily:"Tavily",teams:"Teams",telegram:"Telegram",todoist:"Todoist",trello:"Trello",twilio:"Twilio",twitter:"Twitter",twitterapiio:"Twitter API IO",typeform:"Typeform",vapi:"Vapi",xquik:"XQuik",youtube:"YouTube",zendesk:"Zendesk",zohomail:"Zoho Mail",zoom:"Zoom",perplexityai:"Perplexity AI"};function de(e){let n=Dr[e];return n||e.charAt(0).toUpperCase()+e.slice(1)}var qe="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 pn(e){let n=(e.apiUrl?.trim()||qe).replace(/\/$/,""),t=e.projectApiKey.trim(),r=e.signingSecret.trim();if(!t||!r)throw new Error("Hub config requires non-empty projectApiKey and signingSecret");return{apiUrl:n,projectApiKey:t,signingSecret:r,oauthCallbackUrl:e.oauthCallbackUrl?.trim().replace(/\/$/,"")}}function yi(e){return e.apiUrl.trim().length>0&&e.projectApiKey.trim().length>0&&e.signingSecret.trim().length>0}function N(e){let n=w(e).hub;if(!n||!yi(n))throw new pe;return n}function Or(e){return e.replace(/\/$/,"")}function gn(e){return e.oauthCallbackUrl?Or(e.oauthCallbackUrl.trim()):`${Or(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 mi(e){return e==="ready"||e==="partial"||e==="not_started"||e==="missing_integration"}function hi(e){return e==="oauth_2"||e==="api_key"||e==="bot_token"||e==="managed"}function fn(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 yn(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)||!mi(r.status)||!hi(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 mn(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 hn(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 ki(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function bi(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 Ci(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 Mr(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=bi(o.fields),s=ki(o.missingRequiredFields),u=Ci(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 kn(e){if(!e||typeof e!="object")return null;let n=e;return n.error??n.message??null}var wi="3000",Ti="/api/corsair";function vi(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 vi(r)}return`http://localhost:${process.env.PORT?.trim()||wi}${Ti}`}function Hr(e){return e.replace(/\/$/,"")}function at(e){if(!e.projectApiKey.startsWith("ck_dev_"))return null;try{return ge()}catch{return null}}function Fr(e){let n=at(e);return n?{"x-corsair-delivery-url":n}:{}}async function Ur(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 Br(e,n,t){if(n===404&&t)return t;let r=kn(e);return r||`Hub API returned HTTP ${n}`}async function W(e){let n=Hr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.hub.projectApiKey}`,...Fr(e.hub)},body:JSON.stringify(e.body)}),r=await Ur(t);if(!t.ok)throw new Error(Br(r,t.status,e.notFoundMessage));return e.parseResponse(r)}async function Nr(e){let n=Hr(e.hub.apiUrl),t=await fetch(`${n}${e.path}`,{method:"GET",headers:{authorization:`Bearer ${e.hub.projectApiKey}`,...Fr(e.hub)}}),r=await Ur(t);if(!t.ok)throw new Error(Br(r,t.status,e.notFoundMessage));return e.parseResponse(r)}import{createCipheriv as Lr,createDecipheriv as $r,randomBytes as bn,scrypt as Pi}from"crypto";import{promisify as Ai}from"util";var Wr=Ai(Pi),Cn="aes-256-gcm",jr=12,wn=16,xi=16,Ze=32;function re(){return bn(Ze).toString("base64")}async function oe(e,n){let t=bn(xi),r=await Wr(n,t,Ze),o=bn(jr),i=Lr(Cn,r,o,{authTagLength:wn}),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 Wr(n,a,Ze),p=$r(Cn,c,s,{authTagLength:wn});return p.setAuthTag(u),Buffer.concat([p.update(l),p.final()]).toString("utf8")}function ut(e,n){let t=Buffer.from(n,"base64"),r=bn(jr),o=Lr(Cn,t,r,{authTagLength:wn}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),a=o.getAuthTag();return[r.toString("base64"),a.toString("base64"),i.toString("base64")].join(":")}function Ge(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=$r(Cn,i,a,{authTagLength:wn});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]=ut(o,n);return t}function ie(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Ge(o,n);return t}function Je(e,n,t){let r=ie(e,n);return fe(r,t)}function Kr(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 ct=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:ct(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 T=await j(f.dek,r),C=f.config;C&&Object.keys(C).length>0&&(m=Je(C,T,y))}let h=await oe(y,r);return await u.updateIntegration({config:m,dek:h}),l=y,y},...Kr(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 T=fe(h,y);await u.updateIntegration({config:T})},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:ct(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(),v=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",b.id).executeTakeFirst();if(!v){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:v.id,config:ct(v.config),dek:v.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(),v=k.config;return!v||Object.keys(v).length===0?{}:ie(v,b)},T=async()=>{let k=await g.getIntegration(),b=await m(),v=k.config;return!v||Object.keys(v).length===0?{}:ie(v,b)},E={get_dek:y,issue_new_dek:async()=>{let k=await g.getAccount(),b=re(),v={};if(k.dek){let ee=await j(k.dek,o),D=k.config;D&&Object.keys(D).length>0&&(v=Je(D,ee,b))}let x=await oe(b,o);return await g.updateAccount({config:v,dek:x}),d=b,b},...Kr(h,async k=>{let b=await y(),v;try{v=await h()}catch(D){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,D),v={}}let x={...v};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 T();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),E}async function qr(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 Zr(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 Ii=new Set(["webhook_signature","expires_at","scope","redirect_url"]);function _e(e){return Ii.has(e)}function Si(e,n){return _e(n)?!1:e==="oauth_2"?n==="client_id"||n==="client_secret":!0}function Ri(e){return!_e(e)}function Ei(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 _i(e,n){return Ei(e).every(r=>n.find(i=>i.level==="account"&&i.name===r)?.configured??!1)}async function Gr(e,n){if(!e)return!1;let t=B(e,`get_${n}`);if(!t)return!1;try{let r=await t();return typeof r=="string"&&r.length>0}catch{return!1}}function Di(e,n){let r=e.authConfig?.[n]?.integration??[];return[...O[n].integration,...r]}function Oi(e,n){let r=e.authConfig?.[n]?.account??[];return[...O[n].account,...r]}function Mi(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:_i(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=Di(n,r),p=Oi(n,r),g=[];for(let d of c)g.push({name:d,level:"integration",required:Si(r,d),configured:await Gr(u,d)});for(let d of p)g.push({name:d,level:"account",required:Ri(d),configured:await Gr(l,d)});return Mi(n.id,r,g)}async function ze(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 Tn(e){return e.connected?"connected":e.status==="missing_integration"?"missing_credentials":"not_connected"}var Jr=Symbol.for("corsair:internal"),zr=new WeakMap;function Hi(e){let n=zr.get(e);return n||(n=new Map,zr.set(e,n)),n}function Fi(e){return e.multiTenancy?{withTenant:()=>({}),[Jr]:e}:{[Jr]:e}}async function vn(e,n){if(!e.database)return;let t=n.trim()||"default",r=Hi(e),o=t,i=r.get(o);if(i){await i;return}let a=(async()=>{let{setupCorsair:s}=await import("./setup-OYRFEDUS.js");await s(Fi(e),{tenantId:e.multiTenancy?t:void 0,silent:!0})})().finally(()=>{r.delete(o)});r.set(o,a),await a}import{ZodBoolean as Bi,ZodDate as Ni,ZodEnum as Li,ZodNullable as $i,ZodNumber as Wi,ZodObject as ji,ZodOptional as Ki,ZodRecord as qi,ZodString as Zi,ZodType as Gi}from"zod";var Ui={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:{}}}},lt=Ui;async function An(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=xr(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=zi(e,s.plugins,n),l={...s,database:s.database},c=l.database.db;await Qi(c,i);let p=await Xi(c,l,u.tenantId,u.provisionAccounts,o);n?.credentials&&Object.keys(n.credentials).length>0&&await ts(e,u,n.credentials,l,o,i);let g=await os(p,u,o,a);if(n?.backfill){o("[corsair:setup] Starting backfill...");let d=Qr({plugins:s.plugins,database:c,kek:s.kek,multiTenancy:!0}).withTenant(u.tenantId);await is(d,s.plugins,g,o,i),o("[corsair:setup] Backfill complete.")}return t.join(`
2
+ `)}function dt(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...O[n][t],...r])}function Ji(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=dt(o,i,"account");for(let s of Object.keys(r))if(a.has(s))return!0}return!1}function zi(e,n,t){let r=Ir(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&&Ji(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 Yr(e,n){return le(e)?n===0?!0:Object.values(e).every(t=>Yr(t,n-1)):!1}function Vi(e){return Yr(e,4)}var Yi={...Er};function Pn(e){if(e instanceof ji){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Gi?Pn(r):"unknown";return n}return e instanceof $i?`${Pn(e.unwrap())} | null`:e instanceof Ki?`${Pn(e.unwrap())} | undefined`:e instanceof Li?e.options.join(" | "):e instanceof Zi?"string":e instanceof Wi?"number":e instanceof Bi?"boolean":e instanceof Ni?"date":e instanceof qi?"jsonb":"unknown"}async function Qi(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(o=>o.name));for(let[o,i]of Object.entries(Yi))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 Xi(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 es(e){if(!le(e))return;let n=e.keys;return le(n)?n:void 0}function ns(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function ts(e,n,t,r,o,i){let a=es(e),s=n.provisionAccounts?ns(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=dt(c,p,"integration"),d=dt(c,p,"account"),f=a?.[u],y=s?.[u],m=le(y)?y.keys:void 0;for(let[h,T]of Object.entries(l))if(T){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=B(f,`set_${h}`);if(!C){i(`[corsair:setup] Cannot set integration field '${h}' for '${u}'.`);continue}await C(T),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=B(m,`set_${h}`);if(!C){i(`[corsair:setup] Cannot set account field '${h}' for '${u}'.`);continue}await C(T),o(`[corsair:setup] Set ${u} account.${h} (tenant=${n.tenantId})`);continue}i(`[corsair:setup] Unknown credential field '${h}' for plugin '${u}'.`)}}}var Vr=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function rs(e,n,t,r,o,i,a,s,u){let l=[],c=[];for(let g of o){if(Vr.has(g))continue;let d=B(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(Vr.has(g))continue;let d=B(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 os(e,n,t,r){let o=new Set;for(let i of e.values())await rs(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function is(e,n,t,r,o){if(!Vi(lt)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=lt,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 B(y,d)?.(f)}catch(y){o(`[corsair:setup] ${s} \u203A ${p}.${d} failed: `+(y instanceof Error?y.message:String(y)))}}}}async function Xr(e){if(!w(e).database)throw new Error("A database must be configured to provision Corsair integrations");await An(e,{silent:!0})}async function Te(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 ss=Symbol.for("corsair:internal"),as=new Set(["access_token","refresh_token","expires_at","scope"]);function us(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function cs(e,n){return e==="oauth_2"||e==="managed"?n.filter(t=>!_e(t)&&!as.has(t)):n.filter(t=>!_e(t))}function eo(e){return{plugins:e.plugins,database:e.database,kek:e.kek,multiTenancy:!1}}function no(e){return{[ss]:eo(e)}}async function xn(e,n,t={}){let r=gn(e.hub),o=[],i=t.pluginIds?new Set(t.pluginIds):null,a=eo(e),s=no(e);for(let u of e.plugins){if(i&&!i.has(u.id))continue;let l=I(u);if(!l)continue;let c=us(l),p=t.providerNameOverrides?.[u.id]??de(u.id),g=await De(a,u,n),d=ln(u,l),f=cs(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 T=await pt(s,u.id,{tenantId:n,redirectUri:r,hubConnect:!0});y.oauthUrl=T.url}catch(T){y.setupError=T instanceof Error?T.message:`Could not prepare OAuth for ${u.id}`}}o.push(y)}return o}async function Hu(e,n,t={}){let r=w(e),o=r.hub;if(!o)throw new Error("Hub is not configured");return xn({plugins:r.plugins,database:r.database,kek:r.kek,hub:o},n,t)}async function gt(e,n){if(!e.database)throw new Error("A database must be configured to provision Corsair for connect");await Te(no(e),n)}async function Fu(e,n){await Te(e,n)}async function to(e,n){let t=Ee(e.projectApiKey),r={tenantId:n.tenantId,plugins:n.plugins};return t==="development"&&(r.deliveryUrl=ge({deliveryUrl:n.deliveryUrl})),W({hub:e,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:fn})}async function ft(e,n){let t={plugins:n.plugins,database:n.database,kek:n.kek,hub:e};await gt(t,n.tenantId);let r=await xn(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 to(e,{tenantId:n.tenantId,plugins:r,deliveryUrl:n.deliveryUrl})}async function In(e,n){let t=w(e),r=N(e),o={plugins:t.plugins,database:t.database,kek:t.kek,hub:r};await gt(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 xn(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 to(r,{tenantId:n.tenantId,plugins:u,deliveryUrl:n.deliveryUrl})}function ro(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function ls(e,n){return n&&!n.has(e.id)?!1:I(e)!==null}async function oo(e,n,t={}){let r=w(e),o=n.trim()||"default",i=t.pluginIds?.length?new Set(t.pluginIds):null,a=await ze(r,o,{pluginIds:t.pluginIds}),s=new Map(a.map(l=>[l.plugin,l])),u=r.plugins.filter(l=>ls(l,i)).map(l=>{let c=I(l),p=s.get(l.id);return p?{plugin:l.id,providerName:de(l.id),authKind:ro(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:ro(c),status:"not_started",connected:!1,fields:[],missingRequiredFields:[]}});return{tenantId:o,plugins:u}}async function io(e,n){let t=N(e);return Nr({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:yn})}import*as Ve from"crypto";function ye(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function yt(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=Ve.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var mt=600*1e3;function Sn(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),o=e.slice(t+1),i=Ve.createHmac("sha256",n).update(r).digest("base64url"),a=Buffer.from(o,"base64url"),s=Buffer.from(i,"base64url");return a.length!==s.length||!Ve.timingSafeEqual(a,s)?null:yt(r,{maxAgeMs:mt})}function Me(e){return!!(e?.baseUrl?.trim()&&e?.redirectUri?.trim())}import*as so 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}?${so.stringify(i)}`}var K=class extends Error{code;constructor(n,t){super(t),this.name="ConnectError",this.code=n}};function ds(e){let n=e.oauthConfig;if(!n)throw new K("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function ht(e,n){let t=w(e,()=>new K("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new K("no_database","No database configured on corsair instance");let r=t.manual?.redirectUri;if(!r)throw new K("no_redirect_uri","No redirectUri configured. Set manual.redirectUri in createCorsair().");let o=Sn(n,t.kek);if(!o)throw new K("invalid_state","Invalid or tampered state parameter");let{plugin:i,tenantId:a}=o,s=H(t,i,g=>new K("plugin_not_found",g)),u=ds(s),c=await S({authType:"oauth_2",integrationName:i,kek:t.kek,database:t.database}).get_client_id();if(!c)throw new K("client_id_not_configured",`client_id not configured for '${i}'`);let p=ve({oauthConfig:u,clientId:c,redirectUri:r,state:n});return{plugin:i,tenantId:a,providerName:u.providerName,oauthUrl:p,state:n}}import{randomBytes as gs}from"crypto";import{v4 as fs}from"uuid";async function Rn(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})),W({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:r,parseResponse:mn})}function En(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}var kt="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 Ct(e){return e?e.approvalBaseUrl!==void 0||e.onApprovalRequired!==void 0:!1}function ao(e,n){return`${e.replace(/\/+$/,"")}/${n}`}function bt(e){return En(e)}async function wt(e,n){if(Ct(e.manual)){let r=e.manual?.approvalBaseUrl?.trim();return r?ao(r,n.token):null}let t=e.hub;if(!t)return null;try{return(await Rn(t,{permissionId:n.id,permissionToken:n.token,plugin:n.plugin,endpoint:n.endpoint,args:ps(n.args),tenantId:n.tenant_id,expiresAt:n.expires_at})).approvalUrl}catch{return null}}function ps(e){try{return JSON.parse(e)}catch{return e}}async function _n(e,n){if(!(n.status==="pending"||n.status==="approved"))return{...n,approvalUrl:null};let r=await wt(e,n);return{...n,approvalUrl:r}}async function Tt(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 wt({manual:t,hub:r},{id:o,token:i,plugin:a,endpoint:s,args:JSON.stringify(u),tenant_id:l,expires_at:c});return Ct(t)?d?t?.onApprovalRequired?t.onApprovalRequired({approvalUrl:d}):bt(d):kt:r?d?bt(d):`Action '${p}' requires user approval before it can run. Could not create approval link. Check hub configuration and server logs.`:kt}var ys={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 ms(e,n,t){return t!==void 0?t:ys[n][e]}function vt(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 co(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 uo(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 lo(e){let n=ms(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"?uo(e.db,s.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:s.id,token:s.token,expiresAt:s.expires_at})}let u=fs(),l=gs(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"?uo(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 po(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 go(e,n){return H(e,n,t=>me(t))}async function fo(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 yo(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:o,missingFields:i}=await fo(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 Dn(){return{ok:!0}}async function He(e){return Promise.all(e.plugins.map(n=>yo(n,e)))}async function On(e,n){let t=go(e,n);return yo(t,e)}async function hs(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 mo(e,n){let t=await hs(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 Mn(e,n){if(!n)throw se("Tenant id must be a non-empty string");return mo(e,n)}async function Hn(e,n){let t=n?.id?.trim();if(!t)throw se("Tenant id is required",{missingFields:["id"]});return mo(e,t)}async function Fn(e,n){let t=n?.trim()||"default",r={},o=await ze(e,t);for(let i of o)r[i.plugin]=Tn(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 Pt(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 _n(e,t)}function ks(e){if(!e.oauthConfig)throw se(`Plugin '${e.id}' has no oauthConfig`)}function bs(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 At(e){let n=bs(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 Cs(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 ho(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 ws(e,n){let t=n?.plugin?.trim();if(!t)throw se("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",o=go(e,t);ks(o);let i=At(e);ho(e);let a=await fo(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()+mt).toISOString()}}async function Ts(e,n,t){ho(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 In(e,o);return{connectUrl:s.connectUrl,expiresAt:s.expiresAt}}async function Un(e,n,t){return Cs(n),n.hub?Ts(e,n,t):ws(n,t)}async function Bn(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"]});At(n);try{return await ht(e,r)}catch(o){if(o instanceof K)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 Nn(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=At(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 xt(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 _n(e,t)}async function ko(e,n){return"id"in n?Pt(e,n.id):xt(e,n.token)}import{createCipheriv as Rs,createDecipheriv as Fc,randomBytes as vo,scryptSync as Es}from"crypto";import{createHmac as It,randomUUID as vs,timingSafeEqual as wo}from"crypto";var bo=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 To(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function Ln(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=It("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":vs()}}}function St(e){let n=e.signingSecret.trim();if(!n)return!1;let t=To(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=It("sha256",n).update(e.body).digest("hex");try{return wo(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=To(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=It("sha256",n).update(e.body).digest("hex");try{if(!wo(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 Rt(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function Wn(e){let n=e.sync?.encrypted;return typeof n!="string"||!n.trim()?null:{encrypted:n.trim()}}function jn(e){return Wn($n(e))}function Ps(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 Co(e,n=200){let t=e.trim();return t.length<=n?t:`${t.slice(0,n)}\u2026`}var As="Verify hub.signingSecret in your app matches the signing secret shown in Hub project settings.",xs="Check the delivery URL configured for this environment.";function Is(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})`}. ${As}`}function Ss(e){return`${e.ack.error?`${e.ack.error} (HTTP 404 from ${e.deliveryUrl})`:`Delivery endpoint not found at ${e.deliveryUrl} (HTTP 404)`}. ${xs}`}function Ye(e,n){let t=Ps(n),r=n instanceof Error?n.message:"Delivery request failed",o;switch(t){case"ECONNREFUSED":o="connection refused \u2014 nothing accepted a TCP connection on that host and port";break;case"ENOTFOUND":o="host not found \u2014 DNS could not resolve the hostname";break;case"ETIMEDOUT":case"UND_ERR_CONNECT_TIMEOUT":o="connection timed out before the app responded";break;case"ECONNRESET":o="connection reset while talking to the app";break;case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":o=`TLS certificate error (${t})`;break;default:o=r==="fetch failed"&&t?`${r} (${t})`:r}return[`Could not reach ${e}`,o].join(". ")}function Et(e){if(e.status===0)return e.ack.error?e.ack.error:e.body.startsWith("Could not reach")?e.body:Ye(e.deliveryUrl,new Error(e.body||"Delivery request failed"));if(e.status===401||e.status===403)return Is(e);if(e.status===404)return Ss(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}): ${Co(t)}`:`App failed while processing the delivery (HTTP ${e.status} from ${e.deliveryUrl})`}let n=e.body.trim();return n?`${Co(n)} (HTTP ${e.status} from ${e.deliveryUrl})`:`Delivery failed with HTTP ${e.status} from ${e.deliveryUrl}`}async function _t(e){let{body:n,headers:t}=Ln(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:Ye(e.deliveryUrl,r)}}}var _s="aes-256-gcm",Ds=12,Os=16,Ms=16,Hs=32;function Fs(e,n){return Es(e.trim(),n,Hs)}function Dt(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required to encrypt sync manifest");let r=vo(Ms),o=Fs(t,r),i=vo(Ds),a=Rs(_s,o,i,{authTagLength:Os}),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 Us=["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 Ot(e){if(e instanceof Ar)return!1;if(!(e instanceof Error))return!0;let n=e.message.toLowerCase();return!Us.some(t=>n.includes(t))}async function Qe(e,n){let t=w(e);if(!t.database)throw new Error("A database must be configured to sync connections from the app");await An(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 Dt(i,n)}var Bs=new Set(["localhost","127.0.0.1","[::1]","::1"]);function Mt(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:Bs.has(n)}catch{return!1}}function Ht(e){return e==="development"?"browser":"server"}function Po(e){return Ht(e)==="browser"}function Ao(e){return Mt(e)?"Production delivery URL must be a public URL, not localhost":null}async function xo(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 Ns(o.hub,{plugins:o.plugins,database:o.database,kek:o.kek},{tenantId:t,pluginIds:r});return{connectUrl:i.connectUrl,expiresAt:i.expiresAt}}async function Ns(e,n,t){let{buildConnectPluginManifestFromContext:r,ensureConnectAccountRowsFromContext:o}=await import("./setup-introspect-P674L2XG.js"),{postHubConnectSession:i}=await import("./connect-YUGW4GB5.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 Kn(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 Te(e,n.tenantId);let i=new Set(ln(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=B(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 Ft(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 Xr(e);let i=new Set(Sr(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=B(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 qn=new Map;function Ls(e){for(let[n,t]of qn)t<=e&&qn.delete(n)}function Zn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return Ls(r),qn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(qn.set(t,r+n),{ok:!0})}async function Gn(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 Io=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function $s(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 Ws(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=Io(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 $s({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 Ws({database:n,kek:t,accountId:u,link:i})}async function Ut(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=Io(s.config)[o];if(!c)continue;if(Ge(c,u)===i)return s}catch{continue}return null}async function Jn(e){return(await Ut(e))?.tenant_id??null}async function So(e){return Jn({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}function Ro(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType??"oauth_2",status:"ready",connected:!0,verified:!0,webhookLink:e.link}}function js(e){return{tenantId:e.tenantId,plugin:e.plugin,authType:e.authType,status:e.status,connected:e.connected,verified:e.verified,missingFields:e.missingFields,webhookLink:e.webhookLink}}async function Ne(e,n){await W({hub:e,path:"/connections/report",body:Ro(n),parseResponse:()=>({ok:!0})}).catch(()=>{})}async function Ks(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&&Eo(e.hub,js({tenantId:r,plugin:e.plugin.id,authType:o.authType,status:o.status,connected:o.connected,verified:e.verified??o.connected,missingFields:o.missingRequiredFields}))}function Eo(e,n){W({hub:e,path:"/connections/report",body:n,parseResponse:()=>({ok:!0})}).catch(()=>{})}function Xe(e){Ks(e).catch(()=>{})}var ke=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Le(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 Te(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 Gn(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)}u.hub&&Ne(u.hub,{plugin:t,tenantId:r,link:p,authType:"managed"})}}catch(p){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,p)}return{plugin:t,tenantId:r}}function qs(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function _o(e,n,t=[]){for(let[r,o]of Object.entries(e))if(qs(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=_o(o,n,[...t,r]);if(i)return i}return null}function Zs(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Gs(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 Do(e,n,t,r){let o=Zs(n),i=typeof t=="string"?JSON.parse(t):t;(!i||typeof i=="object"&&Object.keys(i).length===0)&&o["x-goog-resource-uri"]&&(i=Gs(o)||i);let s={headers:o,body:i,...r?{query:r}:{}},u=r?.tenantId||"default",l=e.withTenant?e.withTenant(u):e,c=dn;for(let p of c){let g=l[p];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(s))continue;let d=_o(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 Ys}from"crypto";import{createHmac as Js,randomBytes as zs,timingSafeEqual as Vs}from"crypto";function ae(){return zs(16).toString("base64url")}function en(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Js("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=en(o,t);try{if(!Vs(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 zn(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=en(i,n);return`${i}.${a}`}function nn(e,n,t){let r=Math.floor(Date.now()/1e3);return zn(e,n,r+Math.floor(t/1e3))}function Ae(e){return decodeURIComponent(e)}function Bt(e){return encodeURIComponent(e)}function Oo(e){let n=e.trim();return n.length>0?n:null}function Vn(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Yn(e,n){if(!Oo(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??Ys(16).toString("base64url"),iat:t,exp:t+Math.floor(he/1e3)},o=Buffer.from(JSON.stringify(r)).toString("base64url"),i=en(o,n);return`${o}.${i}`}function be(e,n){return Oo(n)?Q(e,n):null}function xe(e){return e.deliveryMode==="auth.credentials"}function tn(e){return e.deliveryMode==="connections.sync"}function rn(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function on(e){return e.deliveryMode==="oauth.tokens"}function Qn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!xe(e)&&!tn(e)&&!rn(e)&&!on(e)}async function Qs(e,n){try{return{status:"ok",webhookResponse:{status:200,body:{status:"ok",sync:{encrypted:await Qe(e,n)}}}}}catch(t){return{status:"failed",retryable:Ot(t),error:t instanceof Error?t.message:"Connections sync delivery failed"}}}async function Xs(e,n){try{return{status:"ok",connectLink:await xo(e,n)}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Connect link delivery failed"}}}function Nt(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 ea(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 Jn({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function na(e,n,t){let r=await ea(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await Do(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 ta(e,n){return await sn(e,{code:n.code,state:n.state,redirectUri:n.redirectUri,...n.plugin&&n.tenantId?{trusted:!0,plugin:n.plugin,tenantId:n.tenantId}:{}}),{status:"ok"}}async function ra(e,n){return await Le(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function $t(e,n,t){let r=await Lt(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function Lt(e,n,t){let r=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 oa(e,n){try{return await Kn(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function ia(e,n){try{return await Ft(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Integration credential delivery failed"}}}async function Wt(e,n,t={}){let r=w(e),o=Nt(n.headers,"x-corsair-signature"),i=Nt(n.headers,"x-corsair-timestamp"),a=Nt(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=Zn(`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 na(e,r,s.payload);case"oauth.callback":return ta(e,s.payload);case"oauth.tokens":return ra(e,s.payload);case"permission.approve":return Lt(e,s.payload,"approved");case"permission.deny":return Lt(e,s.payload,"denied");case"auth.credentials":return oa(e,s.payload);case"integration.credentials":return ia(e,s.payload);case"connect.create_link":return Xs(e,s.payload);case"connections.sync":{let u=t.signingSecret?.trim();return u?Qs(e,u):{status:"failed",retryable:!1,error:"Tunnel signing secret is required for connections.sync"}}default:return sa(String(s.type))}}function sa(e){return bo.has(e)?{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}:{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${e}`}}var jt=new Map;function Mo(e){let n;try{n=N(e)}catch{return}let t=at(n);t&&jt.get(n.projectApiKey)!==t&&(jt.set(n.projectApiKey,t),W({hub:n,path:"/apps/announce",body:{deliveryUrl:t},parseResponse:()=>({ok:!0})}).catch(()=>{jt.delete(n.projectApiKey)}))}var aa="corsair:client-bridge";function Xn(e){let n=JSON.stringify({type:aa,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 ua=[".corsair.dev"];function ca(e){return e==="localhost"||e==="127.0.0.1"||e==="[::1]"||e==="::1"}function la(e){try{let{hostname:n,protocol:t}=new URL(e);return t!=="http:"&&t!=="https:"?!1:ca(n)?!0:ua.some(r=>n===r.slice(1)||n.endsWith(r))}catch{return!1}}function Ho(e){return!e||!la(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 Fo(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 Kt(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 qt(e,n){let t=N(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=Zn(`browser:${i.jti}`,he);if(!a.ok)return{type:"json",status:400,body:{error:a.error}};try{if(tn(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 Qe(e,t.signingSecret);return{type:"text",status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:Xn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!0,body:{status:"ok",sync:{encrypted:s}}})}}if(xe(i))return i.hubSuccessUrl?i.credentials?(await Kn(e,{plugin:i.plugin,tenantId:i.tenantId,credentials:i.credentials}),{type:"redirect",url:Kt(i.hubSuccessUrl,{connectedPlugin:i.plugin})}):{type:"redirect",url:Kt(i.hubSuccessUrl,{error:"Credential delivery missing credentials"})}:{type:"json",status:400,body:{error:"Credential delivery missing hubSuccessUrl"}};if(rn(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await $t(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(on(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Le(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!Qn(i)||!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await sn(e,{code:i.code,state:i.state,redirectUri:i.redirectUri,trusted:!0,plugin:i.plugin,tenantId:i.tenantId})}}catch(s){let u=s instanceof Error?s.message:"Hub delivery failed";return tn(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Xn({hubOrigin:i.hubOrigin,requestId:i.requestId,ok:!1,error:u})}:xe(i)&&i.hubSuccessUrl?{type:"redirect",url:Kt(i.hubSuccessUrl,{error:u})}:xe(i)&&i.hubOrigin&&i.requestId?{type:"text",status:400,headers:{"Content-Type":"text/html; charset=utf-8"},body:Xn({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 Zt(e,n){let t=N(e),r=await Wt(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 Gt(e){if(e.type==="redirect")return Response.redirect(e.url,302);let n=new Headers;for(let[t,r]of Object.entries(e.headers??{}))typeof r=="string"&&n.set(t,r);return e.type==="json"?Response.json(e.body,{status:e.status,headers:n}):new Response(e.body,{status:e.status,headers:n})}async function Jt(e,n){return n.method==="GET"?qt(e,n.url):Zt(e,{headers:n.headers,body:n.body??""})}async function zt(e,n){try{let t=await Jt(e,n);return Gt(t)}catch(t){if(t instanceof pe)return Response.json({error:t.message},{status:503});throw t}}async function Ie(e,n){Mo(e);let t=n.method.toUpperCase(),r=Ho(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 Fo(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 Uo=300;async function Vt(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+Uo)return{accessToken:s,expiresAt:Number(u),refreshed:!1};if(!l&&s&&!a){let d=u?Number(u):null;if(d===null||d>c+Uo)return{accessToken:s,expiresAt:d??c+3600,refreshed:!1}}let p=await pa(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 da(e){return e.includes("Managed OAuth connection not found")||e.includes("Managed OAuth connection has no tokens")}async function pa(e,n,t){try{return await W({hub:e,path:"/oauth/refresh",body:{plugin:n,tenantId:t},parseResponse:hn})}catch(r){let o=r instanceof Error?r.message:"";throw da(o)?new X(n,"managed"):r}}async function Bo(e,n){e._refreshAuth=async()=>(await Vt(n,{forceRefresh:!0})).accessToken}function No(e){return{delivery:n=>Ie(e,n),deliveryOptions:n=>Ie(e,n)}}var Lo=1200*1e3;function Yt(){return ae()}function Qt(){return Lo}function Xt(e,n){return nn(e,n,Lo)}function er(e,n){return Q(e,n)}function nr(e){return Ae(e)}var $o=600*1e3;function tr(){return ae()}function rr(){return $o}function or(e,n){return nn(e,n,$o)}function ir(e,n){return Q(e,n)}function sr(e){return Bt(e)}function ar(e){return Ae(e)}function ur(){return ae()}function cr(e,n,t){return zn(e,n,Math.floor(t.getTime()/1e3))}function lr(e,n){return Q(e,n)}function dr(e){return Ae(e)}function et(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 ${Ze}`)}})}async function ga(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 Wo(e){let{integrationId:n,accountId:t}=await ga(e);return{integrationId:n,accountId:t}}function pr(e,n){return`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${n}`}async function fa(e,n){let t=e.hub;if(!t||!n.database||!n.kek)return null;try{return(await ft(t,{tenantId:n.tenantId,plugin:n.plugin,database:n.database,kek:n.kek,plugins:n.plugins})).connectUrl}catch{return null}}async function ya(e){let n=e.hub;if(n&&e.database&&e.kek)try{let r=await ft(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}):pr(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 fa({manual:e.manual,hub:e.hub},{plugin:e.plugin,tenantId:e.tenantId,database:e.database,kek:e.kek,plugins:e.plugins});return t?pr(e.pluginId,t):`[auth-missing:${e.pluginId}:${e.authType}]`}function ma(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}):pr(e,i)}async function jo(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"?ma(t,{...e.manual,baseUrl:e.manual.baseUrl,kek:e.manual.kek},e.tenantId):e.hub&&e.plugin&&e.kek&&e.database&&e.plugins?ya({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 ha=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Ko(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||ha)(e,i)}function ka(e){return typeof e=="function"}function gr({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[T,C]of Object.entries(e)){let E=n?.[T];if(ka(C)){let k=E,b=[...a,T].join("."),v=async(x={})=>{let ee;if(u){let M=l?.[b],{result:cn,reason:J,onComplete:Ke,token:te,id:we,expiresAt:$}=await lo({pluginId:o,endpointPath:b,args:x,mode:u.mode,override:u.overrides?.[b],riskLevel:M?.riskLevel??"write",meta:M,db:c,timeoutMs:p?vt(p.timeout):void 0,tenantId:g,approvalMode:p?.mode});if(cn==="blocked"){let z;throw J==="denied"?z=`Action '${b}' was denied by the user. Await further instructions before proceeding.`:J==="policy"?z=`Action '${b}' is blocked by the permission policy. Update the corsair config to allow it.`:J==="timeout"?z=`Action '${b}' timed out waiting for approval.`:te&&we?z=await Tt({permissionsOptions:p,manual:d,hub:f,permissionId:we,permissionToken:te,plugin:o,endpoint:b,args:x,tenantId:g??"default",expiresAt:$??new Date(Date.now()+(p?vt(p.timeout):600*1e3)).toISOString(),operationPath:b}):z=`Action '${b}' requires user approval before it can run.`,new Error(z)}ee=Ke}let D=async(M,cn,J)=>{try{return await C(cn,J)}catch(Ke){if(Ke instanceof Error){let te=await Ko(Ke,o,b,typeof J=="object"&&J!==null?J:{args:J},i);if(M<(te.maxRetries||0)){let we=M+1;console.log(`Retrying (${we} / ${te.maxRetries})...`);let $;if(te.headersRetryAfterMs)$=te.headersRetryAfterMs;else switch(te.retryStrategy){case"exponential_backoff":$=Math.pow(2,we-1)*1e3;break;case"exponential_backoff_jitter":let z=Math.pow(2,we-1)*1e3,fi=(Math.random()-.5)*1e3;$=Math.max(0,z+fi);break;case"linear_1s":$=1e3;break;case"linear_2s":$=2e3;break;case"linear_3s":$=3e3;break;case"linear_4s":$=4e3;break;default:$=1e3;break}await new Promise(z=>setTimeout(z,$)),await D(we,cn,J),console.log(`[corsair:${o}:${b}] Retry strategy:`,te)}}throw Ke}},ce;try{ce=s?await s(t,"endpoint"):void 0}catch(M){if(M instanceof X)return y&&f&&Xe({hub:f,database:c,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!1}),jo({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&&Xe({hub:f,database:c,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!0}),M}let L={...t,key:ce},ne=k.before?await k.before(L,x):{ctx:L,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&&Xe({hub:f,database:c,kek:m,plugins:h??[],plugin:y,tenantId:g,verified:!0}),je};r[T]=v}else if(C&&typeof C=="object"){let k={};gr({endpoints:C,hooks:E,ctx:t,tree:k,pluginId:o,errorHandlers:i,currentPath:[...a,T],keyBuilder:s,permissionsConfig:u,endpointMeta:l,database:c,permissionsOptions:p,tenantId:g,manualConfig:d,hubConfig:f,plugin:y,kek:m,allPlugins:h}),r[T]=k}}}function ba(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function fr({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:o}){for(let[i,a]of Object.entries(e)){let s=n?.[i];if(ba(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={};fr({webhooks:a,hooks:s,ctx:t,webhooksTree:u,keyBuilder:o}),r[i]=u}}}function Ca(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 Wo({database:e,integrationName:n,tenantId:t,ensureProvisioned:r});return o=i,o}}function wa(e,n,t,r,o){return e?st(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 yr(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=Ca(t,d.id,y,c);if(f?.entities){let L={};for(let[ne,je]of Object.entries(f.entities)){let M=t?st(t.db,m,ne,f.version,je):wa(void 0,m,ne,f.version,je);L[ne]=M}g[d.id].db=L,p[d.id].db=L}let h=d.options,T=d.authConfig,C;if(t&&o&&h?.authType){let L=T?.[h.authType]?.account??[];C=_({authType:h.authType,integrationName:d.id,tenantId:y,kek:o,database:t,extraAccountFields:L,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,v={...i,...d.errorHandlers},x={},ee=d.options?.permissions;gr({endpoints:k,hooks:b,ctx:E,tree:x,pluginId:d.id,errorHandlers:v,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 L={};fr({webhooks:D,hooks:ce,ctx:E,webhooksTree:L,keyBuilder:d.keyBuilder}),p[d.id].webhooks=L,d.pluginWebhookMatcher&&(p[d.id].pluginWebhookMatcher=d.pluginWebhookMatcher),d.pluginTenantWebhookMatcher&&(p[d.id].pluginTenantWebhookMatcher=d.pluginTenantWebhookMatcher)}}return p}function qo(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 Ta="createCorsair({ approval: ... }) is deprecated. Rename to permissions: { timeout, onTimeout, mode }.";function Zo(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] ${Ta}`),t):n}var Go=[{method:"GET",pattern:"/ok",handler:async()=>R(200,Dn())},{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 Hn(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>R(200,await Mn(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 On(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>R(200,await Fn(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>R(200,await Pt(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 xt(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 Un(e,n,t))},{method:"GET",pattern:"/connect/resolve",handler:async({corsair:e,internal:n,query:t})=>R(200,await Bn(e,n,t.state??""))},{method:"POST",pattern:"/connect/oauth/callback",handler:async({corsair:e,internal:n,body:t})=>R(200,await Nn(e,n,t))}];(()=>{let e=new Set;for(let n of Go){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function va(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let o={};for(let i=0;i<t.length;i++){let a=t[i],s=r[i];if(a.startsWith(":"))o[a.slice(1)]=decodeURIComponent(s);else if(a!==s)return null}return o}function Pa(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 Aa(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 xa="/api/corsair";function Se(e,n={}){let t=n.basePath??xa,r=w(e,()=>new Error("managementHandler: invalid corsair instance (missing internal config)"));return async o=>{try{let i=new URL(o.url),a=Pa(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 Go){if(l.method!==s)continue;let c=va(l.pattern,a);if(!c)continue;let p=await Aa(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 po(i);let a=i instanceof Error?i.message:"Internal server error";return R(500,{error:"internal_error",message:a})}}}function Ia(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 Sa(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 Jo(e,n){let t=Se(e,n);return async(r,o,i)=>{try{let a=await t(Ia(r));await Sa(o,a)}catch(a){i(a)}}}function zo(e,n){let t=Se(e,n);return r=>t(r.req.raw)}function Vo(e,n){let t=Se(e,n);return{GET:t,POST:t,OPTIONS:t}}function Yo(e){let n={[an]:e};return{ok:Dn,tenants:{list:()=>Fe(e),create:t=>Hn(e,t),get:t=>Mn(e,t)},plugins:{list:()=>He(e),get:t=>On(e,t)},connectionStatus:{get:t=>Fn(e,t?.tenantId)},permissions:{get:t=>ko(e,t)},connect:{createLink:t=>Un(n,e,t),resolve:t=>Bn(n,e,t),oauthCallback:t=>Nn(n,e,t)}}}async function Qo(e,n,t,r,o="pending"){if(!e)return null;try{let i=Rr(),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 Ra(e,n,t,r="pending"){try{let o=await e.$getAccountId();return Qo(e.database,o,n,t,r)}catch(o){return console.warn("Failed to log event:",o),null}}import*as Xo from"https";import*as nt from"querystring";var Ea=["expires_in","refresh_token_expires_in"];function _a(e){try{return JSON.parse(e)}catch{}if(!e.includes("="))return null;let n=nt.parse(e);if(!n.access_token&&!n.error)return null;let t={...n};for(let r of Ea)typeof n[r]=="string"&&(t[r]=Number(n[r]));return t}function tt(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=nt.stringify(l),p={"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json","Content-Length":Buffer.byteLength(c).toString()};a&&(p.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let g=Xo.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}let y=_a(f);y?s(y):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 ei=" ";function Z(e){let n=e;return n._def??n.def??{}}function G(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 q(e){return e.innerType??e.schema??e.out??e.in}function ti(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 q(e)}}function ri(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function ot(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 oi(e,n){return e.description??n.description}function Da(e){let n=e;for(;n;){let t=Z(n),r=oi(n,t);if(r)return r;let o=G(t);if(Cr(o)||o==="ZodPipe"||o==="ZodEffects"||o==="ZodTransform"){n=ti(t,o);continue}break}}function Cr(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function F(e){let n=Z(e),t=G(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=q(n);return r?F(r):"unknown"}case"ZodNullable":{let r=q(n);return`${r?F(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=q(n);return r?F(r):"unknown"}case"ZodArray":{let r=ri(n);if(!r)return"unknown[]";let o=Z(r),i=G(o)==="ZodUnion",a=F(r);return`${i?`(${a})`:a}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=ot(e,n),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([a,s])=>{let u=G(Z(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=ti(n,t);return r?F(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function ue(e){let n=Z(e),t=G(n),r=oi(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=q(n),i=o?ue(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodNullable":{let o=q(n),i=o?ue(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodDefault":case"ZodCatch":{let o=q(n);return o?{...ue(o),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let o=ri(n);return{kind:"array",optional:!1,description:r,items:o?ue(o):{kind:"unknown",optional:!1}}}case"ZodObject":{let o=ot(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=Z(i);if(G(a)==="ZodObject")return{...ue(i),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let o=q(n);return o?{...ue(o),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function pg(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 wr=["equals","contains","startsWith","endsWith","in"],Oa=["equals","gt","gte","lt","lte","in"],Ma=["equals"],Ha=["equals","before","after","between"];function ii(e){let n=Z(e);switch(G(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=q(n);return r?ii(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Tr(e){let n=Z(e),t=G(n);if(Cr(t)){let i=q(n);return i?Tr(i):{}}if(t!=="ZodObject")return{};let r=ot(e,n),o={};for(let[i,a]of Object.entries(r)){let s=ii(a);s==="string"?o[i]={type:"string",operators:wr}:s==="number"?o[i]={type:"number",operators:Oa}:s==="boolean"?o[i]={type:"boolean",operators:Ma}:s==="date"&&(o[i]={type:"date",operators:Ha})}return o}function si(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function hr(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"&&hr(o,i,t)}}function kr(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function br(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];kr(o)?t.push(i.join(".")):o!==null&&typeof o=="object"&&br(o,i,t)}}function vr(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 kr(a)?[i]:null;if(a!==null&&typeof a=="object"&&!kr(a)){let s=vr(a,r);if(s!==null)return[i,...s]}return null}function ai(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 Fa=new Set(dn);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 Fa.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 br(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 hr(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=[];br(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=[];hr(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 Ua(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 mr(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 gg(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=si(f,g);if(y){let[m,h]=y,T=Tr(h),C=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${wr.join(", ")}]`];for(let[E,k]of Object.entries(T))C.push(` ${E}?: ${k.type} [${k.operators.join(", ")}]`);return C.push("}"),C.join(`
30
+ `)}}}return mr(Re(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let c=i.slice(9);if(a.webhooks){let p=vr(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 ${rt(We(d.payload))}`),f&&y.push(`response: ${f}`),y.push(`usage:
31
+ ${ai(o,p)}`),y.join(`
32
+
33
+ `)}}return mr(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 ${rt(We(l.input))}`),l?.output&&c.push(`output ${rt(We(l.output))}`),c.join(`
34
+
35
+ `)}}}return mr(Re(e),"Path not found. Available operations")}function ni(e){let n=e;for(;;){let t=Z(n),r=G(t);if(Cr(r)){let o=q(t);if(!o)return n;n=o;continue}return n}}function We(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=ni(e),t=Z(n);if(G(t)==="ZodObject"){let o=ot(n,t),i=[];for(let[a,s]of Object.entries(o)){let u=Z(s),l=G(u),c=l==="ZodOptional"||l==="ZodNullable",p=ni(s),g=Da(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 rt(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=ei.repeat(n+1),r=ei.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 Ba(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}=Ua(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:We(f?.input),output:We(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=vr(r.webhooks,f.split("."));if(y===null)continue;let m=y.join("."),h=Ce(r.webhookSchemas,m.toLowerCase()),T=h?.response?F(h.response):void 0;i.push({path:c,description:h?.description,payload:We(h?.payload),responseType:T,usageExample:ai(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 T=si(l,m);if(!T)continue;let[C,E]=T,k=Tr(E),b=Object.entries(k).map(([v,x])=>({field:v,type:x.type,operators:x.operators}));s.push({path:c,entityName:C,filters:[{field:"entity_id",type:"string",operators:wr},...b]})}return s.sort((c,p)=>c.path.localeCompare(p.path)),{ok:!0,data:{pluginId:n,api:o,webhooks:i,db:s}}}function ui(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function Na(e,n){let t=ui(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 La(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function ci(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function li(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 un(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function $a(e){return un(e.body)}function di(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return it(Array.isArray(r)?r:[r])}function pi(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let u of t){let l=it(Array.isArray(u)?u:[u]);if(l)return decodeURIComponent(l)}let r=di({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=un(typeof i=="string"?(()=>{try{return JSON.parse(i)}catch{return i}})():i);return it([a?.validationToken])??null}function Wa(e){if(pi(e))return!0;let n=un(e.body??e.payload);return ci(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function it(e){for(let n of e){let t=li(n);if(t)return t}}function ja(e){let t=un(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var an=Symbol.for("corsair:internal");function Qr(e){let n=e.database?Pr(e.database):void 0,t=n&&e.kek?qo(e.plugins,n,e.kek):et(!!n,!!e.kek),r=Zo(e),o={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?pn(e.hub):void 0},i=co(n),a=Yo(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=yr(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,{[an]:o})},keys:t,permissions:i,manage:a},{[an]:o});let s=yr(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,[an]:o})}var U=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function gi(e){let n=e.oauthConfig;if(!n)throw new U("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function Ka(e,n,t,r){let o=_r(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 pt(e,n,t){let{tenantId:r,redirectUri:o,hubConnect:i=!1}=t,a=w(e,()=>new U("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 U("plugin_not_found",g)),u=gi(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(ve({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:ve({oauthConfig:u,clientId:c,redirectUri:o,state:p}),state:p}}async function sn(e,n){let{code:t,state:r,redirectUri:o}=n,i=w(e,()=>new U("invalid_corsair_instance","Invalid corsair instance")),a,s;if(n.trusted){if(!n.plugin||!n.tenantId)throw new U("invalid_state","trusted callback requires plugin and tenantId");a=n.plugin,s=n.tenantId}else{let y=Sn(r,i.kek);if(!y)throw new U("invalid_state","Invalid or tampered state parameter");a=y.plugin,s=y.tenantId}if(!i.database)throw new U("no_database","No database configured on corsair instance");let u=H(i,a,y=>new U("plugin_not_found",y)),l=gi(u),c=S({authType:"oauth_2",integrationName:a,kek:i.kek,database:i.database}),p=await c.get_client_id(),g=await c.get_client_secret();if(!p||!g)throw new U("credentials_not_configured",`Credentials not configured for '${a}'`);await Ka(i.database,a,s,i.kek);let d=await tt(t,p,g,l,o);if(!d.access_token)throw new U("no_access_token",`No access_token returned from ${l.providerName}`);let f=_({authType:"oauth_2",integrationName:a,tenantId:s,kek:i.kek,database:i.database});await f.set_access_token(d.access_token),d.refresh_token&&await f.set_refresh_token(d.refresh_token),d.expires_in&&await f.set_expires_at(String(Math.floor(Date.now()/1e3)+d.expires_in));try{let y=await Gn(i.plugins,a,d);if(y){try{let m=u.authConfig?.oauth_2?.account??[];await Be({database:i.database,kek:i.kek,pluginId:a,tenantId:s,link:y,authType:"oauth_2",extraAccountFields:m})}catch(m){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${a}' tenant '${s}':`,m)}i.hub&&Ne(i.hub,{plugin:a,tenantId:s,link:y,authType:"oauth_2"})}}catch(y){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${a}' tenant '${s}':`,y)}return{plugin:a,tenantId:s}}export{Dr as a,de as b,qe as c,pe as d,pn as e,N as f,gn as g,Ee as h,fn as i,yn as j,mn as k,hn as l,Mr as m,kn as n,ge as o,re as p,oe as q,j as r,ut as s,Ge as t,fe as u,ie as v,Je as w,S as x,_ as y,qr as z,Zr as A,ye as B,yt as C,Ne as D,Be as E,Ut as F,Jn as G,So as H,ve as I,U as J,pt as K,sn as L,An as M,ts as N,xn as O,Hu as P,gt as Q,Fu as R,to as S,ft as T,In as U,oo as V,io as W,ht as X,Rn as Y,En as Z,he as _,Pe as $,Ln as aa,St as ba,Ue as ca,$n as da,Rt as ea,Wn as fa,jn as ga,Ye as ha,Et as ia,_t as ja,Mt as ka,Ht as la,Po as ma,Ao as na,ke as oa,Le as pa,Do as qa,ae as ra,Vn as sa,Yn as ta,be as ua,xe as va,rn as wa,on as xa,Qn as ya,$t as za,Wt as Aa,qt as Ba,Zt as Ca,Gt as Da,Jt as Ea,zt as Fa,Ie as Ga,X as Ha,Vt as Ia,Bo as Ja,No as Ka,Yt as La,Qt as Ma,Xt as Na,er as Oa,nr as Pa,tr as Qa,rr as Ra,or as Sa,ir as Ta,sr as Ua,ar as Va,ur as Wa,cr as Xa,lr as Ya,dr as Za,Se as _a,Jo as $a,zo as ab,Vo as bb,Qo as cb,Ra as db,tt as eb,pg as fb,Re as gb,gg as hb,rt as ib,Ba as jb,ui as kb,Na as lb,La as mb,ci as nb,li as ob,un as pb,$a as qb,di as rb,pi as sb,Wa as tb,it as ub,ja as vb,an as wb,Qr as xb};
@@ -1,9 +1,8 @@
1
- import { T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, b as PermissionRecord, c as ConnectLink, d as CreateConnectLinkInput, O as OAuthCallbackResult, e as OAuthCallbackInput } from '../../types-CzXqyIs-.js';
2
- export { f as PermissionLookupInput } from '../../types-CzXqyIs-.js';
3
- import { C as CorsairClientOptions, a as CorsairManagementClient } from '../../types-Cy9zP96e.js';
4
- import '../../index-ggMa1Rj6.js';
1
+ import { T as Tenant, C as CreateTenantInput, P as PluginInfo, a as ConnectionStatus, b as PermissionRecord, c as ConnectLink, d as CreateConnectLinkInput, O as OAuthCallbackResult, e as OAuthCallbackInput } from '../../types-FOY4YYJo.js';
2
+ export { f as PermissionLookupInput } from '../../types-FOY4YYJo.js';
3
+ import { C as CorsairClientOptions, a as CorsairManagementClient } from '../../types-Br272VqS.js';
4
+ import '../../index-eydqYIn0.js';
5
5
  import 'zod';
6
- import '../../constants-CQtdZMk5.js';
7
6
 
8
7
  type AsyncState<T> = {
9
8
  status: 'idle';
@@ -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{S as a,T as b,U as c}from"./chunk-3ELEU4KA.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as createHubConnectSession,b as createHubConnectSessionForPlugin,a as postHubConnectSession};
package/dist/core.d.ts CHANGED
@@ -1,18 +1,16 @@
1
- export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-CY6fUO8K.js';
1
+ export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-WqJfKVqn.js';
2
2
  import { CorsairDatabase } from './db.js';
3
- import { A as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './types-DpJORHx2.js';
4
- export { a as AccountFieldNames, d as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, b as BaseKeyManager, e as Bivariant, c as IntegrationFieldNames, O as OAuth2IntegrationCredentials, P as PluginAuthConfig, U as UnionToIntersection } from './types-DpJORHx2.js';
5
- export { v as BeforeHookResult, B as BindEndpoints, N as BindWebhooks, h as BoundEndpointFn, i as BoundEndpointTree, Q as BoundWebhook, S as BoundWebhookTree, g as CorsairClient, j as CorsairContext, k as CorsairEndpoint, m as CorsairErrorHandler, c as CorsairIntegration, w as CorsairKeyBuilder, x as CorsairKeyBuilderBase, U as CorsairOAuthWebhookTenantLinkResolver, s as CorsairPermissionsNamespace, C as CorsairPlugin, y as CorsairPluginContext, e as CorsairSingleTenantClient, d as CorsairTenantWrapper, V as CorsairWebhook, X as CorsairWebhookHandler, Y as CorsairWebhookMatcher, Z as CorsairWebhookTenantMatcher, z as EndpointHooks, A as EndpointMetaEntry, E as EndpointPathsOf, D as EndpointRiskLevel, l as EndpointTree, t as EnforcePermissionOptions, u as EnforcePermissionResult, n as ErrorContext, o as ErrorHandler, p as ErrorHandlerAndMatchFunction, q as ErrorMatcher, K as KeyBuilderContext, O as OAuthConfig, P as PermissionMode, F as PermissionPolicy, G as PluginEndpointMeta, H as PluginPermissionsConfig, _ as RawWebhookRequest, I as RequiredPluginEndpointMeta, J as RequiredPluginEndpointSchemas, L as RequiredPluginWebhookSchemas, R as RetryStrategies, r as RetryStrategy, T as TokenResponse, M as WebhookHooks, $ as WebhookPathsOf, a0 as WebhookRequest, a1 as WebhookResponse, W as WebhookTenantMatch, a2 as WebhookTree, f as exchangeCodeForTokens } from './index-BwQsXpxI.js';
6
- export { A as AuthMissingError, D as DocSchemaFieldRow, a as DocSchemaShape, b as DocsApiEndpoint, c as DocsDbEntity, d as DocsDbFilterField, e as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, n as extractMicrosoftGraphValidationToken, o as firstString, f as formatDocSchemaShape, p as getHeader, i as introspectPluginForDocs, q as isMicrosoftGraphValidationHandshake, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, t as readQueryParam, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-mRNSoG3k.js';
7
- import { A as AuthTypes } from './constants-CQtdZMk5.js';
8
- export { a as AllProviders, B as BaseProviders, P as PickAuth, b as ProviderDisplayNames, f as formatProviderDisplayName } from './constants-CQtdZMk5.js';
3
+ import { A as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './index-DKIQbeNM.js';
4
+ export { f as AccountFieldNames, i as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, g as BaseKeyManager, D as BeforeHookResult, l as BindEndpoints, a1 as BindWebhooks, $ as Bivariant, m as BoundEndpointFn, n as BoundEndpointTree, a2 as BoundWebhook, a3 as BoundWebhookTree, k as CorsairClient, o as CorsairContext, p as CorsairEndpoint, r as CorsairErrorHandler, c as CorsairIntegration, F as CorsairKeyBuilder, G as CorsairKeyBuilderBase, a4 as CorsairOAuthWebhookTenantLinkResolver, x as CorsairPermissionsNamespace, C as CorsairPlugin, J as CorsairPluginContext, e as CorsairSingleTenantClient, d as CorsairTenantWrapper, a5 as CorsairWebhook, a6 as CorsairWebhookHandler, a7 as CorsairWebhookMatcher, a8 as CorsairWebhookTenantMatcher, K as EndpointHooks, L as EndpointMetaEntry, E as EndpointPathsOf, M as EndpointRiskLevel, q as EndpointTree, y as EnforcePermissionOptions, z as EnforcePermissionResult, s as ErrorContext, t as ErrorHandler, u as ErrorHandlerAndMatchFunction, v as ErrorMatcher, h as IntegrationFieldNames, N as KeyBuilderContext, O as OAuth2IntegrationCredentials, Q as OAuthConfig, S as PermissionMode, U as PermissionPolicy, P as PluginAuthConfig, V as PluginEndpointMeta, W as PluginPermissionsConfig, a9 as RawWebhookRequest, X as RequiredPluginEndpointMeta, Y as RequiredPluginEndpointSchemas, Z as RequiredPluginWebhookSchemas, R as RetryStrategies, w as RetryStrategy, T as TokenResponse, a0 as UnionToIntersection, _ as WebhookHooks, aa as WebhookPathsOf, ab as WebhookRequest, ac as WebhookResponse, ad as WebhookTenantMatch, ae as WebhookTree, j as exchangeCodeForTokens } from './index-DKIQbeNM.js';
5
+ export { A as AuthMissingError, D as DocSchemaFieldRow, a as DocSchemaShape, b as DocsApiEndpoint, c as DocsDbEntity, d as DocsDbFilterField, e as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, j as PluginWebhookMatchers, R as ResolveConnectLinkResult, W as WebhookPluginTenantMatch, k as asRecord, g as collectPluginWebhookMatchers, l as decodePubSubData, n as extractMicrosoftGraphValidationToken, o as firstString, f as formatDocSchemaShape, p as getHeader, i as introspectPluginForDocs, q as isMicrosoftGraphValidationHandshake, m as matchWebhookPlugin, h as matchWebhookPluginAndTenant, s as readBodyRecord, t as readQueryParam, r as resolveConnectLink, u as toExternalId } from './tenant-match-utils-C5Jn0opu.js';
6
+ import { A as AuthTypes } from './types-FOY4YYJo.js';
7
+ export { g as AllProviders, B as BaseProviders, h as PickAuth, j as ProviderDisplayNames, i as formatProviderDisplayName } from './types-FOY4YYJo.js';
9
8
  import 'kysely';
10
- import './index-ggMa1Rj6.js';
9
+ import './index-eydqYIn0.js';
11
10
  import 'zod';
12
11
  import 'pg';
13
12
  import 'postgres';
14
13
  import './orm.js';
15
- import './types-CzXqyIs-.js';
16
14
 
17
15
  /**
18
16
  * Context interface with account ID resolver for logging events.
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,Ha as q,X as p,a,b,cb as r,db as s,eb as t,ib as u,jb as v,kb as w,lb as x,mb as y,nb as z,ob as A,p as d,pb as B,q as e,qb as C,r as f,rb as D,s as g,sb as E,t as h,tb as F,u as i,ub as G,v as j,vb as H,w as k,wb as I,x as l,xb as J,y as m,z as n}from"./chunk-3ELEU4KA.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/db.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Kysely, SqliteDialectConfig } from 'kysely';
2
2
  export { sql } from 'kysely';
3
- import { b as CorsairIntegration, C as CorsairAccount, c as CorsairEntity, d as CorsairEvent, a as CorsairPermission } from './index-ggMa1Rj6.js';
4
- export { n as CorsairAccountInsert, t as CorsairAccountUpdate, f as CorsairAccountsSchema, g as CorsairEntitiesSchema, o as CorsairEntityInsert, u as CorsairEntityUpdate, p as CorsairEventInsert, v as CorsairEventUpdate, h as CorsairEventsSchema, m as CorsairIntegrationInsert, s as CorsairIntegrationUpdate, e as CorsairIntegrationsSchema, j as CorsairPermissionInsert, i as CorsairPermissionsSchema, q as CorsairTableInsert, k as CorsairTableName, l as CorsairTableRow, w as CorsairTableUpdate, r as TableInsertType, T as TableRowType, x as TableUpdateType } from './index-ggMa1Rj6.js';
3
+ import { b as CorsairIntegration, a as CorsairAccount, c as CorsairEntity, d as CorsairEvent, C as CorsairPermission } from './index-eydqYIn0.js';
4
+ export { n as CorsairAccountInsert, t as CorsairAccountUpdate, f as CorsairAccountsSchema, g as CorsairEntitiesSchema, o as CorsairEntityInsert, u as CorsairEntityUpdate, p as CorsairEventInsert, v as CorsairEventUpdate, h as CorsairEventsSchema, m as CorsairIntegrationInsert, s as CorsairIntegrationUpdate, e as CorsairIntegrationsSchema, j as CorsairPermissionInsert, i as CorsairPermissionsSchema, q as CorsairTableInsert, k as CorsairTableName, l as CorsairTableRow, w as CorsairTableUpdate, r as TableInsertType, T as TableRowType, x as TableUpdateType } from './index-eydqYIn0.js';
5
5
  import { Pool } from 'pg';
6
6
  import { Sql } from 'postgres';
7
7
  import 'zod';
package/dist/hub.d.ts CHANGED
@@ -1,10 +1,17 @@
1
- import { A as AuthTypes } from './constants-CQtdZMk5.js';
2
- export { f as formatProviderDisplayName } from './constants-CQtdZMk5.js';
3
- import { g as HubOAuthMode, h as HubConnectSessionResult, i as HubPermissionSessionResult, H as HubConfig, f as HubConfigInput, j as HubConnectSessionInput, k as HubListProjectConnectionsInput, A as AccountKeyManagerFor, l as HubPermissionSessionInput } from './types-DpJORHx2.js';
4
- export { D as DEFAULT_HUB_API_URL, m as HubEnvironmentSlug } from './types-DpJORHx2.js';
5
- import { e as TunnelType, c as ProcessCorsairRequest } from './index-BL_Wze86.js';
6
- export { f as BROWSER_DELIVERY_TTL_MS, g as BrowserDeliveryMode, B as BrowserDeliveryPayload, S as SIGNED_TUNNEL_REPLAY_WINDOW_MS, d as TunnelEnvelope } from './index-BL_Wze86.js';
7
- export { b as buildBrowserDeliveryRedirectUrl, s as signBrowserDeliveryToken, v as verifyBrowserDeliveryToken } from './browser-delivery-S1jgUS7n.js';
1
+ import { A as AuthTypes } from './types-FOY4YYJo.js';
2
+ export { i as formatProviderDisplayName } from './types-FOY4YYJo.js';
3
+ import { ag as HubOAuthMode, ah as HubConnectSessionResult, ai as HubPermissionSessionResult, H as HubConfig, aj as HubConfigInput, ak as HubConnectSessionInput, al as HubListProjectConnectionsInput, A as AccountKeyManagerFor, am as HubPermissionSessionInput } from './index-DKIQbeNM.js';
4
+ export { an as DEFAULT_HUB_API_URL, ao as HubEnvironmentSlug } from './index-DKIQbeNM.js';
5
+ import { g as TunnelType, c as ProcessCorsairRequest, h as WebhookTenantLink } from './index-CXpDAEOf.js';
6
+ export { i as BROWSER_DELIVERY_TTL_MS, j as BrowserDeliveryMode, B as BrowserDeliveryPayload, S as SIGNED_TUNNEL_REPLAY_WINDOW_MS, f as TunnelEnvelope } from './index-CXpDAEOf.js';
7
+ export { b as buildBrowserDeliveryRedirectUrl, s as signBrowserDeliveryToken, v as verifyBrowserDeliveryToken } from './browser-delivery-DE71IK5C.js';
8
+ import './index-eydqYIn0.js';
9
+ import 'zod';
10
+ import './db.js';
11
+ import 'kysely';
12
+ import 'pg';
13
+ import 'postgres';
14
+ import './orm.js';
8
15
 
9
16
  type ConnectAuthKind = 'oauth' | 'api_key' | 'bot_token';
10
17
  type ConnectPluginManifestEntry = {
@@ -331,9 +338,25 @@ declare function processManagedOAuthDelivery(corsair: unknown, options: ProcessM
331
338
  declare function createHubPermissionSession(hub: HubConfig, input: HubPermissionSessionInput): Promise<HubPermissionSessionResult>;
332
339
  declare function formatHubApprovalMessage(approvalUrl: string): string;
333
340
 
341
+ /**
342
+ * Forwards a resolved webhook tenant link to Hub (fire-and-forget). Called after
343
+ * OAuth completes (email-style links) and after a watch/subscription is created
344
+ * (channel_id / subscription_id). No-op unless Hub is configured.
345
+ */
346
+ declare function registerHubWebhookTenantLink(hub: HubConfig, input: {
347
+ plugin: string;
348
+ tenantId: string;
349
+ link: WebhookTenantLink;
350
+ authType?: AuthTypes;
351
+ }): Promise<void>;
352
+
353
+ /**
354
+ * One knob: `CORSAIR_DELIVERY_URL` (full endpoint, wins over everything).
355
+ * Without it, auto-detects `http://localhost:{PORT}/api/corsair` — PORT is
356
+ * set by the runtime, not something users configure for Corsair.
357
+ */
334
358
  declare function resolveHubDeliveryUrl(input?: {
335
359
  deliveryUrl?: string;
336
- deliveryPath?: string;
337
360
  }): string;
338
361
 
339
362
  declare function createHubRouteHandlers(corsair: unknown): {
@@ -490,4 +513,4 @@ declare function decodePermissionTokenFromPath(encoded: string): string;
490
513
  */
491
514
  declare function createSignedTokenJti(): string;
492
515
 
493
- export { type ConnectAuthFieldStatus, type ConnectAuthKind, type ConnectAuthStatusLevel, type ConnectPluginManifestEntry, type ConnectSessionTokenPayload, type ConnectStatusPluginEntry, type ConnectStatusResponse, type ConnectTokenPayload, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, type FormatServerDeliveryErrorInput, HubConfig, HubConfigInput, HubConnectSessionInput, HubConnectSessionResult, type HubDeliveryRequest, type HubDeliveryResult, HubListProjectConnectionsInput, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, HubPermissionSessionInput, HubPermissionSessionResult, type HubProjectConnection, type ManagedAccessTokenResult, type ManagedAuthContext, ManagedOAuthDeliveryError, type PermissionTokenPayload, type ProcessManagedOAuthDeliveryOptions, type ProcessManagedOAuthDeliveryResult, type ServerDeliveryAckBody, type SignedDeliveryHeaders, type SignedEnvelopeDeliveryResult, TunnelType, attachManagedRefreshAuth, createConnectSessionJti, createConnectTokenJti, createHubConnectSession, createHubPermissionSession, createHubRouteHandlers, createPermissionSessionJti, createSignedTokenJti, decodeConnectSessionTokenFromPath, decodeConnectTokenFromPath, decodePermissionTokenFromPath, deliverSignedEnvelope, describeDeliveryNetworkError, encodeConnectTokenForPath, extractSyncFromDeliveryAck, formatHubApprovalMessage, formatServerDeliveryError, getConnectSessionExpiryMs, getConnectStatusForTenant, getConnectTokenExpiryMs, getHubConfig, getManagedAccessToken, handleHubDeliveryGet, handleHubDeliveryPost, handleHubDeliveryRequest, hubDeliveryToResponse, inferHubEnvironmentSlug, isLoopbackUrl, isServerDeliveryAckSuccessful, listHubProjectConnections, normalizeHubConfig, parseConnectSessionResponse, parseConnectStatusResponse, parseHubApiErrorBody, parseOAuthRefreshResponse, parsePermissionSessionResponse, parseProjectConnectionsResponse, parseServerDeliveryAckBody, parseSyncFromDeliveryBody, processManagedOAuthDelivery, resolveDeliveryTransport, resolveHubDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, signConnectSessionToken, signConnectToken, signDeliveryEnvelope, signPermissionToken, usesBrowserDelivery, validateProductionDeliveryUrl, verifyConnectSessionToken, verifyConnectToken, verifyDeliveryEnvelope, verifyPermissionToken, verifySignedTunnelDelivery };
516
+ export { type ConnectAuthFieldStatus, type ConnectAuthKind, type ConnectAuthStatusLevel, type ConnectPluginManifestEntry, type ConnectSessionTokenPayload, type ConnectStatusPluginEntry, type ConnectStatusResponse, type ConnectTokenPayload, type CreateConnectSessionRequestBody, type CreatePermissionSessionRequestBody, type FormatServerDeliveryErrorInput, HubConfig, HubConfigInput, HubConnectSessionInput, HubConnectSessionResult, type HubDeliveryRequest, type HubDeliveryResult, HubListProjectConnectionsInput, HubNotConfiguredError, HubOAuthMode, type HubOAuthRefreshResponse, HubPermissionSessionInput, HubPermissionSessionResult, type HubProjectConnection, type ManagedAccessTokenResult, type ManagedAuthContext, ManagedOAuthDeliveryError, type PermissionTokenPayload, type ProcessManagedOAuthDeliveryOptions, type ProcessManagedOAuthDeliveryResult, type ServerDeliveryAckBody, type SignedDeliveryHeaders, type SignedEnvelopeDeliveryResult, TunnelType, attachManagedRefreshAuth, createConnectSessionJti, createConnectTokenJti, createHubConnectSession, createHubPermissionSession, createHubRouteHandlers, createPermissionSessionJti, createSignedTokenJti, decodeConnectSessionTokenFromPath, decodeConnectTokenFromPath, decodePermissionTokenFromPath, deliverSignedEnvelope, describeDeliveryNetworkError, encodeConnectTokenForPath, extractSyncFromDeliveryAck, formatHubApprovalMessage, formatServerDeliveryError, getConnectSessionExpiryMs, getConnectStatusForTenant, getConnectTokenExpiryMs, getHubConfig, getManagedAccessToken, handleHubDeliveryGet, handleHubDeliveryPost, handleHubDeliveryRequest, hubDeliveryToResponse, inferHubEnvironmentSlug, isLoopbackUrl, isServerDeliveryAckSuccessful, listHubProjectConnections, normalizeHubConfig, parseConnectSessionResponse, parseConnectStatusResponse, parseHubApiErrorBody, parseOAuthRefreshResponse, parsePermissionSessionResponse, parseProjectConnectionsResponse, parseServerDeliveryAckBody, parseSyncFromDeliveryBody, processManagedOAuthDelivery, registerHubWebhookTenantLink, resolveDeliveryTransport, resolveHubDeliveryUrl, resolveHubOAuthCallbackUrl, respondToHubDelivery, respondToHubDeliveryFromRequest, signConnectSessionToken, signConnectToken, signDeliveryEnvelope, signPermissionToken, usesBrowserDelivery, validateProductionDeliveryUrl, verifyConnectSessionToken, verifyConnectToken, verifyDeliveryEnvelope, verifyPermissionToken, verifySignedTunnelDelivery };
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as 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,Ba as Q,Ca as R,D as o,Da as S,Ea as T,Fa as U,Ga 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,Ta as fa,U as p,Ua as ga,V as q,Va as ha,W as r,Wa as ia,Xa as ja,Y as s,Ya as ka,Z as t,Za as la,_ 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,pa as L,ra as M,sa as N,ta as O,ua as P}from"./chunk-3ELEU4KA.js";import"./chunk-BPFUYXOD.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{u as BROWSER_DELIVERY_TTL_MS,b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,K as ManagedOAuthDeliveryError,v as SIGNED_TUNNEL_REPLAY_WINDOW_MS,X as attachManagedRefreshAuth,N as buildBrowserDeliveryRedirectUrl,Z as createConnectSessionJti,ca as createConnectTokenJti,p as createHubConnectSession,s as createHubPermissionSession,Y as createHubRouteHandlers,ia as createPermissionSessionJti,M as createSignedTokenJti,ba as decodeConnectSessionTokenFromPath,ha as decodeConnectTokenFromPath,la as decodePermissionTokenFromPath,F as deliverSignedEnvelope,D as describeDeliveryNetworkError,ga as encodeConnectTokenForPath,B as extractSyncFromDeliveryAck,t as formatHubApprovalMessage,a as formatProviderDisplayName,E as formatServerDeliveryError,_ as getConnectSessionExpiryMs,q as getConnectStatusForTenant,da as getConnectTokenExpiryMs,e as getHubConfig,W as getManagedAccessToken,Q as handleHubDeliveryGet,R as handleHubDeliveryPost,T as handleHubDeliveryRequest,S as hubDeliveryToResponse,g as inferHubEnvironmentSlug,G as isLoopbackUrl,A as isServerDeliveryAckSuccessful,r as listHubProjectConnections,d as normalizeHubConfig,h as parseConnectSessionResponse,l as parseConnectStatusResponse,m as parseHubApiErrorBody,k as parseOAuthRefreshResponse,j as parsePermissionSessionResponse,i as parseProjectConnectionsResponse,z as parseServerDeliveryAckBody,C as parseSyncFromDeliveryBody,L as processManagedOAuthDelivery,o as registerHubWebhookTenantLink,H as resolveDeliveryTransport,n as resolveHubDeliveryUrl,f as resolveHubOAuthCallbackUrl,U as respondToHubDelivery,V as respondToHubDeliveryFromRequest,O as signBrowserDeliveryToken,$ as signConnectSessionToken,ea as signConnectToken,w as signDeliveryEnvelope,ja as signPermissionToken,I as usesBrowserDelivery,J as validateProductionDeliveryUrl,P as verifyBrowserDeliveryToken,aa as verifyConnectSessionToken,fa as verifyConnectToken,x as verifyDeliveryEnvelope,ka as verifyPermissionToken,y as verifySignedTunnelDelivery};
@@ -1,3 +1,8 @@
1
+ import { A as AuthTypes } from './types-FOY4YYJo.js';
2
+ import { ad as WebhookTenantMatch } from './index-DKIQbeNM.js';
3
+ import { a as CorsairAccount } from './index-eydqYIn0.js';
4
+ import { CorsairDatabase } from './db.js';
5
+
1
6
  /**
2
7
  * Shared wire-format types for hub ↔ app delivery (browser and server transports).
3
8
  */
@@ -78,6 +83,44 @@ declare const BROWSER_DELIVERY_TTL_MS: number;
78
83
  /** Max age of a server delivery request timestamp (5 minutes). */
79
84
  declare const SIGNED_TUNNEL_REPLAY_WINDOW_MS: number;
80
85
 
86
+ type WebhookTenantLink = WebhookTenantMatch;
87
+ declare function setWebhookTenantLink(options: {
88
+ database: CorsairDatabase;
89
+ kek: string;
90
+ pluginId: string;
91
+ tenantId: string;
92
+ link: WebhookTenantLink;
93
+ authType?: AuthTypes;
94
+ extraAccountFields?: readonly string[];
95
+ }): Promise<void>;
96
+ type ResolveAccountFromWebhookLinkInput = {
97
+ database: CorsairDatabase;
98
+ kek: string;
99
+ pluginId: string;
100
+ linkType: string;
101
+ externalId: string;
102
+ };
103
+ /**
104
+ * Resolves the matching corsair_accounts row for a webhook tenant link.
105
+ *
106
+ * Runs one SQL query scoped to the plugin, then decrypts only the requested
107
+ * link field per account using the account DEK and KEK.
108
+ */
109
+ declare function resolveAccountFromWebhookLink(options: ResolveAccountFromWebhookLinkInput): Promise<CorsairAccount | null>;
110
+ declare function resolveTenantIdFromWebhookLink(options: {
111
+ database: CorsairDatabase;
112
+ kek: string;
113
+ pluginId: string;
114
+ linkType: string;
115
+ externalId: string;
116
+ }): Promise<string | null>;
117
+ declare function resolveTenantFromWebhookLink(options: {
118
+ database: CorsairDatabase;
119
+ kek: string;
120
+ pluginId: string;
121
+ match: WebhookTenantMatch;
122
+ }): Promise<string | null>;
123
+
81
124
  type TunnelAck = {
82
125
  status: 'ok' | 'failed';
83
126
  retryable?: boolean;
@@ -107,6 +150,13 @@ type OAuthCallbackTunnelPayload = {
107
150
  code: string;
108
151
  state: string;
109
152
  redirectUri: string;
153
+ /**
154
+ * Set by Hub, which authenticates the delivery envelope with the signing
155
+ * secret and cannot sign a Corsair `state`. When present, the callback is
156
+ * processed against these instead of decoding `state`.
157
+ */
158
+ plugin?: string;
159
+ tenantId?: string;
110
160
  };
111
161
  type OAuthTokensTunnelPayload = {
112
162
  plugin: string;
@@ -129,4 +179,4 @@ type ProcessCorsairOptions = {
129
179
  };
130
180
  declare function processCorsair(corsair: unknown, request: ProcessCorsairRequest, options?: ProcessCorsairOptions): Promise<TunnelAck>;
131
181
 
132
- export { type BrowserDeliveryPayload as B, type OAuthCallbackTunnelPayload as O, type ProcessCorsairOptions as P, SIGNED_TUNNEL_REPLAY_WINDOW_MS as S, type TunnelAck as T, type WebhookTunnelPayload as W, applyPermissionDecision as a, type OAuthTokensTunnelPayload as b, type ProcessCorsairRequest as c, type TunnelEnvelope as d, type TunnelType as e, BROWSER_DELIVERY_TTL_MS as f, type BrowserDeliveryMode as g, processCorsair as p };
182
+ export { type BrowserDeliveryPayload as B, type OAuthCallbackTunnelPayload as O, type ProcessCorsairOptions as P, type ResolveAccountFromWebhookLinkInput as R, SIGNED_TUNNEL_REPLAY_WINDOW_MS as S, type TunnelAck as T, type WebhookTunnelPayload as W, applyPermissionDecision as a, type OAuthTokensTunnelPayload as b, type ProcessCorsairRequest as c, resolveTenantFromWebhookLink as d, resolveTenantIdFromWebhookLink as e, type TunnelEnvelope as f, type TunnelType as g, type WebhookTenantLink as h, BROWSER_DELIVERY_TTL_MS as i, type BrowserDeliveryMode as j, processCorsair as p, resolveAccountFromWebhookLink as r, setWebhookTenantLink as s };