corsair 0.1.80 → 0.1.81

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.
@@ -2,7 +2,7 @@ import{a as ie,b as ot,c as P,d as B,e as it,f as z,g as U,h as se,i as Re,j as
2
2
  `)}function Cn(e,n,t){let r=t==="integration"?e.authConfig?.[n]?.integration??[]:e.authConfig?.[n]?.account??[];return new Set([...U[n][t],...r])}function $r(e,n){if(!e)return!1;for(let[t,r]of Object.entries(e)){let o=n.find(a=>a.id===t);if(!o)continue;let i=se(o);if(!i)continue;let s=Cn(o,i,"account");for(let a of Object.keys(r))if(s.has(a))return!0}return!1}function Fr(e,n,t){let r=it(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&&$r(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 mt(e,n){return ie(e)?n===0?!0:Object.values(e).every(t=>mt(t,n-1)):!1}function Br(e){return mt(e,4)}var Ur={...at};function We(e){if(e instanceof Er){let n={};for(let[t,r]of Object.entries(e.shape))n[t]=r instanceof Mr?We(r):"unknown";return n}return e instanceof Sr?`${We(e.unwrap())} | null`:e instanceof Or?`${We(e.unwrap())} | undefined`:e instanceof Ir?e.options.join(" | "):e instanceof Hr?"string":e instanceof _r?"number":e instanceof Rr?"boolean":e instanceof vr?"date":e instanceof Dr?"jsonb":"unknown"}async function Nr(e,n){let t=await e.introspection.getTables(),r=new Set(t.map(o=>o.name));for(let[o,i]of Object.entries(Ur))r.has(o)||n(`[corsair:setup] Table "${o}" does not exist. Run your database migrations before calling setupCorsair.
3
3
  Schema: ${JSON.stringify(We(i),null,2)}`)}async function Wr(e,n,t,r,o){let i=new Date,s=new Map;for(let a of n.plugins){let c=a.id,d=se(a),l=await e.selectFrom("corsair_integrations").selectAll().where("name","=",c).executeTakeFirst();if(!l){let f=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:f,name:c,config:{},created_at:i,updated_at:i}).execute(),l=await e.selectFrom("corsair_integrations").selectAll().where("id","=",f).executeTakeFirst(),o(`[corsair:setup] Created integration: ${c}`)}let u=d?a.authConfig?.[d]?.integration??[]:[],g=d?a.authConfig?.[d]?.account??[]:[],y=d&&l?D({authType:d,integrationName:c,kek:n.kek,database:n.database,extraIntegrationFields:u}):void 0;if(l&&!l.dek&&y&&(await y.issue_new_dek(),o(`[corsair:setup] Issued integration DEK: ${c}`)),!l||!d||!y)continue;let p;if(r){let f=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",l.id).executeTakeFirst();if(!f){let h=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:h,tenant_id:t,integration_id:l.id,config:{},created_at:i,updated_at:i}).execute(),f=await e.selectFrom("corsair_accounts").selectAll().where("id","=",h).executeTakeFirst(),o(`[corsair:setup] Created account: ${c}`)}p=f&&I({authType:d,integrationName:c,tenantId:t,kek:n.kek,database:n.database,extraAccountFields:g}),f&&p&&!f.dek&&(await p.issue_new_dek(),o(`[corsair:setup] Issued account DEK: ${c}`))}s.set(c,{pluginId:c,authType:d,integration:y,account:p,integrationFields:[...U[d].integration,...u],accountFields:r?[...U[d].account,...g]:[]})}return s}function Lr(e){if(!ie(e))return;let n=e.keys;return ie(n)?n:void 0}function jr(e,n){return"withTenant"in e&&typeof e.withTenant=="function"?e.withTenant(n):e}async function Kr(e,n,t,r,o,i){let s=Lr(e),a=n.provisionAccounts?jr(e,n.tenantId):void 0;for(let[c,d]of Object.entries(t)){let l=r.plugins.find(m=>m.id===c);if(!l){i(`[corsair:setup] Unknown plugin '${c}' \u2014 skipping credentials.`);continue}let u=se(l);if(!u){i(`[corsair:setup] Plugin '${c}' has no auth type \u2014 skipping credentials.`);continue}let g=Cn(l,u,"integration"),y=Cn(l,u,"account"),p=s?.[c],f=a?.[c],h=ie(f)?f.keys:void 0;for(let[m,C]of Object.entries(d))if(C){if(g.has(m)){if(n.multiTenant&&n.tenantIdProvided)throw new Error(`[corsair:setup] '${c}.${m}' is an integration-level credential shared across all tenants. You passed tenantId="${n.tenantId}", which only scopes account-level credentials. Run setup without --tenant if you intend to change this credential globally.`);let b=z(p,`set_${m}`);if(!b){i(`[corsair:setup] Cannot set integration field '${m}' for '${c}'.`);continue}await b(C),o(`[corsair:setup] Set ${c} integration.${m}`);continue}if(y.has(m)){if(n.multiTenant&&!n.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${c}.${m}' on a multi-tenant instance`);let b=z(h,`set_${m}`);if(!b){i(`[corsair:setup] Cannot set account field '${m}' for '${c}'.`);continue}await b(C),o(`[corsair:setup] Set ${c} account.${m} (tenant=${n.tenantId})`);continue}i(`[corsair:setup] Unknown credential field '${m}' for plugin '${c}'.`)}}}var yt=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function Zr(e,n,t,r,o,i,s,a,c){let d=[],l=[];for(let g of o){if(yt.has(g))continue;let y=z(t,`get_${g}`);if(!y)continue;let p=null;try{let f=await y();p=typeof f=="string"?f:null}catch{}p||d.push(g)}if(r&&i.length>0)for(let g of i){if(yt.has(g))continue;let y=z(r,`get_${g}`);if(!y)continue;let p=null;try{let f=await y();p=typeof f=="string"?f:null}catch{}p||l.push(g)}let u=d.length===0&&l.length===0;if(u)a(`[corsair:setup] '${e}' (${n}) is configured \u2713`);else{let g=[...d,...l];if(c==="cli"){let y=g.map(p=>`${p}=VALUE`).join(" ");a(`[corsair:setup] '${e}' (${n}) needs credentials. Run:
4
4
  corsair setup --${e} ${y}`)}else{let y=[`[corsair:setup] '${e}' (${n}) needs credentials. Call:`];for(let p of d)y.push(` await corsair.keys.${e}.set_${p}(value)`);for(let p of l){let f=s.provisionAccounts?s.tenantId==="default"?`corsair.${e}`:`corsair.withTenant(${JSON.stringify(s.tenantId)}).${e}`:`corsair.withTenant(<tenant>).${e}`;y.push(` await ${f}.keys.set_${p}(value)`)}a(y.join(`
5
- `))}}return u}async function qr(e,n,t,r){let o=new Set;for(let i of e.values())await Zr(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function Gr(e,n,t,r,o){if(!Br(wn)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=wn,s=new Set(n.map(a=>a.id));for(let[a,c]of Object.entries(i)){if(!s.has(a))continue;if(!t.has(a)){r(`[corsair:setup] Skipping backfill for '${a}' \u2014 auth not configured.`);continue}let d=ie(e)?e[a]:void 0,l=ie(d)?d.api:void 0;if(l)for(let[u,g]of Object.entries(c))for(let[y,p]of Object.entries(g)){r(`[corsair:setup] Backfilling ${a} \u203A ${u}.${y}...`);try{let f=ie(l)?l[u]:void 0;await z(f,y)?.(p)}catch(f){o(`[corsair:setup] ${a} \u203A ${u}.${y} failed: `+(f instanceof Error?f.message:String(f)))}}}}async function we(e,n){if(!P(e).database)throw new Error("A database must be configured to provision Corsair for connect");await ht(e,{tenantId:n})}var bt=new Set(["webhook_signature","expires_at","scope"]);function zr(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}async function Jr(e,n,t,r){let o=Re(n,t).filter(c=>!bt.has(c));if(o.length===0)return!0;let s=(typeof e.withTenant=="function"?e.withTenant(r):e)[n.id],a=s&&typeof s=="object"&&"keys"in s?s.keys:null;if(!a)return!1;for(let c of o){if((t==="oauth_2"||t==="managed")&&c==="refresh_token")continue;let d=z(a,`get_${c}`);if(!d)continue;let l=null;try{let u=await d();l=typeof u=="string"?u:null}catch{l=null}if(!l)return!1}return!0}function Vr(e,n){return e==="oauth_2"||e==="managed"?[]:n.filter(t=>!bt.has(t))}async function wt(e,n,t={}){let r=P(e),o=M(e),i=Ue(o),s=[],a=t.pluginIds?new Set(t.pluginIds):null;for(let c of r.plugins){if(a&&!a.has(c.id))continue;let d=se(c);if(!d)continue;let l=zr(d),u=ve(c.id),g=await Jr(e,c,d,n),y=Re(c,d),p={plugin:c.id,providerName:u,authKind:l,alreadyConfigured:g};if(l==="oauth"){let h=t.oauthModeOverrides?.[c.id]??(d==="managed"?"managed":"byo");if(p.oauthMode=h,!g)if(h==="managed")p.state=ae(J(c.id,n),r.kek);else try{let m=await Tn(e,c.id,{tenantId:n,redirectUri:i});p.oauthUrl=m.url,p.state=m.state}catch{continue}}else{let f=Vr(d,y);f.length>0&&(p.credentialFields=f)}s.push(p)}return s}function Ct(e,n){let t=M(e);if(n){let r=be({source:n,deliveryUrl:t.deliveryUrl});if(r)throw new Error(r.error);return n}return ke(t.deliveryUrl)}async function Tt(e,n){await we(e,n)}async function Le(e,n){let t=M(e);await Tt(e,n.tenantId);let r=n.plugin?[n.plugin]:void 0,o=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,i=await wt(e,n.tenantId,{pluginIds:r,oauthModeOverrides:o});if(i.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");if(i.filter(c=>!c.alreadyConfigured).length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is already configured for this tenant`:"All plugins are already configured for this tenant");let a=Ct(e,n.source);return me({hub:t,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{tenantId:n.tenantId,deliveryUrl:t.deliveryUrl,source:a,plugins:i},parseResponse:dt})}function Yr(e){if(e==="byo"||e==="managed")return e}function Qr(e){if(e==="client"||e==="server")return e}function Pn(e){let n=e.plugin?.trim(),t=e.tenantId?.trim()||"default",r=Qr(e.source),o=Yr(e.oauthMode),i=e.providerName?.trim();if(e.source!==void 0&&e.source!==null&&String(e.source).trim()!==""&&!r)return{error:'source must be "client" or "server"',status:400};if(e.oauthMode&&!o)return{error:'oauthMode must be "byo" or "managed"',status:400};let s={tenantId:t,oauthMode:o};return n&&(s.plugin=n),r&&(s.source=r),i&&(s.providerName=i),s}function xn(e){let{searchParams:n}=new URL(e),t=n.get("oauthMode");return{plugin:n.get("plugin")??void 0,tenantId:n.get("tenantId")??void 0,source:n.get("source")??void 0,oauthMode:t??void 0,providerName:n.get("providerName")??void 0}}function Xr(e){return{ok:!0,connectUrl:e.connectUrl,token:e.token,projectId:e.projectId,expiresAt:e.expiresAt}}async function eo(e,n,t){if(t?.resolveTenantId){let r=await t.resolveTenantId(e);return r?.trim()?r.trim():{error:"Unauthorized",status:401}}return n.tenantId?.trim()||t?.defaultTenantId?.trim()||"default"}async function An(e,n,t){let o=n.method.toUpperCase()==="GET"?xn(n.url):await n.json().catch(()=>null);if(!o)return{error:"Invalid JSON body",status:400};let i=await eo(n,o,t);if(typeof i!="string")return i;let s=Pn({...o,tenantId:i});if("error"in s)return s;let a=M(e);if(s.source){let l=be({source:s.source,deliveryUrl:a.deliveryUrl,oauthMode:s.oauthMode});if(l)return l}let c={...s,source:s.source??ke(a.deliveryUrl)},d=await Le(e,c);return Xr(d)}async function Rn(e,n,t){try{let r=await An(e,n,t);return"error"in r?Response.json({error:r.error},{status:r.status}):Response.json(r)}catch(r){if(r instanceof V)return Response.json({error:r.message},{status:503});let o=r instanceof Error?r.message:String(r);return Response.json({error:o},{status:500})}}async function je(e,n,t){let r=n.method.toUpperCase();return r!=="GET"&&r!=="POST"?Response.json({error:"Method not allowed"},{status:405}):Rn(e,n,t)}var Y=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function Pt(e,n){let t=P(e,()=>new Y("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Y("no_database","Database not configured");let r=B(t,n.plugin,d=>new Y("plugin_not_found",d)),o=se(r);if(!o)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(o==="oauth_2"||o==="managed")throw new Y("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await we(e,n.tenantId);let i=new Set(Re(r,o)),a=r.authConfig?.[o]?.account??[],c=I({authType:o,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a});for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!i.has(d))throw new Y("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let u=z(c,`set_${d}`);if(!u)throw new Y("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await u(l.trim())}return{plugin:n.plugin,tenantId:n.tenantId}}async function Ke(e,n,t){for(let r of e){if(r.id!==n)continue;let o=r.oauthWebhookTenantLinkResolver;return o?o(t):null}return null}import{createCipheriv as xt,createDecipheriv as At,randomBytes as Ze,scrypt as no}from"crypto";import{promisify as to}from"util";var Rt=to(no),qe="aes-256-gcm",vt=12,Ge=16,ro=16,Ee=32;function Q(){return Ze(Ee).toString("base64")}async function X(e,n){let t=Ze(ro),r=await Rt(n,t,Ee),o=Ze(vt),i=xt(qe,r,o,{authTagLength:Ge}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[t.toString("base64"),o.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function W(e,n){let[t,r,o,i]=e.split(":");if(!t||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),d=Buffer.from(i,"base64"),l=await Rt(n,s,Ee),u=At(qe,l,a,{authTagLength:Ge});return u.setAuthTag(c),Buffer.concat([u.update(d),u.final()]).toString("utf8")}function vn(e,n){let t=Buffer.from(n,"base64"),r=Ze(vt),o=xt(qe,t,r,{authTagLength:Ge}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function Oe(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"),s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),d=At(qe,i,s,{authTagLength:Ge});return d.setAuthTag(a),Buffer.concat([d.update(c),d.final()]).toString("utf8")}function ce(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=vn(o,n);return t}function ee(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Oe(o,n);return t}function De(e,n,t){let r=ee(e,n);return ce(r,t)}function It(e,n,t){let r={};for(let o of t)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await n({[o]:s})};return r}var In=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function D(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,s=[...U[n].integration,...i],a=null,c={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let p=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!p)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:p.id,config:In(p.config),dek:p.dek??null},a},updateIntegration:async p=>{let f=await c.getIntegration();await o.db.updateTable("corsair_integrations").set({...p.config!==void 0?{config:p.config}:{},...p.dek!==void 0?{dek:p.dek}:{},updated_at:new Date}).where("id","=",f.id).execute(),a=null}},d=null,l=async()=>{if(d)return d;let p=await c.getIntegration();if(!p.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return d=await W(p.dek,r),d},u=async()=>{let p=await c.getIntegration(),f=await l(),h=p.config;return!h||Object.keys(h).length===0?{}:ee(h,f)};return{get_dek:l,issue_new_dek:async()=>{let p=await c.getIntegration(),f=Q(),h={};if(p.dek){let C=await W(p.dek,r),b=p.config;b&&Object.keys(b).length>0&&(h=De(b,C,f))}let m=await X(f,r);return await c.updateIntegration({config:h,dek:m}),d=f,f},...It(u,async p=>{let f=await l(),h;try{h=await u()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,b),h={}}let m={...h};for(let[b,k]of Object.entries(p))k===null?delete m[b]:m[b]=k;let C=ce(m,f);await c.updateIntegration({config:C})},s)}}function I(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:s=[]}=e,a=[...U[n].account,...s],c=null,d=null,l=async()=>{if(d)return d;let k=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!k)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return d={id:k.id,config:In(k.config),dek:k.dek??null},d},u={kek:o,integrationName:t,tenantId:r,getIntegration:l,getAccount:async()=>{if(c)return c;let k=await l(),w=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",k.id).executeTakeFirst();if(!w)throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`);return c={id:w.id,config:In(w.config),dek:w.dek??null},c},updateAccount:async k=>{let w=await u.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","=",w.id).execute(),c=null}},g=null,y=null,p=async()=>{if(g)return g;let k=await u.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return g=await W(k.dek,o),g},f=async()=>{if(y)return y;let k=await u.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return y=await W(k.dek,o),y},h=async()=>{let k=await u.getAccount(),w=await p(),T=k.config;return!T||Object.keys(T).length===0?{}:ee(T,w)},m=async()=>{let k=await u.getIntegration(),w=await f(),T=k.config;return!T||Object.keys(T).length===0?{}:ee(T,w)},b={get_dek:p,issue_new_dek:async()=>{let k=await u.getAccount(),w=Q(),T={};if(k.dek){let _=await W(k.dek,o),E=k.config;E&&Object.keys(E).length>0&&(T=De(E,_,w))}let S=await X(w,o);return await u.updateAccount({config:T,dek:S}),g=w,w},...It(h,async k=>{let w=await p(),T;try{T=await h()}catch(E){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,E),T={}}let S={...T};for(let[E,x]of Object.entries(k))x===null?delete S[E]:S[E]=x;let _=ce(S,w);await u.updateAccount({config:_})},a)};return n==="oauth_2"&&(b.get_integration_credentials=async()=>{let k=await m();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),b}async function St(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=Q(),i=await X(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function _t(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 s=Q(),a=await X(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var Et=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function oo(e){let n=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.pluginId).executeTakeFirst();if(!n)throw new Error(`Integration '${e.pluginId}' not found. Run setupCorsair before registering webhook tenant links.`);let t=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",n.id).executeTakeFirst();if(!t)throw new Error(`Account not found for tenant '${e.tenantId}' and integration '${e.pluginId}'.`);return{integrationId:n.id,accountId:t.id}}async function io(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 W(n.dek,e.kek),r=Et(n.config),o={};Object.keys(r).length>0&&(o=ee(r,t)),o[e.link.linkType]=e.link.externalId;let i=ce(o,t);await e.database.db.updateTable("corsair_accounts").set({config:i,updated_at:new Date}).where("id","=",n.id).execute()}async function Ce(e){let{database:n,kek:t,pluginId:r,tenantId:o,link:i,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await oo({database:n,pluginId:r,tenantId:o}),d=!1;if(s){let l=I({authType:s,integrationName:r,tenantId:o,kek:t,database:n,extraAccountFields:a}),u=`set_${i.linkType}`,g=l[u];typeof g=="function"&&(await g(i.externalId),d=!0)}d||await io({database:n,kek:t,accountId:c,link:i})}async function Sn(e){let{database:n,kek:t,pluginId:r,linkType:o,externalId:i}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let c=await W(a.dek,t),l=Et(a.config)[o];if(!l)continue;if(Oe(l,c)===i)return a}catch{continue}return null}async function ze(e){return(await Sn(e))?.tenant_id??null}async function Ot(e){return ze({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var ue=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Te(e,n){let{plugin:t,tenantId:r,accessToken:o,refreshToken:i,expiresIn:s,scope:a}=n;if(!o.trim())throw new ue("no_access_token","Managed OAuth delivery missing access_token");let c=P(e,()=>new ue("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new ue("no_database","No database configured on corsair instance");let d=B(c,t,u=>new ue("plugin_not_found",u));await we(e,r);let l=I({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await l.set_access_token(o),i&&await l.set_refresh_token(i),s&&await l.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await l.set_scope(a);try{let u=await Ke(c.plugins,t,{access_token:o,refresh_token:i,scope:a});if(u)try{let g=d.authConfig?.managed?.account??[];await Ce({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:u,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(u){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,u)}return{plugin:t,tenantId:r}}function so(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Dt(e,n,t=[]){for(let[r,o]of Object.entries(e))if(so(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=Dt(o,n,[...t,r]);if(i)return i}return null}function ao(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function co(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 Ht(e,n,t,r){let o=ao(n),i=typeof t=="string"?JSON.parse(t):t;(!i||typeof i=="object"&&Object.keys(i).length===0)&&o["x-goog-resource-uri"]&&(i=co(o)||i);let a={headers:o,body:i,...r?{query:r}:{}},c=r?.tenantId||"default",d=e.withTenant?e.withTenant(c):e,l=Fe;for(let u of l){let g=d[u];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(a))continue;let y=Dt(g.webhooks,a);if(!y)continue;let p=y.path.join("."),f={payload:i,headers:o,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let h=await y.webhook.handler(f),m=!!Object.keys(h.returnToSender||{})?.length;return{plugin:u,action:p,body:i,response:m?{...h?.returnToSender,success:!0}:{success:!0},...h.responseHeaders&&{responseHeaders:h.responseHeaders}}}catch(h){return console.error(`Error executing webhook handler for ${u}.${p}:`,h),{plugin:u,action:p,body:i,response:{success:!1,error:h instanceof Error?h.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{createHmac as uo,timingSafeEqual as lo}from"crypto";var po=300*1e3;function go(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function _n(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=go(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)>po)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let i=uo("sha256",n).update(e.body).digest("hex");try{if(!lo(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}}import{createHmac as fo,timingSafeEqual as yo}from"crypto";function Je(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function Ve(e){return e.deliveryMode==="oauth.tokens"||typeof e.accessToken=="string"&&e.accessToken.length>0}function Mt(e){let n=e.trim();return n.length>0?n:null}function ho(e,n){let t=Mt(n);if(!t)throw new Error("Signing secret is required for browser delivery tokens");return fo("sha256",t).update(e).digest("base64url")}function Ye(e,n){let t=Mt(n);if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[o,i]=r;if(!o||!i)return null;let s=ho(o,t);try{if(!yo(Buffer.from(i,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function $t(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 mo(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 ze({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function ko(e,n,t){let r=await mo(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await Ht(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 s=i.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(i.response?.data??i.response);return{status:"ok",webhookResponse:{status:i.response?.statusCode??200,body:a,headers:i.responseHeaders}}}async function bo(e,n){return await He(e,n),{status:"ok"}}async function wo(e,n){return await Te(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function On(e,n,t){let r=await En(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function En(e,n,t){let r=P(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(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",o).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<i?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Co(e,n){try{return await Pt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function Dn(e,n,t={}){let r=P(e),o=$t(n.headers,"x-corsair-signature"),i=$t(n.headers,"x-corsair-timestamp");if(t.signingSecret?.trim()){let a=_n({body:n.body,signatureHeader:o,timestampHeader:i,signingSecret:t.signingSecret});if(!a.ok)return{status:"failed",retryable:!1,error:a.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(s.type){case"webhook":return ko(e,r,s.payload);case"oauth.callback":return bo(e,s.payload);case"oauth.tokens":return wo(e,s.payload);case"permission.approve":return En(e,s.payload,"approved");case"permission.deny":return En(e,s.payload,"denied");case"auth.credentials":return Co(e,s.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${s.type}`}}}async function Hn(e,n){let t=M(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=Ye(o,t.signingSecret);if(!i)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};try{if(Je(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await On(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(Ve(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Te(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await He(e,{code:i.code,state:i.state,redirectUri:i.redirectUri})}}catch(s){return{type:"json",status:400,body:{error:s instanceof Error?s.message:"Hub delivery failed"}}}return{type:"redirect",url:i.hubSuccessUrl}}async function Mn(e,n){let t=M(e),r=await Dn(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(!o)return{type:"json",status:200,body:{status:"ok"}};let i=o.status??200,s=o.headers;return o.body&&typeof o.body=="object"&&!(o.body instanceof ArrayBuffer)?{type:"json",status:i,body:o.body,headers:s}:{type:"text",status:i,body:typeof o.body=="string"?o.body:o.body?JSON.stringify(o.body):null,headers:s}}function $n(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 Fn(e,n){return n.method==="GET"?Hn(e,n.url):Mn(e,{headers:n.headers,body:n.body??""})}async function Bn(e,n){try{let t=await Fn(e,n);return $n(t)}catch(t){if(t instanceof V)return Response.json({error:t.message},{status:503});throw t}}async function Qe(e,n){let t=n.method.toUpperCase();return t!=="GET"&&t!=="POST"?Response.json({error:"Method not allowed"},{status:405}):Bn(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0})}var ne=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 To=300;async function Un(e,n){let{keys:t,hub:r,plugin:o,tenantId:i}=e,s=n?.forceRefresh??!1,[a,c,d]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!a&&!d)throw new ne(o,"managed");let l=Math.floor(Date.now()/1e3);if(!s&&a&&c&&Number(c)>l+To)return{accessToken:a,expiresAt:Number(c),refreshed:!1};if(!d&&a&&!s)return{accessToken:a,expiresAt:c?Number(c):l+3600,refreshed:!1};let u=await me({hub:r,path:"/oauth/refresh",body:{plugin:o,tenantId:i},parseResponse:pt}),g=u.expires_in?l+u.expires_in:c?Number(c):l+3600;return await t.set_access_token(u.access_token),await t.set_expires_at(String(g)),u.refresh_token&&await t.set_refresh_token(u.refresh_token),u.scope&&await t.set_scope(u.scope),{accessToken:u.access_token,expiresAt:g,refreshed:!0}}async function Ft(e,n){e._refreshAuth=async()=>(await Un(n,{forceRefresh:!0})).accessToken}async function Nn(e,n){return me({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,deliveryUrl:e.deliveryUrl,expiresAt:n.expiresAt},parseResponse:lt})}function Wn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}function Bt(e,n){return{delivery:t=>Qe(e,t),createConnectSession:t=>je(e,t,n)}}function Xe(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(o,i){let s=t.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${t.join(" and ")} ${s?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
5
+ `))}}return u}async function qr(e,n,t,r){let o=new Set;for(let i of e.values())await Zr(i.pluginId,i.authType,i.integration,i.account,i.integrationFields,i.accountFields,n,t,r)&&o.add(i.pluginId);return o}async function Gr(e,n,t,r,o){if(!Br(wn)){o("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let i=wn,s=new Set(n.map(a=>a.id));for(let[a,c]of Object.entries(i)){if(!s.has(a))continue;if(!t.has(a)){r(`[corsair:setup] Skipping backfill for '${a}' \u2014 auth not configured.`);continue}let d=ie(e)?e[a]:void 0,l=ie(d)?d.api:void 0;if(l)for(let[u,g]of Object.entries(c))for(let[y,p]of Object.entries(g)){r(`[corsair:setup] Backfilling ${a} \u203A ${u}.${y}...`);try{let f=ie(l)?l[u]:void 0;await z(f,y)?.(p)}catch(f){o(`[corsair:setup] ${a} \u203A ${u}.${y} failed: `+(f instanceof Error?f.message:String(f)))}}}}async function we(e,n){if(!P(e).database)throw new Error("A database must be configured to provision Corsair for connect");await ht(e,{tenantId:n})}var bt=new Set(["webhook_signature","expires_at","scope"]);function zr(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}async function Jr(e,n,t,r){let o=Re(n,t).filter(c=>!bt.has(c));if(o.length===0)return!0;let s=(typeof e.withTenant=="function"?e.withTenant(r):e)[n.id],a=s&&typeof s=="object"&&"keys"in s?s.keys:null;if(!a)return!1;for(let c of o){if((t==="oauth_2"||t==="managed")&&c==="refresh_token")continue;let d=z(a,`get_${c}`);if(!d)continue;let l=null;try{let u=await d();l=typeof u=="string"?u:null}catch{l=null}if(!l)return!1}return!0}function Vr(e,n){return e==="oauth_2"||e==="managed"?[]:n.filter(t=>!bt.has(t))}async function wt(e,n,t={}){let r=P(e),o=M(e),i=Ue(o),s=[],a=t.pluginIds?new Set(t.pluginIds):null;for(let c of r.plugins){if(a&&!a.has(c.id))continue;let d=se(c);if(!d)continue;let l=zr(d),u=ve(c.id),g=await Jr(e,c,d,n),y=Re(c,d),p={plugin:c.id,providerName:u,authKind:l,alreadyConfigured:g};if(l==="oauth"){let h=t.oauthModeOverrides?.[c.id]??(d==="managed"?"managed":"byo");if(p.oauthMode=h,!g)if(h==="managed")p.state=ae(J(c.id,n),r.kek);else try{let m=await Tn(e,c.id,{tenantId:n,redirectUri:i});p.oauthUrl=m.url,p.state=m.state}catch{continue}}else{let f=Vr(d,y);f.length>0&&(p.credentialFields=f)}s.push(p)}return s}function Ct(e,n){let t=M(e);if(n){let r=be({source:n,deliveryUrl:t.deliveryUrl});if(r)throw new Error(r.error);return n}return ke(t.deliveryUrl)}async function Tt(e,n){await we(e,n)}async function Le(e,n){let t=M(e);await Tt(e,n.tenantId);let r=n.plugin?[n.plugin]:void 0,o=n.plugin&&n.oauthMode?{[n.plugin]:n.oauthMode}:void 0,i=await wt(e,n.tenantId,{pluginIds:r,oauthModeOverrides:o});if(i.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is not configured on this Corsair instance`:"No plugins are configured on this Corsair instance");let s=i.filter(c=>!c.alreadyConfigured);if(s.length===0)throw new Error(n.plugin?`Plugin '${n.plugin}' is already configured for this tenant`:"All plugins are already configured for this tenant");let a=Ct(e,n.source);return me({hub:t,path:"/connect/sessions",notFoundMessage:"Hub REST API not found at /connect/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{tenantId:n.tenantId,deliveryUrl:t.deliveryUrl,source:a,plugins:s},parseResponse:dt})}function Yr(e){if(e==="byo"||e==="managed")return e}function Qr(e){if(e==="client"||e==="server")return e}function Pn(e){let n=e.plugin?.trim(),t=e.tenantId?.trim()||"default",r=Qr(e.source),o=Yr(e.oauthMode),i=e.providerName?.trim();if(e.source!==void 0&&e.source!==null&&String(e.source).trim()!==""&&!r)return{error:'source must be "client" or "server"',status:400};if(e.oauthMode&&!o)return{error:'oauthMode must be "byo" or "managed"',status:400};let s={tenantId:t,oauthMode:o};return n&&(s.plugin=n),r&&(s.source=r),i&&(s.providerName=i),s}function xn(e){let{searchParams:n}=new URL(e),t=n.get("oauthMode");return{plugin:n.get("plugin")??void 0,tenantId:n.get("tenantId")??void 0,source:n.get("source")??void 0,oauthMode:t??void 0,providerName:n.get("providerName")??void 0}}function Xr(e){return{ok:!0,connectUrl:e.connectUrl,token:e.token,projectId:e.projectId,expiresAt:e.expiresAt}}async function eo(e,n,t){if(t?.resolveTenantId){let r=await t.resolveTenantId(e);return r?.trim()?r.trim():{error:"Unauthorized",status:401}}return n.tenantId?.trim()||t?.defaultTenantId?.trim()||"default"}async function An(e,n,t){let o=n.method.toUpperCase()==="GET"?xn(n.url):await n.json().catch(()=>null);if(!o)return{error:"Invalid JSON body",status:400};let i=await eo(n,o,t);if(typeof i!="string")return i;let s=Pn({...o,tenantId:i});if("error"in s)return s;let a=M(e);if(s.source){let l=be({source:s.source,deliveryUrl:a.deliveryUrl,oauthMode:s.oauthMode});if(l)return l}let c={...s,source:s.source??ke(a.deliveryUrl)},d=await Le(e,c);return Xr(d)}async function Rn(e,n,t){try{let r=await An(e,n,t);return"error"in r?Response.json({error:r.error},{status:r.status}):Response.json(r)}catch(r){if(r instanceof V)return Response.json({error:r.message},{status:503});let o=r instanceof Error?r.message:String(r);return Response.json({error:o},{status:500})}}async function je(e,n,t){let r=n.method.toUpperCase();return r!=="GET"&&r!=="POST"?Response.json({error:"Method not allowed"},{status:405}):Rn(e,n,t)}var Y=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function Pt(e,n){let t=P(e,()=>new Y("invalid_corsair_instance","Invalid corsair instance"));if(!t.database)throw new Y("no_database","Database not configured");let r=B(t,n.plugin,d=>new Y("plugin_not_found",d)),o=se(r);if(!o)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(o==="oauth_2"||o==="managed")throw new Y("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await we(e,n.tenantId);let i=new Set(Re(r,o)),a=r.authConfig?.[o]?.account??[],c=I({authType:o,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a});for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!i.has(d))throw new Y("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let u=z(c,`set_${d}`);if(!u)throw new Y("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await u(l.trim())}return{plugin:n.plugin,tenantId:n.tenantId}}async function Ke(e,n,t){for(let r of e){if(r.id!==n)continue;let o=r.oauthWebhookTenantLinkResolver;return o?o(t):null}return null}import{createCipheriv as xt,createDecipheriv as At,randomBytes as Ze,scrypt as no}from"crypto";import{promisify as to}from"util";var Rt=to(no),qe="aes-256-gcm",vt=12,Ge=16,ro=16,Ee=32;function Q(){return Ze(Ee).toString("base64")}async function X(e,n){let t=Ze(ro),r=await Rt(n,t,Ee),o=Ze(vt),i=xt(qe,r,o,{authTagLength:Ge}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[t.toString("base64"),o.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function W(e,n){let[t,r,o,i]=e.split(":");if(!t||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),d=Buffer.from(i,"base64"),l=await Rt(n,s,Ee),u=At(qe,l,a,{authTagLength:Ge});return u.setAuthTag(c),Buffer.concat([u.update(d),u.final()]).toString("utf8")}function vn(e,n){let t=Buffer.from(n,"base64"),r=Ze(vt),o=xt(qe,t,r,{authTagLength:Ge}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function Oe(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"),s=Buffer.from(t,"base64"),a=Buffer.from(r,"base64"),c=Buffer.from(o,"base64"),d=At(qe,i,s,{authTagLength:Ge});return d.setAuthTag(a),Buffer.concat([d.update(c),d.final()]).toString("utf8")}function ce(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=vn(o,n);return t}function ee(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Oe(o,n);return t}function De(e,n,t){let r=ee(e,n);return ce(r,t)}function It(e,n,t){let r={};for(let o of t)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await n({[o]:s})};return r}var In=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function D(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,s=[...U[n].integration,...i],a=null,c={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let p=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!p)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:p.id,config:In(p.config),dek:p.dek??null},a},updateIntegration:async p=>{let f=await c.getIntegration();await o.db.updateTable("corsair_integrations").set({...p.config!==void 0?{config:p.config}:{},...p.dek!==void 0?{dek:p.dek}:{},updated_at:new Date}).where("id","=",f.id).execute(),a=null}},d=null,l=async()=>{if(d)return d;let p=await c.getIntegration();if(!p.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return d=await W(p.dek,r),d},u=async()=>{let p=await c.getIntegration(),f=await l(),h=p.config;return!h||Object.keys(h).length===0?{}:ee(h,f)};return{get_dek:l,issue_new_dek:async()=>{let p=await c.getIntegration(),f=Q(),h={};if(p.dek){let C=await W(p.dek,r),b=p.config;b&&Object.keys(b).length>0&&(h=De(b,C,f))}let m=await X(f,r);return await c.updateIntegration({config:h,dek:m}),d=f,f},...It(u,async p=>{let f=await l(),h;try{h=await u()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,b),h={}}let m={...h};for(let[b,k]of Object.entries(p))k===null?delete m[b]:m[b]=k;let C=ce(m,f);await c.updateIntegration({config:C})},s)}}function I(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:s=[]}=e,a=[...U[n].account,...s],c=null,d=null,l=async()=>{if(d)return d;let k=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!k)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return d={id:k.id,config:In(k.config),dek:k.dek??null},d},u={kek:o,integrationName:t,tenantId:r,getIntegration:l,getAccount:async()=>{if(c)return c;let k=await l(),w=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",k.id).executeTakeFirst();if(!w)throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`);return c={id:w.id,config:In(w.config),dek:w.dek??null},c},updateAccount:async k=>{let w=await u.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","=",w.id).execute(),c=null}},g=null,y=null,p=async()=>{if(g)return g;let k=await u.getAccount();if(!k.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return g=await W(k.dek,o),g},f=async()=>{if(y)return y;let k=await u.getIntegration();if(!k.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return y=await W(k.dek,o),y},h=async()=>{let k=await u.getAccount(),w=await p(),T=k.config;return!T||Object.keys(T).length===0?{}:ee(T,w)},m=async()=>{let k=await u.getIntegration(),w=await f(),T=k.config;return!T||Object.keys(T).length===0?{}:ee(T,w)},b={get_dek:p,issue_new_dek:async()=>{let k=await u.getAccount(),w=Q(),T={};if(k.dek){let _=await W(k.dek,o),E=k.config;E&&Object.keys(E).length>0&&(T=De(E,_,w))}let S=await X(w,o);return await u.updateAccount({config:T,dek:S}),g=w,w},...It(h,async k=>{let w=await p(),T;try{T=await h()}catch(E){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,E),T={}}let S={...T};for(let[E,x]of Object.entries(k))x===null?delete S[E]:S[E]=x;let _=ce(S,w);await u.updateAccount({config:_})},a)};return n==="oauth_2"&&(b.get_integration_credentials=async()=>{let k=await m();return{client_id:k.client_id||null,client_secret:k.client_secret||null,redirect_url:k.redirect_url??null}}),b}async function St(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=Q(),i=await X(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function _t(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 s=Q(),a=await X(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var Et=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function oo(e){let n=await e.database.db.selectFrom("corsair_integrations").selectAll().where("name","=",e.pluginId).executeTakeFirst();if(!n)throw new Error(`Integration '${e.pluginId}' not found. Run setupCorsair before registering webhook tenant links.`);let t=await e.database.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",e.tenantId).where("integration_id","=",n.id).executeTakeFirst();if(!t)throw new Error(`Account not found for tenant '${e.tenantId}' and integration '${e.pluginId}'.`);return{integrationId:n.id,accountId:t.id}}async function io(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 W(n.dek,e.kek),r=Et(n.config),o={};Object.keys(r).length>0&&(o=ee(r,t)),o[e.link.linkType]=e.link.externalId;let i=ce(o,t);await e.database.db.updateTable("corsair_accounts").set({config:i,updated_at:new Date}).where("id","=",n.id).execute()}async function Ce(e){let{database:n,kek:t,pluginId:r,tenantId:o,link:i,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await oo({database:n,pluginId:r,tenantId:o}),d=!1;if(s){let l=I({authType:s,integrationName:r,tenantId:o,kek:t,database:n,extraAccountFields:a}),u=`set_${i.linkType}`,g=l[u];typeof g=="function"&&(await g(i.externalId),d=!0)}d||await io({database:n,kek:t,accountId:c,link:i})}async function Sn(e){let{database:n,kek:t,pluginId:r,linkType:o,externalId:i}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let c=await W(a.dek,t),l=Et(a.config)[o];if(!l)continue;if(Oe(l,c)===i)return a}catch{continue}return null}async function ze(e){return(await Sn(e))?.tenant_id??null}async function Ot(e){return ze({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var ue=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Te(e,n){let{plugin:t,tenantId:r,accessToken:o,refreshToken:i,expiresIn:s,scope:a}=n;if(!o.trim())throw new ue("no_access_token","Managed OAuth delivery missing access_token");let c=P(e,()=>new ue("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new ue("no_database","No database configured on corsair instance");let d=B(c,t,u=>new ue("plugin_not_found",u));await we(e,r);let l=I({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await l.set_access_token(o),i&&await l.set_refresh_token(i),s&&await l.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await l.set_scope(a);try{let u=await Ke(c.plugins,t,{access_token:o,refresh_token:i,scope:a});if(u)try{let g=d.authConfig?.managed?.account??[];await Ce({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:u,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(u){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,u)}return{plugin:t,tenantId:r}}function so(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Dt(e,n,t=[]){for(let[r,o]of Object.entries(e))if(so(o)){if(o.match(n))return{webhook:o,path:[...t,r]}}else if(o&&typeof o=="object"){let i=Dt(o,n,[...t,r]);if(i)return i}return null}function ao(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function co(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 Ht(e,n,t,r){let o=ao(n),i=typeof t=="string"?JSON.parse(t):t;(!i||typeof i=="object"&&Object.keys(i).length===0)&&o["x-goog-resource-uri"]&&(i=co(o)||i);let a={headers:o,body:i,...r?{query:r}:{}},c=r?.tenantId||"default",d=e.withTenant?e.withTenant(c):e,l=Fe;for(let u of l){let g=d[u];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(a))continue;let y=Dt(g.webhooks,a);if(!y)continue;let p=y.path.join("."),f={payload:i,headers:o,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let h=await y.webhook.handler(f),m=!!Object.keys(h.returnToSender||{})?.length;return{plugin:u,action:p,body:i,response:m?{...h?.returnToSender,success:!0}:{success:!0},...h.responseHeaders&&{responseHeaders:h.responseHeaders}}}catch(h){return console.error(`Error executing webhook handler for ${u}.${p}:`,h),{plugin:u,action:p,body:i,response:{success:!1,error:h instanceof Error?h.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{createHmac as uo,timingSafeEqual as lo}from"crypto";var po=300*1e3;function go(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function _n(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=go(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)>po)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let i=uo("sha256",n).update(e.body).digest("hex");try{if(!lo(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}}import{createHmac as fo,timingSafeEqual as yo}from"crypto";function Je(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function Ve(e){return e.deliveryMode==="oauth.tokens"||typeof e.accessToken=="string"&&e.accessToken.length>0}function Mt(e){let n=e.trim();return n.length>0?n:null}function ho(e,n){let t=Mt(n);if(!t)throw new Error("Signing secret is required for browser delivery tokens");return fo("sha256",t).update(e).digest("base64url")}function Ye(e,n){let t=Mt(n);if(!t)return null;let r=e.split(".");if(r.length!==2)return null;let[o,i]=r;if(!o||!i)return null;let s=ho(o,t);try{if(!yo(Buffer.from(i,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function $t(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 mo(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 ze({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function ko(e,n,t){let r=await mo(e,n,t),o={...t.query??{},...r?{tenantId:r}:{}},i=await Ht(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 s=i.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(i.response?.data??i.response);return{status:"ok",webhookResponse:{status:i.response?.statusCode??200,body:a,headers:i.responseHeaders}}}async function bo(e,n){return await He(e,n),{status:"ok"}}async function wo(e,n){return await Te(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function On(e,n,t){let r=await En(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function En(e,n,t){let r=P(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(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",o).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<i?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Co(e,n){try{return await Pt(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function Dn(e,n,t={}){let r=P(e),o=$t(n.headers,"x-corsair-signature"),i=$t(n.headers,"x-corsair-timestamp");if(t.signingSecret?.trim()){let a=_n({body:n.body,signatureHeader:o,timestampHeader:i,signingSecret:t.signingSecret});if(!a.ok)return{status:"failed",retryable:!1,error:a.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let s;try{s=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(s.type){case"webhook":return ko(e,r,s.payload);case"oauth.callback":return bo(e,s.payload);case"oauth.tokens":return wo(e,s.payload);case"permission.approve":return En(e,s.payload,"approved");case"permission.deny":return En(e,s.payload,"denied");case"auth.credentials":return Co(e,s.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${s.type}`}}}async function Hn(e,n){let t=M(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=Ye(o,t.signingSecret);if(!i)return{type:"json",status:400,body:{error:"Invalid or expired delivery token"}};try{if(Je(i)){if(!i.permissionToken)return{type:"json",status:400,body:{error:"Permission delivery missing permission token"}};await On(e,i.permissionToken,i.deliveryMode==="permission.approve"?"approved":"denied")}else if(Ve(i)){if(!i.accessToken)return{type:"json",status:400,body:{error:"Managed OAuth delivery missing access_token"}};await Te(e,{plugin:i.plugin,tenantId:i.tenantId,accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn,scope:i.scope})}else{if(!i.code||!i.state||!i.redirectUri)return{type:"json",status:400,body:{error:"Invalid BYO OAuth delivery token"}};await He(e,{code:i.code,state:i.state,redirectUri:i.redirectUri})}}catch(s){return{type:"json",status:400,body:{error:s instanceof Error?s.message:"Hub delivery failed"}}}return{type:"redirect",url:i.hubSuccessUrl}}async function Mn(e,n){let t=M(e),r=await Dn(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(!o)return{type:"json",status:200,body:{status:"ok"}};let i=o.status??200,s=o.headers;return o.body&&typeof o.body=="object"&&!(o.body instanceof ArrayBuffer)?{type:"json",status:i,body:o.body,headers:s}:{type:"text",status:i,body:typeof o.body=="string"?o.body:o.body?JSON.stringify(o.body):null,headers:s}}function $n(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 Fn(e,n){return n.method==="GET"?Hn(e,n.url):Mn(e,{headers:n.headers,body:n.body??""})}async function Bn(e,n){try{let t=await Fn(e,n);return $n(t)}catch(t){if(t instanceof V)return Response.json({error:t.message},{status:503});throw t}}async function Qe(e,n){let t=n.method.toUpperCase();return t!=="GET"&&t!=="POST"?Response.json({error:"Method not allowed"},{status:405}):Bn(e,{method:t,url:n.url,headers:n.headers,body:t==="POST"?await n.text():void 0})}var ne=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 To=300;async function Un(e,n){let{keys:t,hub:r,plugin:o,tenantId:i}=e,s=n?.forceRefresh??!1,[a,c,d]=await Promise.all([t.get_access_token(),t.get_expires_at(),t.get_refresh_token()]);if(!a&&!d)throw new ne(o,"managed");let l=Math.floor(Date.now()/1e3);if(!s&&a&&c&&Number(c)>l+To)return{accessToken:a,expiresAt:Number(c),refreshed:!1};if(!d&&a&&!s)return{accessToken:a,expiresAt:c?Number(c):l+3600,refreshed:!1};let u=await me({hub:r,path:"/oauth/refresh",body:{plugin:o,tenantId:i},parseResponse:pt}),g=u.expires_in?l+u.expires_in:c?Number(c):l+3600;return await t.set_access_token(u.access_token),await t.set_expires_at(String(g)),u.refresh_token&&await t.set_refresh_token(u.refresh_token),u.scope&&await t.set_scope(u.scope),{accessToken:u.access_token,expiresAt:g,refreshed:!0}}async function Ft(e,n){e._refreshAuth=async()=>(await Un(n,{forceRefresh:!0})).accessToken}async function Nn(e,n){return me({hub:e,path:"/permission/sessions",notFoundMessage:"Hub REST API not found at /permission/sessions. Check HUB_API_URL and ensure the Hub API is deployed.",body:{permissionId:n.permissionId,permissionToken:n.permissionToken,plugin:n.plugin,endpoint:n.endpoint,args:n.args,tenantId:n.tenantId,deliveryUrl:e.deliveryUrl,expiresAt:n.expiresAt},parseResponse:lt})}function Wn(e){return`Approval required. Visit ${e} to approve or deny, then tell the agent to retry this action.`}function Bt(e,n){return{delivery:t=>Qe(e,t),createConnectSession:t=>je(e,t,n)}}function Xe(e,n){let t=[];e||t.push("database"),n||t.push("kek");let r={};return new Proxy(r,{get(o,i){let s=t.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${t.join(" and ")} ${s?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
6
6
 
7
7
  To generate a KEK, run: openssl rand -base64 ${Ee}`)}})}var Po=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Ut(e,n,t,r,o){let i={pluginId:n,operation:t,input:r,originalError:e},s=Object.keys(o).find(d=>o[d]?.match(e,i));return await(o[s||"DEFAULT"]?.handler||Po)(e,i)}import{randomBytes as xo}from"crypto";import{v4 as Ao}from"uuid";var Ro={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 vo(e,n,t){return t!==void 0?t:Ro[n][e]}function Ln(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 Wt(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 Nt(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 Lt(e){let n=vo(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}'.`,`
8
8
  Action: ${r}`,`
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{Aa as F,Ba as G,Ca as H,Da as I,Ea as J,a,aa as p,b,ea as q,j as d,ja as r,k as e,ka as s,l as f,la as t,m as g,n as h,o as i,p as j,pa as u,q as k,qa as v,r as l,ra as w,s as m,sa as x,t as n,ta as y,u as o,ua as z,va as A,wa as B,xa as C,ya as D,za as E}from"./chunk-36XOX6SO.js";import{g as c}from"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{p as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,q as resolveConnectLink,A as toExternalId};
1
+ import{Aa as F,Ba as G,Ca as H,Da as I,Ea as J,a,aa as p,b,ea as q,j as d,ja as r,k as e,ka as s,l as f,la as t,m as g,n as h,o as i,p as j,pa as u,q as k,qa as v,r as l,ra as w,s as m,sa as x,t as n,ta as y,u as o,ua as z,va as A,wa as B,xa as C,ya as D,za as E}from"./chunk-GJ743ML7.js";import{g as c}from"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{p as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,q as resolveConnectLink,A as toExternalId};
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as x,C as g,D as h,E as i,F as j,I as k,J as l,K as m,L as n,M as o,N as p,O as q,P as r,W as s,X as t,Y as u,Z as v,_ as w,b as a,ba as y,c as b,ca as z,d as c,da as A,e as d,f as e,g as f}from"./chunk-36XOX6SO.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,q as ManagedOAuthDeliveryError,z as attachManagedRefreshAuth,k as createHubConnectSession,A as createHubRouteHandlers,a as formatProviderDisplayName,e as getHubConfig,y as getManagedAccessToken,n as handleHubConnectSessionRequest,s as handleHubDeliveryGet,t as handleHubDeliveryPost,v as handleHubDeliveryRequest,u as hubDeliveryToResponse,g as isLoopbackDeliveryUrl,d as normalizeHubConfig,l as parseHubConnectSessionBody,m as parseHubConnectSessionSearchParams,r as processManagedOAuthDelivery,h as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,o as respondToHubConnectSession,p as respondToHubConnectSessionFromRequest,w as respondToHubDelivery,x as respondToHubDeliveryFromRequest,i as shouldUseBrowserConnectDelivery,j as validateExplicitConnectSource};
1
+ import{$ as x,C as g,D as h,E as i,F as j,I as k,J as l,K as m,L as n,M as o,N as p,O as q,P as r,W as s,X as t,Y as u,Z as v,_ as w,b as a,ba as y,c as b,ca as z,d as c,da as A,e as d,f as e,g as f}from"./chunk-GJ743ML7.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as DEFAULT_HUB_API_URL,c as HubNotConfiguredError,q as ManagedOAuthDeliveryError,z as attachManagedRefreshAuth,k as createHubConnectSession,A as createHubRouteHandlers,a as formatProviderDisplayName,e as getHubConfig,y as getManagedAccessToken,n as handleHubConnectSessionRequest,s as handleHubDeliveryGet,t as handleHubDeliveryPost,v as handleHubDeliveryRequest,u as hubDeliveryToResponse,g as isLoopbackDeliveryUrl,d as normalizeHubConfig,l as parseHubConnectSessionBody,m as parseHubConnectSessionSearchParams,r as processManagedOAuthDelivery,h as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,o as respondToHubConnectSession,p as respondToHubConnectSessionFromRequest,w as respondToHubDelivery,x as respondToHubDeliveryFromRequest,i as shouldUseBrowserConnectDelivery,j as validateExplicitConnectSource};
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{Ba as H,Ca as j,Da as k,Ea as B,G as w,Q as I,V as T,aa as S,ea as O,fa as L,ga as A,ha as v,ia as $,ma as d,na as g,oa as C,pa as f,ra as E,sa as M,ta as W,ua as F,v as P,va as _,w as x,wa as N,x as b,xa as D,y as R}from"./chunk-36XOX6SO.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";var c=class extends Error{status;code;extra;constructor(r,o,e,a={}){super(e),this.name="CorsairClientError",this.status=r,this.code=o,this.extra=a}};function J(n){return n.endsWith("/")?n.slice(0,-1):n}async function y(n){let r={};try{r=await n.json()}catch{}let o=typeof r.error=="string"?r.error:"request_failed",e=typeof r.message=="string"?r.message:`Request failed (${n.status})`,{error:a,message:u,...t}=r;return new c(n.status,o,e,t)}function U(n){let r=J(n.baseURL),o=n.fetch??globalThis.fetch.bind(globalThis);async function e(t,s){let i=s&&Object.keys(s).length?`?${new URLSearchParams(s).toString()}`:"",p=await o(`${r}${t}${i}`,{method:"GET"});if(!p.ok)throw await y(p);return await p.json()}async function a(t,s){let i=await o(`${r}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw await y(i);return await i.json()}let u=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:t=>a("/tenants",t),get:t=>e(`/tenants/${u(t)}`)},plugins:{list:()=>e("/plugins"),get:t=>e(`/plugins/${u(t)}`)},connectionStatus:{get:t=>{let s={};return t?.tenantId&&(s.tenantId=t.tenantId),e("/connection-status",s)}},permissions:{get:t=>e(`/permissions/${u(t)}`),getByToken:t=>a("/permissions/lookup-by-token",{token:t})},connect:{createLink:t=>a("/connect/links",t),resolve:t=>e("/connect/resolve",{state:t}),oauthCallback:t=>a("/connect/oauth/callback",t)}}}function l(n){let r=n[k];if(!r)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return r.plugins}function q(n,r){let o=g(l(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
1
+ import{Ba as H,Ca as j,Da as k,Ea as B,G as w,Q as I,V as T,aa as S,ea as O,fa as L,ga as A,ha as v,ia as $,ma as d,na as g,oa as C,pa as f,ra as E,sa as M,ta as W,ua as F,v as P,va as _,w as x,wa as N,x as b,xa as D,y as R}from"./chunk-GJ743ML7.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";var c=class extends Error{status;code;extra;constructor(r,o,e,a={}){super(e),this.name="CorsairClientError",this.status=r,this.code=o,this.extra=a}};function J(n){return n.endsWith("/")?n.slice(0,-1):n}async function y(n){let r={};try{r=await n.json()}catch{}let o=typeof r.error=="string"?r.error:"request_failed",e=typeof r.message=="string"?r.message:`Request failed (${n.status})`,{error:a,message:u,...t}=r;return new c(n.status,o,e,t)}function U(n){let r=J(n.baseURL),o=n.fetch??globalThis.fetch.bind(globalThis);async function e(t,s){let i=s&&Object.keys(s).length?`?${new URLSearchParams(s).toString()}`:"",p=await o(`${r}${t}${i}`,{method:"GET"});if(!p.ok)throw await y(p);return await p.json()}async function a(t,s){let i=await o(`${r}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw await y(i);return await i.json()}let u=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:t=>a("/tenants",t),get:t=>e(`/tenants/${u(t)}`)},plugins:{list:()=>e("/plugins"),get:t=>e(`/plugins/${u(t)}`)},connectionStatus:{get:t=>{let s={};return t?.tenantId&&(s.tenantId=t.tenantId),e("/connection-status",s)}},permissions:{get:t=>e(`/permissions/${u(t)}`),getByToken:t=>a("/permissions/lookup-by-token",{token:t})},connect:{createLink:t=>a("/connect/links",t),resolve:t=>e("/connect/resolve",{state:t}),oauthCallback:t=>a("/connect/oauth/callback",t)}}}function l(n){let r=n[k];if(!r)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return r.plugins}function q(n,r){let o=g(l(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
2
2
  `):Object.values(o).flat().join(`
3
3
  `)}function G(n,r){return C(l(n),r)}function Y(n,r){return d(l(n),r)}var z=Symbol.for("corsair:internal");function K(n,r){let o=n;for(let e of r){if(!o||typeof o!="object")return null;o=o[e]}return typeof o=="function"?o:null}function h(n){return n[z]?.database}async function Q(n,r){let o=new Date().toISOString(),e=await n.permissions.find_by_token(r);if(!e)return console.error("executePermission: no permission found for token."),{error:"executePermission: no permission found for token."};if(e.status!=="approved")return console.error(`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`};if(e.expires_at<o){let i=h(n);return i&&await i.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",e.id).execute(),console.error(`executePermission: permission '${e.id}' has expired.`),{error:`executePermission: permission '${e.id}' has expired.`,endpoint:e.endpoint,plugin:e.plugin,result:null}}let a=e.tenant_id??"default",t=(n.withTenant?n.withTenant(a):n)[e.plugin];if(!t?.api)return console.error(`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`),{error:`executePermission: plugin '${e.plugin}' not found or has no API on this corsair instance.`,plugin:e.plugin,endpoint:e.endpoint,result:null};let s=K(t.api,e.endpoint.split("."));if(!s)return console.error(`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: endpoint '${e.endpoint}' not found in plugin '${e.plugin}'.`};await n.permissions.set_executing(e.id);try{let i=typeof e.args=="string"?JSON.parse(e.args):e.args,p=await s(i);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:p}}catch(i){let p=i instanceof Error?i.message:String(i),m=h(n);return m&&await m.db.updateTable("corsair_permissions").set({status:"failed",error:p,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:p}}}export{S as AuthMissingError,c as CorsairClientError,N as asRecord,W as collectPluginWebhookMatchers,B as createCorsair,U as createCorsairClient,j as decodePubSubData,Q as executePermission,H as firstString,f as formatDocSchemaShape,F as getHeader,G as getSchema,Y as getStructuredSchema,q as listOperations,L as managementHandler,E as matchWebhookPlugin,M as matchWebhookPluginAndTenant,T as processCorsair,I as processWebhook,D as readBodyRecord,x as resolveAccountFromWebhookLink,O as resolveConnectLink,R as resolveTenantFromWebhookLink,b as resolveTenantIdFromWebhookLink,P as setWebhookTenantLink,w as setupCorsair,A as toExpressHandler,_ as toExternalId,v as toHonoHandler,$ as toNextJsHandler};
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{A as d,B as e,h as a,i as b,z as c}from"./chunk-36XOX6SO.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as OAuthCallbackError,b as decodeOAuthState,a as encodeOAuthState,d as generateOAuthUrl,e as processOAuthCallback};
1
+ import{A as d,B as e,h as a,i as b,z as c}from"./chunk-GJ743ML7.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{c as OAuthCallbackError,b as decodeOAuthState,a as encodeOAuthState,d as generateOAuthUrl,e as processOAuthCallback};
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{G as a,H as b}from"./chunk-36XOX6SO.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{G as a,H as b}from"./chunk-GJ743ML7.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
package/dist/tunnel.js CHANGED
@@ -1 +1 @@
1
- import{R as e,S as f,T as g,U as h,V as i,v as a,w as b,x as c,y as d}from"./chunk-36XOX6SO.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{h as applyPermissionDecision,f as isManagedBrowserDelivery,e as isPermissionBrowserDelivery,i as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,g as verifyBrowserDeliveryToken};
1
+ import{R as e,S as f,T as g,U as h,V as i,v as a,w as b,x as c,y as d}from"./chunk-GJ743ML7.js";import"./chunk-6D4UDUPJ.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{h as applyPermissionDecision,f as isManagedBrowserDelivery,e as isPermissionBrowserDelivery,i as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,g as verifyBrowserDeliveryToken};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.80",
3
+ "version": "0.1.81",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",