corsair 0.1.84 → 0.1.85

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.
@@ -12,7 +12,7 @@ Schema: ${JSON.stringify(un(o),null,2)}`)}async function Lo(e,n,t,r,i){let o=new
12
12
  Permission ID: ${c}`,`
13
13
  Permission token: ${u}`,`
14
14
  Expires at: ${l}`,`
15
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Pr(e.db,c,d):{result:"blocked",reason:"pending",id:c,token:u,expiresAt:l}}var v=class extends Error{status;code;extra;constructor(n,t,r,i={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=i}};function A(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function Ar(e){let n={error:e.code,message:e.message,...e.extra};return A(e.status,n)}function ue(e){return new v(404,"not_found",e)}function V(e,n={}){return new v(400,"bad_request",e,n)}function Rr(e,n){return F(e,n,t=>ue(t))}async function ot(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=O({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),i=N[t].integration,o=r,s;try{s=await Promise.all(i.map(u=>o[`get_${u}`]()))}catch{s=i.map(()=>null)}let a=i.filter((u,d)=>s[d]==null),c;return t==="oauth_2"?c=!a.includes("client_id")&&!a.includes("client_secret"):c=a.length===0,{configured:c,missingFields:a}}async function Sr(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await ot(e,n);return{id:e.id,authType:t,configured:i,missingFields:o,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function hn(){return{ok:!0}}async function kn(e){return Promise.all(e.plugins.map(n=>Sr(n,e)))}async function bn(e,n){let t=Rr(e,n);return Sr(t,e)}async function Ir(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 Er(e,n){let t=await Ir(e,n),r=t.filter(i=>i.hasCredentials).map(i=>i.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function wn(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let i=r.tenant_id;if(!i)continue;let o=n.get(i);o||(o={id:i,accounts:[],connectedPlugins:[]},n.set(i,o));let s=!!r.dek;o.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&o.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function Cn(e,n){if(!n)throw V("Tenant id must be a non-empty string");return Er(e,n)}async function Tn(e,n){let t=n?.id?.trim();if(!t)throw V("Tenant id is required",{missingFields:["id"]});return Er(e,t)}async function _e(e,n){let t=n?.trim()||"default",r={},i=e.database?await Ir(e,t):[],o=new Map(i.map(s=>[s.integrationName,s]));for(let s of e.plugins){if(!(await ot(s,e)).configured){r[s.id]="missing_credentials";continue}let c=o.get(s.id),u;c&&c.hasCredentials?u="connected":u="not_connected",r[s.id]=u}return r}async function it(e,n){if(!e.database)throw ue(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ue(`Permission '${n}' not found`);return mn(e,t)}function ci(e){if(!e.oauthConfig)throw V(`Plugin '${e.id}' has no oauthConfig`)}function ui(e){if(!e.manual)throw new v(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function st(e){let n=ui(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new v(500,"connect_not_configured","Manual connect requires manual.baseUrl and manual.redirectUri. Use hub for hosted connect, or set both URLs for manual OAuth.");return n}function li(e){let n=!!e.hub,t=Ie(e.manual);if(!n&&!t)throw new v(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function _r(e){if(!e.database||!e.kek)throw new v(500,"database_not_configured","A database and kek are required to issue connect links.")}async function di(e,n){let t=n?.plugin?.trim();if(!t)throw V("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=Rr(e,t);ci(i);let o=st(e);_r(e);let s=await ot(i,e);if(!s.configured)throw new v(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:s.missingFields});let a=ae(z(t,r),e.kek),c;try{c=new URL(o.baseUrl)}catch{throw new v(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return c.searchParams.set("state",a),{connectUrl:c.toString(),expiresAt:new Date(Date.now()+Kn).toISOString()}}async function pi(e,n,t){_r(n);let r=t.tenantId?.trim()||"default",i=H(e);if(t.source){let u=Re({source:t.source,deliveryUrl:i.deliveryUrl,oauthMode:t.oauthMode});if(u)throw V(u.error)}let o={tenantId:r,source:t.source??Ae(i.deliveryUrl),oauthMode:t.oauthMode},s=t.plugin?.trim();s&&(o.plugin=s);let a=t.providerName?.trim();a&&(o.providerName=a);let c=await ln(e,o);return{connectUrl:c.connectUrl,expiresAt:c.expiresAt}}async function Pn(e,n,t){return li(n),n.hub?pi(e,n,t):di(n,t)}async function vn(e,n,t){if(n.hub&&!Ie(n.manual))throw new v(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw V("state is required",{missingFields:["state"]});st(n);try{return await Yn(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw V("Invalid or expired state");case"client_id_not_configured":throw new v(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new v(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function xn(e,n,t){if(n.hub&&!Ie(n.manual))throw new v(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),i=t?.state?.trim(),o=[];if(r||o.push("code"),i||o.push("state"),o.length)throw V("Missing required fields",{missingFields:o});let s=st(n),{processOAuthCallback:a}=await import("./oauth.js");try{return await a(e,{code:r,state:i,redirectUri:s.redirectUri})}catch(c){if(c instanceof Error&&c.name==="OAuthCallbackError")switch(c.code){case"invalid_state":throw V("Invalid or expired state");case"credentials_not_configured":throw new v(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new v(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function at(e,n){if(!e.database)throw ue("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ue("Permission not found");return mn(e,t)}async function Dr(e,n){return"id"in n?it(e,n.id):at(e,n.token)}function gi(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function fi(e,n){return n&&!n.has(e.id)?!1:$(e)!==null}async function De(e,n,t={}){let r=P(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,s=await _e(r,i),a=r.plugins.filter(c=>fi(c,o)).map(c=>{let u=$(c),d=s[c.id]??"not_connected";return{plugin:c.id,providerName:ye(c.id),authKind:gi(u),connected:d==="connected"}});return{tenantId:i,plugins:a}}var le=6e4,he=3e5;var Y=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function An(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=F(t,n.plugin,d=>new Y("plugin_not_found",d)),i=$(r);if(!i)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new Y("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Se(e,n.tenantId);let o=new Set(Xe(r,i)),a=r.authConfig?.[i]?.account??[],c=I({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a}),u=0;for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!o.has(d))throw new Y("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let g=J(c,`set_${d}`);if(!g)throw new Y("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await g(l.trim()),u+=1}if(u===0)throw new Y("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var Rn=new Map;function yi(e){for(let[n,t]of Rn)t<=e&&Rn.delete(n)}function Sn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return yi(r),Rn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(Rn.set(t,r+n),{ok:!0})}async function In(e,n,t){for(let r of e){if(r.id!==n)continue;let i=r.oauthWebhookTenantLinkResolver;return i?i(t):null}return null}var Or=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function mi(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 hi(e){let n=await e.database.db.selectFrom("corsair_accounts").selectAll().where("id","=",e.accountId).executeTakeFirst();if(!n?.dek)throw new Error(`Account '${e.accountId}' has no DEK.`);let t=await L(n.dek,e.kek),r=Or(n.config),i={};Object.keys(r).length>0&&(i=te(r,t)),i[e.link.linkType]=e.link.externalId;let o=ce(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function Oe(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await mi({database:n,pluginId:r,tenantId:i}),u=!1;if(s){let d=I({authType:s,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:a}),l=`set_${o.linkType}`,g=d[l];typeof g=="function"&&(await g(o.externalId),u=!0)}u||await hi({database:n,kek:t,accountId:c,link:o})}async function ct(e){let{database:n,kek:t,pluginId:r,linkType:i,externalId:o}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let c=await L(a.dek,t),d=Or(a.config)[i];if(!d)continue;if(je(d,c)===o)return a}catch{continue}return null}async function En(e){return(await ct(e))?.tenant_id??null}async function Mr(e){return En({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var de=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Me(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:s,scope:a}=n;if(!i.trim())throw new de("no_access_token","Managed OAuth delivery missing access_token");let c=P(e,()=>new de("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new de("no_database","No database configured on corsair instance");let u=F(c,t,l=>new de("plugin_not_found",l));await Se(e,r);let d=I({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await d.set_access_token(i),o&&await d.set_refresh_token(o),s&&await d.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await d.set_scope(a);try{let l=await In(c.plugins,t,{access_token:i,refresh_token:o,scope:a});if(l)try{let g=u.authConfig?.managed?.account??[];await Oe({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:l,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(l){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,l)}return{plugin:t,tenantId:r}}function ki(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Hr(e,n,t=[]){for(let[r,i]of Object.entries(e))if(ki(i)){if(i.match(n))return{webhook:i,path:[...t,r]}}else if(i&&typeof i=="object"){let o=Hr(i,n,[...t,r]);if(o)return o}return null}function bi(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function wi(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 Br(e,n,t,r){let i=bi(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=wi(i)||o);let a={headers:i,body:o,...r?{query:r}:{}},c=r?.tenantId||"default",u=e.withTenant?e.withTenant(c):e,d=en;for(let l of d){let g=u[l];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(a))continue;let f=Hr(g.webhooks,a);if(!f)continue;let p=f.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let m=await f.webhook.handler(y),h=!!Object.keys(m.returnToSender||{})?.length;return{plugin:l,action:p,body:o,response:h?{...m?.returnToSender,success:!0}:{success:!0},...m.responseHeaders&&{responseHeaders:m.responseHeaders}}}catch(m){return console.error(`Error executing webhook handler for ${l}.${p}:`,m),{plugin:l,action:p,body:o,response:{success:!1,error:m instanceof Error?m.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{createHmac as ut,randomUUID as Ci,timingSafeEqual as Ur}from"crypto";function Fr(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function _n(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=ut("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":Ci()}}}function lt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Fr(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>3e5)return!1;let o=ut("sha256",n).update(e.body).digest("hex");try{return Ur(Buffer.from(o,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function He(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Fr(e.signatureHeader);if(!t)return{ok:!1,error:"Invalid tunnel signature"};let r=Number(e.timestampHeader);if(!Number.isFinite(r))return{ok:!1,error:"Invalid or missing tunnel timestamp"};if(Math.abs(Date.now()-r*1e3)>3e5)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let o=ut("sha256",n).update(e.body).digest("hex");try{if(!Ur(Buffer.from(o,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function dt(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function pt(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function gt(e){return e.status===0?`Could not reach delivery URL (${e.deliveryUrl}): ${e.ack.error??e.body}`:e.ack.error??e.body??`HTTP ${e.status}`}async function ft(e){let{body:n,headers:t}=_n(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),i=await r.text();return{ok:r.ok,status:r.status,body:i}}catch(r){return{ok:!1,status:0,body:r instanceof Error?r.message:"Delivery request failed"}}}import{randomBytes as xi}from"crypto";import{createHmac as Ti,randomBytes as Pi,timingSafeEqual as vi}from"crypto";function re(){return Pi(16).toString("base64url")}function Ze(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Ti("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[i,o]=r;if(!i||!o)return null;let s=Ze(i,t);try{if(!vi(Buffer.from(o,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(i,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function Dn(e,n,t){let r=Math.floor(Date.now()/1e3),i={...e,iat:r,exp:t},o=Buffer.from(JSON.stringify(i)).toString("base64url"),s=Ze(o,n);return`${o}.${s}`}function qe(e,n,t){let r=Math.floor(Date.now()/1e3);return Dn(e,n,r+Math.floor(t/1e3))}function ke(e){return decodeURIComponent(e)}function yt(e){return encodeURIComponent(e)}function Nr(e){let n=e.trim();return n.length>0?n:null}function On(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Mn(e,n){if(!Nr(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??xi(16).toString("base64url"),iat:t,exp:t+Math.floor(6e4/1e3)},i=Buffer.from(JSON.stringify(r)).toString("base64url"),o=Ze(i,n);return`${i}.${o}`}function pe(e,n){return Nr(n)?Q(e,n):null}function be(e){return e.deliveryMode==="connect.status"}function we(e){return e.deliveryMode==="auth.credentials"}function Ge(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function Je(e){return e.deliveryMode==="oauth.tokens"}function Hn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!be(e)&&!we(e)&&!Ge(e)&&!Je(e)}function mt(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 Ai(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 En({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function Ri(e,n,t){let r=await Ai(e,n,t),i={...t.query??{},...r?{tenantId:r}:{}},o=await Br(e,t.headers,t.body,i);if(!o.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(o.response&&o.response.success===!1)return{status:"failed",retryable:!1,error:typeof o.response.error=="string"?o.response.error:"Webhook handler failed"};let s=o.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(o.response?.data??o.response);return{status:"ok",webhookResponse:{status:o.response?.statusCode??200,body:a,headers:o.responseHeaders}}}async function Si(e,n){return await ze(e,n),{status:"ok"}}async function Ii(e,n){return await Me(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function kt(e,n,t){let r=await ht(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function ht(e,n,t){let r=P(e),i=n.token?.trim();if(!i)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let o=new Date().toISOString(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",i).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<o?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Ei(e,n){try{return await An(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function _i(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await De(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function bt(e,n,t={}){let r=P(e),i=mt(n.headers,"x-corsair-signature"),o=mt(n.headers,"x-corsair-timestamp"),s=mt(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let c=He({body:n.body,signatureHeader:i,timestampHeader:o,signingSecret:t.signingSecret});if(!c.ok)return{status:"failed",retryable:!1,error:c.error};if(!s?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let u=Sn(`nonce:${s.trim()}`,3e5);if(!u.ok)return{status:"failed",retryable:!1,error:u.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let a;try{a=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(a.type){case"webhook":return Ri(e,r,a.payload);case"oauth.callback":return Si(e,a.payload);case"oauth.tokens":return Ii(e,a.payload);case"permission.approve":return ht(e,a.payload,"approved");case"permission.deny":return ht(e,a.payload,"denied");case"auth.credentials":return Ei(e,a.payload);case"connect.status":return _i(e,a.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${a.type}`}}}var Di="corsair:client-bridge";function $r(e){let n=JSON.stringify({type:Di,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>
15
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Pr(e.db,c,d):{result:"blocked",reason:"pending",id:c,token:u,expiresAt:l}}var v=class extends Error{status;code;extra;constructor(n,t,r,i={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=i}};function A(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function Ar(e){let n={error:e.code,message:e.message,...e.extra};return A(e.status,n)}function ue(e){return new v(404,"not_found",e)}function V(e,n={}){return new v(400,"bad_request",e,n)}function Rr(e,n){return F(e,n,t=>ue(t))}async function ot(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=O({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),i=N[t].integration,o=r,s;try{s=await Promise.all(i.map(u=>o[`get_${u}`]()))}catch{s=i.map(()=>null)}let a=i.filter((u,d)=>s[d]==null),c;return t==="oauth_2"?c=!a.includes("client_id")&&!a.includes("client_secret"):c=a.length===0,{configured:c,missingFields:a}}async function Sr(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:i,missingFields:o}=await ot(e,n);return{id:e.id,authType:t,configured:i,missingFields:o,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function hn(){return{ok:!0}}async function kn(e){return Promise.all(e.plugins.map(n=>Sr(n,e)))}async function bn(e,n){let t=Rr(e,n);return Sr(t,e)}async function Ir(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 Er(e,n){let t=await Ir(e,n),r=t.filter(i=>i.hasCredentials).map(i=>i.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function wn(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let i=r.tenant_id;if(!i)continue;let o=n.get(i);o||(o={id:i,accounts:[],connectedPlugins:[]},n.set(i,o));let s=!!r.dek;o.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&o.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function Cn(e,n){if(!n)throw V("Tenant id must be a non-empty string");return Er(e,n)}async function Tn(e,n){let t=n?.id?.trim();if(!t)throw V("Tenant id is required",{missingFields:["id"]});return Er(e,t)}async function _e(e,n){let t=n?.trim()||"default",r={},i=e.database?await Ir(e,t):[],o=new Map(i.map(s=>[s.integrationName,s]));for(let s of e.plugins){if(!(await ot(s,e)).configured){r[s.id]="missing_credentials";continue}let c=o.get(s.id),u;c&&c.hasCredentials?u="connected":u="not_connected",r[s.id]=u}return r}async function it(e,n){if(!e.database)throw ue(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw ue(`Permission '${n}' not found`);return mn(e,t)}function ci(e){if(!e.oauthConfig)throw V(`Plugin '${e.id}' has no oauthConfig`)}function ui(e){if(!e.manual)throw new v(500,"connect_not_configured","createCorsair was not given manual config. Set { manual: { baseUrl, redirectUri } } to enable manual connect routes.");return e.manual}function st(e){let n=ui(e);if(!n.baseUrl?.trim()||!n.redirectUri?.trim())throw new v(500,"connect_not_configured","Manual connect requires manual.baseUrl and manual.redirectUri. Use hub for hosted connect, or set both URLs for manual OAuth.");return n}function li(e){let n=!!e.hub,t=Ie(e.manual);if(!n&&!t)throw new v(500,"connect_not_configured","createCorsair was not given connect config. Set hub: { ... } for Hub mode, or manual: { baseUrl, redirectUri } for manual connect.")}function _r(e){if(!e.database||!e.kek)throw new v(500,"database_not_configured","A database and kek are required to issue connect links.")}async function di(e,n){let t=n?.plugin?.trim();if(!t)throw V("Plugin id is required",{missingFields:["plugin"]});let r=n.tenantId?.trim()||"default",i=Rr(e,t);ci(i);let o=st(e);_r(e);let s=await ot(i,e);if(!s.configured)throw new v(400,"missing_credentials",`Plugin '${t}' is missing OAuth client credentials`,{missingFields:s.missingFields});let a=ae(z(t,r),e.kek),c;try{c=new URL(o.baseUrl)}catch{throw new v(500,"connect_misconfigured","manual.baseUrl is not a valid URL. Set a full URL including protocol (e.g. https://app.example.com/connect).")}return c.searchParams.set("state",a),{connectUrl:c.toString(),expiresAt:new Date(Date.now()+Kn).toISOString()}}async function pi(e,n,t){_r(n);let r=t.tenantId?.trim()||"default",i=H(e);if(t.source){let u=Re({source:t.source,deliveryUrl:i.deliveryUrl,oauthMode:t.oauthMode});if(u)throw V(u.error)}let o={tenantId:r,source:t.source??Ae(i.deliveryUrl),oauthMode:t.oauthMode},s=t.plugin?.trim();s&&(o.plugin=s);let a=t.providerName?.trim();a&&(o.providerName=a);let c=await ln(e,o);return{connectUrl:c.connectUrl,expiresAt:c.expiresAt}}async function Pn(e,n,t){return li(n),n.hub?pi(e,n,t):di(n,t)}async function vn(e,n,t){if(n.hub&&!Ie(n.manual))throw new v(400,"hub_mode","resolve is not used with hub config. Redirect users to connectUrl from createLink.");let r=t?.trim();if(!r)throw V("state is required",{missingFields:["state"]});st(n);try{return await Yn(e,r)}catch(i){if(i instanceof W)switch(i.code){case"invalid_state":throw V("Invalid or expired state");case"client_id_not_configured":throw new v(400,"missing_credentials","OAuth client_id is not configured for this plugin",{missingFields:["client_id"]});case"no_redirect_uri":break}throw new v(500,"resolve_failed","Could not resolve connect link. Check server logs for details.")}}async function xn(e,n,t){if(n.hub&&!Ie(n.manual))throw new v(400,"hub_mode","oauthCallback is not used with hub config. Hub delivers tokens to your deliveryUrl.");let r=t?.code?.trim(),i=t?.state?.trim(),o=[];if(r||o.push("code"),i||o.push("state"),o.length)throw V("Missing required fields",{missingFields:o});let s=st(n),{processOAuthCallback:a}=await import("./oauth.js");try{return await a(e,{code:r,state:i,redirectUri:s.redirectUri})}catch(c){if(c instanceof Error&&c.name==="OAuthCallbackError")switch(c.code){case"invalid_state":throw V("Invalid or expired state");case"credentials_not_configured":throw new v(400,"missing_credentials","OAuth client credentials are not configured for this plugin",{missingFields:["client_id","client_secret"]})}throw new v(502,"oauth_callback_failed","OAuth callback did not complete. Check server logs for details.")}}async function at(e,n){if(!e.database)throw ue("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw ue("Permission not found");return mn(e,t)}async function Dr(e,n){return"id"in n?it(e,n.id):at(e,n.token)}function gi(e){return e==="oauth_2"||e==="managed"?"oauth":e==="bot_token"?"bot_token":"api_key"}function fi(e,n){return n&&!n.has(e.id)?!1:$(e)!==null}async function De(e,n,t={}){let r=P(e),i=n.trim()||"default",o=t.pluginIds?.length?new Set(t.pluginIds):null,s=await _e(r,i),a=r.plugins.filter(c=>fi(c,o)).map(c=>{let u=$(c),d=s[c.id]??"not_connected";return{plugin:c.id,providerName:ye(c.id),authKind:gi(u),connected:d==="connected"}});return{tenantId:i,plugins:a}}var le=6e4,he=3e5;var Y=class extends Error{code;constructor(n,t){super(t),this.name="AuthCredentialsDeliveryError",this.code=n}};async function An(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=F(t,n.plugin,d=>new Y("plugin_not_found",d)),i=$(r);if(!i)throw new Y("invalid_credentials",`Plugin '${r.id}' has no authType configured`);if(i==="oauth_2"||i==="managed")throw new Y("invalid_credentials","OAuth plugins must be connected via sign-in, not credentials delivery");await Se(e,n.tenantId);let o=new Set(Xe(r,i)),a=r.authConfig?.[i]?.account??[],c=I({authType:i,integrationName:n.plugin,tenantId:n.tenantId,kek:t.kek,database:t.database,extraAccountFields:a}),u=0;for(let[d,l]of Object.entries(n.credentials)){if(!l.trim())continue;if(!o.has(d))throw new Y("invalid_credentials",`Unknown credential field '${d}' for plugin '${n.plugin}'`);let g=J(c,`set_${d}`);if(!g)throw new Y("invalid_credentials",`Cannot set credential field '${d}' for plugin '${n.plugin}'`);await g(l.trim()),u+=1}if(u===0)throw new Y("invalid_credentials","Provide at least one credential field to save");return{plugin:n.plugin,tenantId:n.tenantId}}var Rn=new Map;function yi(e){for(let[n,t]of Rn)t<=e&&Rn.delete(n)}function Sn(e,n){let t=e.trim();if(!t)return{ok:!1,error:"Delivery replay key is required"};let r=Date.now();return yi(r),Rn.has(t)?{ok:!1,error:"Delivery request already consumed"}:(Rn.set(t,r+n),{ok:!0})}async function In(e,n,t){for(let r of e){if(r.id!==n)continue;let i=r.oauthWebhookTenantLinkResolver;return i?i(t):null}return null}var Or=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};async function mi(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 hi(e){let n=await e.database.db.selectFrom("corsair_accounts").selectAll().where("id","=",e.accountId).executeTakeFirst();if(!n?.dek)throw new Error(`Account '${e.accountId}' has no DEK.`);let t=await L(n.dek,e.kek),r=Or(n.config),i={};Object.keys(r).length>0&&(i=te(r,t)),i[e.link.linkType]=e.link.externalId;let o=ce(i,t);await e.database.db.updateTable("corsair_accounts").set({config:o,updated_at:new Date}).where("id","=",n.id).execute()}async function Oe(e){let{database:n,kek:t,pluginId:r,tenantId:i,link:o,authType:s,extraAccountFields:a=[]}=e,{accountId:c}=await mi({database:n,pluginId:r,tenantId:i}),u=!1;if(s){let d=I({authType:s,integrationName:r,tenantId:i,kek:t,database:n,extraAccountFields:a}),l=`set_${o.linkType}`,g=d[l];typeof g=="function"&&(await g(o.externalId),u=!0)}u||await hi({database:n,kek:t,accountId:c,link:o})}async function ct(e){let{database:n,kek:t,pluginId:r,linkType:i,externalId:o}=e,s=await n.db.selectFrom("corsair_accounts as accounts").innerJoin("corsair_integrations as integrations","integrations.id","accounts.integration_id").selectAll("accounts").where("integrations.name","=",r).execute();for(let a of s)if(a.dek)try{let c=await L(a.dek,t),d=Or(a.config)[i];if(!d)continue;if(je(d,c)===o)return a}catch{continue}return null}async function En(e){return(await ct(e))?.tenant_id??null}async function Mr(e){return En({database:e.database,kek:e.kek,pluginId:e.pluginId,linkType:e.match.linkType,externalId:e.match.externalId})}var de=class extends Error{code;constructor(n,t){super(t),this.name="ManagedOAuthDeliveryError",this.code=n}};async function Me(e,n){let{plugin:t,tenantId:r,accessToken:i,refreshToken:o,expiresIn:s,scope:a}=n;if(!i.trim())throw new de("no_access_token","Managed OAuth delivery missing access_token");let c=P(e,()=>new de("invalid_corsair_instance","Invalid corsair instance"));if(!c.database)throw new de("no_database","No database configured on corsair instance");let u=F(c,t,l=>new de("plugin_not_found",l));await Se(e,r);let d=I({authType:"managed",integrationName:t,tenantId:r,kek:c.kek,database:c.database});await d.set_access_token(i),o&&await d.set_refresh_token(o),s&&await d.set_expires_at(String(Math.floor(Date.now()/1e3)+s)),a&&await d.set_scope(a);try{let l=await In(c.plugins,t,{access_token:i,refresh_token:o,scope:a});if(l)try{let g=u.authConfig?.managed?.account??[];await Oe({database:c.database,kek:c.kek,pluginId:t,tenantId:r,link:l,authType:"managed",extraAccountFields:g})}catch(g){console.warn(`[corsair:managed-oauth] Failed to persist webhook tenant link for '${t}' tenant '${r}':`,g)}}catch(l){console.warn(`[corsair:managed-oauth] Failed to resolve webhook tenant link for '${t}' tenant '${r}':`,l)}return{plugin:t,tenantId:r}}import{createHmac as ut,randomUUID as ki,timingSafeEqual as Hr}from"crypto";function Br(e){if(e)return e.startsWith("sha256=")?e.slice(7):e}function _n(e){let n=JSON.stringify({type:e.type,payload:e.payload}),t=Math.floor(Date.now()/1e3).toString(),r=ut("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":ki()}}}function lt(e){let n=e.signingSecret.trim();if(!n)return!1;let t=Br(e.signatureHeader);if(!t)return!1;let r=Number(e.timestampHeader);if(!Number.isFinite(r)||Math.abs(Date.now()-r*1e3)>3e5)return!1;let o=ut("sha256",n).update(e.body).digest("hex");try{return Hr(Buffer.from(o,"utf8"),Buffer.from(t,"utf8"))}catch{return!1}}function He(e){let n=e.signingSecret.trim();if(!n)return{ok:!1,error:"Tunnel signing secret is required"};let t=Br(e.signatureHeader);if(!t)return{ok:!1,error:"Invalid tunnel signature"};let r=Number(e.timestampHeader);if(!Number.isFinite(r))return{ok:!1,error:"Invalid or missing tunnel timestamp"};if(Math.abs(Date.now()-r*1e3)>3e5)return{ok:!1,error:"Tunnel request timestamp is outside the allowed window"};let o=ut("sha256",n).update(e.body).digest("hex");try{if(!Hr(Buffer.from(o,"utf8"),Buffer.from(t,"utf8")))return{ok:!1,error:"Invalid tunnel signature"}}catch{return{ok:!1,error:"Invalid tunnel signature"}}return{ok:!0}}function dt(e){if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function pt(e){return e.httpOk&&(e.status===204||e.body.status==="ok"||e.body.ok===!0)}function gt(e){return e.status===0?`Could not reach delivery URL (${e.deliveryUrl}): ${e.ack.error??e.body}`:e.ack.error??e.body??`HTTP ${e.status}`}async function ft(e){let{body:n,headers:t}=_n(e);try{let r=await fetch(e.deliveryUrl,{method:"POST",headers:t,body:n}),i=await r.text();return{ok:r.ok,status:r.status,body:i}}catch(r){return{ok:!1,status:0,body:r instanceof Error?r.message:"Delivery request failed"}}}function bi(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Ur(e,n,t=[]){for(let[r,i]of Object.entries(e))if(bi(i)){if(i.match(n))return{webhook:i,path:[...t,r]}}else if(i&&typeof i=="object"){let o=Ur(i,n,[...t,r]);if(o)return o}return null}function wi(e){let n={};for(let[t,r]of Object.entries(e))n[t.toLowerCase()]=Array.isArray(r)?r[0]:r;return n}function Ci(e){let n=e["x-goog-resource-uri"],t=e["x-goog-channel-id"];if(!n||!t)return null;let r={resourceId:e["x-goog-resource-id"]||"",resourceState:e["x-goog-resource-state"]||"",resourceUri:n,channelId:t,channelExpiration:e["x-goog-channel-expiration"]||""};return n.includes("/drive/")&&(r.kind="drive#change"),{message:{data:Buffer.from(JSON.stringify(r)).toString("base64"),messageId:e["x-goog-message-number"]||""}}}async function Fr(e,n,t,r){let i=wi(n),o=typeof t=="string"?JSON.parse(t):t;(!o||typeof o=="object"&&Object.keys(o).length===0)&&i["x-goog-resource-uri"]&&(o=Ci(i)||o);let a={headers:i,body:o,...r?{query:r}:{}},c=r?.tenantId||"default",u=e.withTenant?e.withTenant(c):e,d=en;for(let l of d){let g=u[l];if(!g||!g.webhooks||g.pluginWebhookMatcher&&!g.pluginWebhookMatcher(a))continue;let f=Ur(g.webhooks,a);if(!f)continue;let p=f.path.join("."),y={payload:o,headers:i,rawBody:typeof t=="string"?t:JSON.stringify(t),...r?{query:r}:{}};try{let m=await f.webhook.handler(y),h=!!Object.keys(m.returnToSender||{})?.length;return{plugin:l,action:p,body:o,response:h?{...m?.returnToSender,success:!0}:{success:!0},...m.responseHeaders&&{responseHeaders:m.responseHeaders}}}catch(m){return console.error(`Error executing webhook handler for ${l}.${p}:`,m),{plugin:l,action:p,body:o,response:{success:!1,error:m instanceof Error?m.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}import{randomBytes as xi}from"crypto";import{createHmac as Ti,randomBytes as Pi,timingSafeEqual as vi}from"crypto";function re(){return Pi(16).toString("base64url")}function Ze(e,n){let t=n.trim();if(!t)throw new Error("Signing secret is required");return Ti("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[i,o]=r;if(!i||!o)return null;let s=Ze(i,t);try{if(!vi(Buffer.from(o,"utf8"),Buffer.from(s,"utf8")))return null}catch{return null}let a;try{a=JSON.parse(Buffer.from(i,"base64url").toString("utf8"))}catch{return null}return a.exp*1e3<Date.now()?null:a}function Dn(e,n,t){let r=Math.floor(Date.now()/1e3),i={...e,iat:r,exp:t},o=Buffer.from(JSON.stringify(i)).toString("base64url"),s=Ze(o,n);return`${o}.${s}`}function qe(e,n,t){let r=Math.floor(Date.now()/1e3);return Dn(e,n,r+Math.floor(t/1e3))}function ke(e){return decodeURIComponent(e)}function yt(e){return encodeURIComponent(e)}function Nr(e){let n=e.trim();return n.length>0?n:null}function On(e,n){let t=new URL(e);return t.searchParams.set("d",n),t.toString()}function Mn(e,n){if(!Nr(n))throw new Error("Signing secret is required for browser delivery tokens");let t=Math.floor(Date.now()/1e3),r={...e,jti:e.jti??xi(16).toString("base64url"),iat:t,exp:t+Math.floor(6e4/1e3)},i=Buffer.from(JSON.stringify(r)).toString("base64url"),o=Ze(i,n);return`${i}.${o}`}function pe(e,n){return Nr(n)?Q(e,n):null}function be(e){return e.deliveryMode==="connect.status"}function we(e){return e.deliveryMode==="auth.credentials"}function Ge(e){return e.deliveryMode==="permission.approve"||e.deliveryMode==="permission.deny"}function Je(e){return e.deliveryMode==="oauth.tokens"}function Hn(e){return e.deliveryMode==="oauth.callback"||e.deliveryMode===void 0&&!be(e)&&!we(e)&&!Ge(e)&&!Je(e)}function mt(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 Ai(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 En({database:n.database,kek:n.kek,pluginId:t.plugin,linkType:t.linkType,externalId:t.externalId})??void 0)}async function Ri(e,n,t){let r=await Ai(e,n,t),i={...t.query??{},...r?{tenantId:r}:{}},o=await Fr(e,t.headers,t.body,i);if(!o.plugin)return{status:"failed",retryable:!1,error:"No matching webhook handler found"};if(o.response&&o.response.success===!1)return{status:"failed",retryable:!1,error:typeof o.response.error=="string"?o.response.error:"Webhook handler failed"};let s=o.response?.returnToSender,a=s&&typeof s=="object"&&typeof s.validationToken=="string"&&Object.keys(s).length===1?s.validationToken:s||(o.response?.data??o.response);return{status:"ok",webhookResponse:{status:o.response?.statusCode??200,body:a,headers:o.responseHeaders}}}async function Si(e,n){return await ze(e,n),{status:"ok"}}async function Ii(e,n){return await Me(e,{plugin:n.plugin,tenantId:n.tenantId,accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.expiresIn,scope:n.scope}),{status:"ok"}}async function kt(e,n,t){let r=await ht(e,{token:n},t);if(r.status!=="ok")throw new Error(r.error??"Permission decision failed")}async function ht(e,n,t){let r=P(e),i=n.token?.trim();if(!i)return{status:"failed",retryable:!1,error:"Permission token is required"};if(!r.database)return{status:"failed",retryable:!1,error:"Database not configured"};let o=new Date().toISOString(),s=await r.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",i).executeTakeFirst();return s?s.status!=="pending"?{status:"ok"}:s.expires_at<o?(await r.database.db.updateTable("corsair_permissions").set({status:"expired",updated_at:new Date}).where("id","=",s.id).execute(),{status:"failed",retryable:!1,error:"Permission has expired"}):(await r.database.db.updateTable("corsair_permissions").set({status:t,updated_at:new Date}).where("id","=",s.id).execute(),{status:"ok"}):{status:"failed",retryable:!1,error:"Permission not found"}}async function Ei(e,n){try{return await An(e,n),{status:"ok"}}catch(t){return{status:"failed",retryable:!1,error:t instanceof Error?t.message:"Credential delivery failed"}}}async function _i(e,n){let t=n.tenantId?.trim()||"default";try{return{status:"ok",webhookResponse:{status:200,body:await De(e,t,{pluginIds:n.plugins})}}}catch(r){return{status:"failed",retryable:!1,error:r instanceof Error?r.message:"Connect status introspection failed"}}}async function bt(e,n,t={}){let r=P(e),i=mt(n.headers,"x-corsair-signature"),o=mt(n.headers,"x-corsair-timestamp"),s=mt(n.headers,"x-corsair-nonce");if(t.signingSecret?.trim()){let c=He({body:n.body,signatureHeader:i,timestampHeader:o,signingSecret:t.signingSecret});if(!c.ok)return{status:"failed",retryable:!1,error:c.error};if(!s?.trim())return{status:"failed",retryable:!1,error:"Missing tunnel nonce"};let u=Sn(`nonce:${s.trim()}`,3e5);if(!u.ok)return{status:"failed",retryable:!1,error:u.error}}else if(!t.allowUnsignedTunnel)return{status:"failed",retryable:!1,error:"Tunnel signing secret is required"};let a;try{a=JSON.parse(n.body)}catch{return{status:"failed",retryable:!1,error:"Invalid tunnel envelope JSON"}}switch(a.type){case"webhook":return Ri(e,r,a.payload);case"oauth.callback":return Si(e,a.payload);case"oauth.tokens":return Ii(e,a.payload);case"permission.approve":return ht(e,a.payload,"approved");case"permission.deny":return ht(e,a.payload,"denied");case"auth.credentials":return Ei(e,a.payload);case"connect.status":return _i(e,a.payload);default:return{status:"failed",retryable:!1,error:`Unsupported tunnel type: ${a.type}`}}}var Di="corsair:client-bridge";function $r(e){let n=JSON.stringify({type:Di,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
16
  (function () {
17
17
  var message = ${n};
18
18
  var targetOrigin = ${t};
@@ -35,4 +35,4 @@ ${po(i,l)}`),y.join(`
35
35
  `)}}}return Kt(Te(e),"Path not found. Available operations")}function io(e){let n=e;for(;;){let t=K(n),r=Z(t);if(Jt(r)){let i=j(t);if(!i)return n;n=i;continue}return n}}function Ue(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=io(e),t=K(n);if(Z(t)==="ZodObject"){let i=$n(n,t),o=[];for(let[s,a]of Object.entries(i)){let c=K(a),u=Z(c),d=u==="ZodOptional"||u==="ZodNullable",l=io(a),g=Yi(a);o.push({key:s,optional:d,type:M(l),...g!==void 0?{description:g}:{}})}return{kind:"object",fields:o}}return{kind:"inline",type:M(n)}}function Nn(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=oo.repeat(n+1),r=oo.repeat(n);return`{
36
36
  ${e.fields.map(o=>{let s=o.optional?`${o.key}?`:o.key,a=o.description?` // ${o.description}`:"";return`${t}${s}: ${o.type}${a}`}).join(`
37
37
  `)}
38
- ${r}}`}return"unknown"}function rs(e,n){let t=Te(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(d=>d.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let i=[];for(let d of t){let{shortPath:l,lookupKey:g}=ts(d,n),f=ge(r.endpointMeta,g),p=ge(r.endpointSchemas,g);!f&&!p||i.push({path:d,shortPath:l,description:f?.description,riskLevel:f?.riskLevel,irreversible:f?.irreversible,input:Ue(p?.input),output:Ue(p?.output)})}i.sort((d,l)=>d.path.localeCompare(l.path));let o=[],s=Te(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let d of s){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("webhooks."))continue;let p=f.slice(9),y=Yt(r.webhooks,p.split("."));if(y===null)continue;let m=y.join("."),h=ge(r.webhookSchemas,m.toLowerCase()),C=h?.response?M(h.response):void 0;o.push({path:d,description:h?.description,payload:Ue(h?.payload),responseType:C,usageExample:po(n,y)})}o.sort((d,l)=>d.path.localeCompare(l.path));let a=[],c=Te(e,{plugin:n,type:"db"}),u=r.schema?.entities;if(Array.isArray(c)&&u)for(let d of c){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("db."))continue;let p=f.slice(3),y=p.lastIndexOf(".");if(y===-1)continue;let m=p.slice(0,y);if(p.slice(y+1)!=="search")continue;let C=lo(u,m);if(!C)continue;let[b,k]=C,w=Vt(k),T=Object.entries(w).map(([E,_])=>({field:E,type:_.type,operators:_.operators}));a.push({path:d,entityName:b,filters:[{field:"entity_id",type:"string",operators:zt},...T]})}return a.sort((d,l)=>d.path.localeCompare(l.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:a}}}function go(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function os(e,n){let t=go(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let i=r.pluginTenantWebhookMatcher(n);return i?{plugin:t,tenantMatch:i}:null}function is(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function fo(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function yo(e){if(typeof e=="string"){let n=e.trim();return n.length>0?n:void 0}if(typeof e=="number"&&Number.isFinite(e))return String(e)}function Qe(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function ss(e){return Qe(e.body)}function mo(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Ln(Array.isArray(r)?r:[r])}function ho(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let c of t){let u=Ln(Array.isArray(c)?c:[c]);if(u)return decodeURIComponent(u)}let r=mo({query:e.query},"validationToken");if(r)return r;let i=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let c of i){let u=n[c],d=Array.isArray(u)?u[0]:u;if(!(!d||typeof d!="string"))try{let g=(d.startsWith("http")?new URL(d):new URL(`https://example.invalid${d.startsWith("/")?d:`/${d}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let o=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,s=Qe(typeof o=="string"?(()=>{try{return JSON.parse(o)}catch{return o}})():o);return Ln([s?.validationToken])??null}function as(e){if(ho(e))return!0;let n=Qe(e.body??e.payload);return fo(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Ln(e){for(let n of e){let t=yo(n);if(t)return t}}function cs(e){let t=Qe(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var Ye=Symbol.for("corsair:internal");function lr(e){let n=e.database?Qt(e.database):void 0,t=n&&e.kek?Jr(e.plugins,n,e.kek):Un(!!n,!!e.kek),r=zr(e),i={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?nn(e.hub):void 0},o=vr(n),s=eo(i);if(e.multiTenancy)return Object.assign({withTenant:c=>{if(!c)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let u=jt(e.plugins,{database:n,tenantId:c,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(u,{[Ye]:i})},keys:t,permissions:o,manage:s},{[Ye]:i});let a=jt(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign({},a,{keys:t,permissions:o,manage:s,[Ye]:i})}var B=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function ko(e){let n=e.oauthConfig;if(!n)throw new B("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function us(e,n,t,r){let i=rr(e),o=await i.integrations.findByName(n);if(!o)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:t,integration_id:o.id}))return;let a=ee(),c=await ne(a,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:c})}async function Jn(e,n,t){let{tenantId:r,redirectUri:i}=t,o=P(e,()=>new B("invalid_corsair_instance","Invalid corsair instance"));if(!o.database)throw new Error("No database configured on corsair instance");let s=F(o,n,l=>new B("plugin_not_found",l)),a=ko(s),u=await O({authType:"oauth_2",integrationName:n,kek:o.kek,database:o.database}).get_client_id();if(!u)throw new Error(`client_id not configured for '${n}'`);let d=ae(z(n,r),o.kek);return{url:Ee({oauthConfig:a,clientId:u,redirectUri:i,state:d}),state:d}}async function ze(e,n){let{code:t,state:r,redirectUri:i}=n,o=P(e,()=>new B("invalid_corsair_instance","Invalid corsair instance")),s=cn(r,o.kek);if(!s)throw new B("invalid_state","Invalid or tampered state parameter");let{plugin:a,tenantId:c}=s;if(!o.database)throw new B("no_database","No database configured on corsair instance");let u=F(o,a,m=>new B("plugin_not_found",m)),d=ko(u),l=O({authType:"oauth_2",integrationName:a,kek:o.kek,database:o.database}),g=await l.get_client_id(),f=await l.get_client_secret();if(!g||!f)throw new B("credentials_not_configured",`Credentials not configured for '${a}'`);await us(o.database,a,c,o.kek);let p=await Fn(t,g,f,d,i);if(!p.access_token)throw new B("no_access_token",`No access_token returned from ${d.providerName}`);let y=I({authType:"oauth_2",integrationName:a,tenantId:c,kek:o.kek,database:o.database});await y.set_access_token(p.access_token),p.refresh_token&&await y.set_refresh_token(p.refresh_token),p.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+p.expires_in));try{let m=await In(o.plugins,a,p);if(m)try{let h=u.authConfig?.oauth_2?.account??[];await Oe({database:o.database,kek:o.kek,pluginId:a,tenantId:c,link:m,authType:"oauth_2",extraAccountFields:h})}catch(h){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${a}' tenant '${c}':`,h)}}catch(m){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${a}' tenant '${c}':`,m)}return{plugin:a,tenantId:c}}export{or as a,ye as b,Ne as c,me as d,nn as e,H as f,tn as g,rn as h,on as i,sn as j,ir as k,an as l,z as m,jn as n,ee as o,ne as p,L as q,zn as r,je as s,ce as t,te as u,Ke as v,O as w,I as x,br as y,wr as z,Oe as A,ct as B,En as C,Mr as D,Ee as E,B as F,Jn as G,ze as H,Le as I,Ae as J,Zn as K,sr as L,Re as M,cr as N,Ko as O,ln as P,Yn as Q,fn as R,yn as S,De as T,le as U,he as V,de as W,Me as X,Br as Y,_n as Z,lt as _,He as $,dt as aa,pt as ba,gt as ca,ft as da,re as ea,On as fa,Mn as ga,pe as ha,be as ia,we as ja,Ge as ka,Je as la,Hn as ma,kt as na,bt as oa,wt as pa,Ct as qa,Tt as ra,Pt as sa,vt as ta,Ve as ua,oe as va,xt as wa,jr as xa,Kr as ya,At as za,Rt as Aa,St as Ba,It as Ca,Et as Da,_t as Ea,Dt as Fa,Ot as Ga,Mt as Ha,Ht as Ia,Bt as Ja,Ut as Ka,Ft as La,Nt as Ma,$t as Na,Ce as Oa,Yr as Pa,Qr as Qa,Xr as Ra,no as Sa,Vi as Ta,Fn as Ua,hl as Va,Te as Wa,kl as Xa,Nn as Ya,rs as Za,go as _a,os as $a,is as ab,fo as bb,yo as cb,Qe as db,ss as eb,mo as fb,ho as gb,as as hb,Ln as ib,cs as jb,Ye as kb,lr as lb};
38
+ ${r}}`}return"unknown"}function rs(e,n){let t=Te(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(d=>d.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let i=[];for(let d of t){let{shortPath:l,lookupKey:g}=ts(d,n),f=ge(r.endpointMeta,g),p=ge(r.endpointSchemas,g);!f&&!p||i.push({path:d,shortPath:l,description:f?.description,riskLevel:f?.riskLevel,irreversible:f?.irreversible,input:Ue(p?.input),output:Ue(p?.output)})}i.sort((d,l)=>d.path.localeCompare(l.path));let o=[],s=Te(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let d of s){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("webhooks."))continue;let p=f.slice(9),y=Yt(r.webhooks,p.split("."));if(y===null)continue;let m=y.join("."),h=ge(r.webhookSchemas,m.toLowerCase()),C=h?.response?M(h.response):void 0;o.push({path:d,description:h?.description,payload:Ue(h?.payload),responseType:C,usageExample:po(n,y)})}o.sort((d,l)=>d.path.localeCompare(l.path));let a=[],c=Te(e,{plugin:n,type:"db"}),u=r.schema?.entities;if(Array.isArray(c)&&u)for(let d of c){let g=d.toLowerCase().slice(n.length+1),f=g.startsWith(".")?g.slice(1):g;if(!f.startsWith("db."))continue;let p=f.slice(3),y=p.lastIndexOf(".");if(y===-1)continue;let m=p.slice(0,y);if(p.slice(y+1)!=="search")continue;let C=lo(u,m);if(!C)continue;let[b,k]=C,w=Vt(k),T=Object.entries(w).map(([E,_])=>({field:E,type:_.type,operators:_.operators}));a.push({path:d,entityName:b,filters:[{field:"entity_id",type:"string",operators:zt},...T]})}return a.sort((d,l)=>d.path.localeCompare(l.path)),{ok:!0,data:{pluginId:n,api:i,webhooks:o,db:a}}}function go(e,n){for(let[t,r]of Object.entries(e))if(r?.pluginWebhookMatcher&&r.pluginWebhookMatcher(n))return t;return null}function os(e,n){let t=go(e,n);if(!t)return null;let r=e[t];if(!r?.pluginTenantWebhookMatcher)return null;let i=r.pluginTenantWebhookMatcher(n);return i?{plugin:t,tenantMatch:i}:null}function is(e){let n={};for(let t of e)!t.pluginWebhookMatcher&&!t.pluginTenantWebhookMatcher||(n[t.id]={pluginWebhookMatcher:t.pluginWebhookMatcher,pluginTenantWebhookMatcher:t.pluginTenantWebhookMatcher});return n}function fo(e,n){let t=n.toLowerCase(),r=e[t]??e[n];return Array.isArray(r)?r[0]:typeof r=="string"?r:void 0}function yo(e){if(typeof e=="string"){let n=e.trim();return n.length>0?n:void 0}if(typeof e=="number"&&Number.isFinite(e))return String(e)}function Qe(e){return!e||typeof e!="object"||Array.isArray(e)?null:e}function ss(e){return Qe(e.body)}function mo(e,n){let t=e.query;if(!t)return;let r=t[n]??t[n.toLowerCase()];return Ln(Array.isArray(r)?r:[r])}function ho(e){let n=e.headers??{},t=[n.validationtoken,n.validationToken,n["validation-token"],n["ms-validation-token"]];for(let c of t){let u=Ln(Array.isArray(c)?c:[c]);if(u)return decodeURIComponent(u)}let r=mo({query:e.query},"validationToken");if(r)return r;let i=["x-forwarded-uri","x-original-uri","x-rewrite-url","x-envoy-original-path","referer"];for(let c of i){let u=n[c],d=Array.isArray(u)?u[0]:u;if(!(!d||typeof d!="string"))try{let g=(d.startsWith("http")?new URL(d):new URL(`https://example.invalid${d.startsWith("/")?d:`/${d}`}`)).searchParams.get("validationToken");if(g?.trim())return g.trim()}catch{continue}}let o=e.payload!==void 0?e.payload:e.body!==void 0?e.body:void 0,s=Qe(typeof o=="string"?(()=>{try{return JSON.parse(o)}catch{return o}})():o);return Ln([s?.validationToken])??null}function as(e){if(ho(e))return!0;let n=Qe(e.body??e.payload);return fo(e.headers??{},"content-type")?.includes("text/plain")?!n||Object.keys(n).length===0:!1}function Ln(e){for(let n of e){let t=yo(n);if(t)return t}}function cs(e){let t=Qe(e.message)?.data;if(typeof t!="string")return null;try{return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}catch{return null}}var Ye=Symbol.for("corsair:internal");function lr(e){let n=e.database?Qt(e.database):void 0,t=n&&e.kek?Jr(e.plugins,n,e.kek):Un(!!n,!!e.kek),r=zr(e),i={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,permissions:r,manual:e.manual,hub:e.hub?nn(e.hub):void 0},o=vr(n),s=eo(i);if(e.multiTenancy)return Object.assign({withTenant:c=>{if(!c)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let u=jt(e.plugins,{database:n,tenantId:c,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign(u,{[Ye]:i})},keys:t,permissions:o,manage:s},{[Ye]:i});let a=jt(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,permissionsOptions:r,manualConfig:e.manual,hubConfig:i.hub});return Object.assign({},a,{keys:t,permissions:o,manage:s,[Ye]:i})}var B=class extends Error{code;constructor(n,t){super(t),this.name="OAuthCallbackError",this.code=n}};function ko(e){let n=e.oauthConfig;if(!n)throw new B("plugin_has_no_oauth_config",`Plugin '${e.id}' has no oauthConfig`);return n}async function us(e,n,t,r){let i=rr(e),o=await i.integrations.findByName(n);if(!o)throw new Error(`Integration '${n}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:t,integration_id:o.id}))return;let a=ee(),c=await ne(a,r);await i.accounts.create({tenant_id:t,integration_id:o.id,config:{},dek:c})}async function Jn(e,n,t){let{tenantId:r,redirectUri:i}=t,o=P(e,()=>new B("invalid_corsair_instance","Invalid corsair instance"));if(!o.database)throw new Error("No database configured on corsair instance");let s=F(o,n,l=>new B("plugin_not_found",l)),a=ko(s),u=await O({authType:"oauth_2",integrationName:n,kek:o.kek,database:o.database}).get_client_id();if(!u)throw new Error(`client_id not configured for '${n}'`);let d=ae(z(n,r),o.kek);return{url:Ee({oauthConfig:a,clientId:u,redirectUri:i,state:d}),state:d}}async function ze(e,n){let{code:t,state:r,redirectUri:i}=n,o=P(e,()=>new B("invalid_corsair_instance","Invalid corsair instance")),s=cn(r,o.kek);if(!s)throw new B("invalid_state","Invalid or tampered state parameter");let{plugin:a,tenantId:c}=s;if(!o.database)throw new B("no_database","No database configured on corsair instance");let u=F(o,a,m=>new B("plugin_not_found",m)),d=ko(u),l=O({authType:"oauth_2",integrationName:a,kek:o.kek,database:o.database}),g=await l.get_client_id(),f=await l.get_client_secret();if(!g||!f)throw new B("credentials_not_configured",`Credentials not configured for '${a}'`);await us(o.database,a,c,o.kek);let p=await Fn(t,g,f,d,i);if(!p.access_token)throw new B("no_access_token",`No access_token returned from ${d.providerName}`);let y=I({authType:"oauth_2",integrationName:a,tenantId:c,kek:o.kek,database:o.database});await y.set_access_token(p.access_token),p.refresh_token&&await y.set_refresh_token(p.refresh_token),p.expires_in&&await y.set_expires_at(String(Math.floor(Date.now()/1e3)+p.expires_in));try{let m=await In(o.plugins,a,p);if(m)try{let h=u.authConfig?.oauth_2?.account??[];await Oe({database:o.database,kek:o.kek,pluginId:a,tenantId:c,link:m,authType:"oauth_2",extraAccountFields:h})}catch(h){console.warn(`[corsair:oauth] Failed to persist webhook tenant link for '${a}' tenant '${c}':`,h)}}catch(m){console.warn(`[corsair:oauth] Failed to resolve webhook tenant link for '${a}' tenant '${c}':`,m)}return{plugin:a,tenantId:c}}export{or as a,ye as b,Ne as c,me as d,nn as e,H as f,tn as g,rn as h,on as i,sn as j,ir as k,an as l,z as m,jn as n,ee as o,ne as p,L as q,zn as r,je as s,ce as t,te as u,Ke as v,O as w,I as x,br as y,wr as z,Oe as A,ct as B,En as C,Mr as D,Ee as E,B as F,Jn as G,ze as H,Le as I,Ae as J,Zn as K,sr as L,Re as M,cr as N,Ko as O,ln as P,Yn as Q,fn as R,yn as S,De as T,le as U,he as V,de as W,Me as X,_n as Y,lt as Z,He as _,dt as $,pt as aa,gt as ba,ft as ca,Fr as da,re as ea,On as fa,Mn as ga,pe as ha,be as ia,we as ja,Ge as ka,Je as la,Hn as ma,kt as na,bt as oa,wt as pa,Ct as qa,Tt as ra,Pt as sa,vt as ta,Ve as ua,oe as va,xt as wa,jr as xa,Kr as ya,At as za,Rt as Aa,St as Ba,It as Ca,Et as Da,_t as Ea,Dt as Fa,Ot as Ga,Mt as Ha,Ht as Ia,Bt as Ja,Ut as Ka,Ft as La,Nt as Ma,$t as Na,Ce as Oa,Yr as Pa,Qr as Qa,Xr as Ra,no as Sa,Vi as Ta,Fn as Ua,hl as Va,Te as Wa,kl as Xa,Nn as Ya,rs as Za,go as _a,os as $a,is as ab,fo as bb,yo as cb,Qe as db,ss as eb,mo as fb,ho as gb,as as hb,Ln as ib,cs as jb,Ye as kb,lr as lb};
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{$a as x,Q as p,Sa as r,Ta as s,Ua as t,Ya as u,Za as v,_a as w,a,ab as y,b,bb as z,cb as A,db as B,eb as C,fb as D,gb as E,hb as F,ib as G,jb as H,kb as I,lb as J,o as d,p as e,q as f,r as g,s as h,t as i,u as j,v as k,va as q,w as l,x as m,y as n,z as o}from"./chunk-2LV4I6JX.js";import{g as c}from"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,p as resolveConnectLink,A as toExternalId};
1
+ import{$a as x,Q as p,Sa as r,Ta as s,Ua as t,Ya as u,Za as v,_a as w,a,ab as y,b,bb as z,cb as A,db as B,eb as C,fb as D,gb as E,hb as F,ib as G,jb as H,kb as I,lb as J,o as d,p as e,q as f,r as g,s as h,t as i,u as j,v as k,va as q,w as l,x as m,y as n,z as o}from"./chunk-6LBMTCN6.js";import{g as c}from"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{q as AuthMissingError,c as BASE_AUTH_FIELDS,I as CORSAIR_INTERNAL,a as ProviderDisplayNames,B as asRecord,y as collectPluginWebhookMatchers,m as createAccountKeyManager,J as createCorsair,l as createIntegrationKeyManager,H as decodePubSubData,j as decryptConfig,f as decryptDEK,h as decryptWithDEK,i as encryptConfig,e as encryptDEK,g as encryptWithDEK,t as exchangeCodeForTokens,E as extractMicrosoftGraphValidationToken,G as firstString,u as formatDocSchemaShape,b as formatProviderDisplayName,d as generateDEK,z as getHeader,o as initializeAccountDEK,n as initializeIntegrationDEK,v as introspectPluginForDocs,F as isMicrosoftGraphValidationHandshake,r as logEvent,s as logEventFromContext,w as matchWebhookPlugin,x as matchWebhookPluginAndTenant,k as reEncryptConfig,C as readBodyRecord,D as readQueryParam,p as resolveConnectLink,A as toExternalId};
package/dist/hub.js CHANGED
@@ -1 +1 @@
1
- import{$ as A,Aa as T,Ba as U,Ca as V,Da as W,Ea as X,Fa as Y,Ga as Z,Ha as _,I as l,Ia as $,J as m,Ja as aa,K as n,Ka as ba,L as o,La as ca,M as p,Ma as da,Na as ea,P as q,R as r,S as s,T as t,U as u,V as v,W as w,X as x,Z as y,_ as z,aa as B,b as a,ba as C,c as b,ca as D,d as c,da as E,e as d,ea as F,f as e,fa as G,g as f,ga as H,h as g,ha as I,i as h,j as i,k as j,l as k,pa as J,qa as K,ra as L,sa as M,ta as N,ua as O,wa as P,xa as Q,ya as R,za as S}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.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,w as ManagedOAuthDeliveryError,v as SIGNED_TUNNEL_REPLAY_WINDOW_MS,Q as attachManagedRefreshAuth,G as buildBrowserDeliveryRedirectUrl,S as createConnectSessionJti,X as createConnectTokenJti,q as createHubConnectSession,r as createHubPermissionSession,R as createHubRouteHandlers,ba as createPermissionSessionJti,F as createSignedTokenJti,W as decodeConnectSessionTokenFromPath,aa as decodeConnectTokenFromPath,ea as decodePermissionTokenFromPath,E as deliverSignedEnvelope,$ as encodeConnectTokenForPath,s as formatHubApprovalMessage,a as formatProviderDisplayName,D as formatServerDeliveryError,T as getConnectSessionExpiryMs,t as getConnectStatusForTenant,Y as getConnectTokenExpiryMs,e as getHubConfig,P as getManagedAccessToken,J as handleHubDeliveryGet,K as handleHubDeliveryPost,M as handleHubDeliveryRequest,L as hubDeliveryToResponse,l as isLoopbackDeliveryUrl,C as isServerDeliveryAckSuccessful,d as normalizeHubConfig,g as parseConnectSessionResponse,j as parseConnectStatusResponse,k as parseHubApiErrorBody,i as parseOAuthRefreshResponse,h as parsePermissionSessionResponse,B as parseServerDeliveryAckBody,x as processManagedOAuthDelivery,m as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,N as respondToHubDelivery,O as respondToHubDeliveryFromRequest,o as shouldUseBrowserConnectDelivery,n as shouldUseBrowserDelivery,H as signBrowserDeliveryToken,U as signConnectSessionToken,Z as signConnectToken,y as signDeliveryEnvelope,ca as signPermissionToken,p as validateExplicitConnectSource,I as verifyBrowserDeliveryToken,V as verifyConnectSessionToken,_ as verifyConnectToken,z as verifyDeliveryEnvelope,da as verifyPermissionToken,A as verifySignedTunnelDelivery};
1
+ import{$ as B,Aa as T,Ba as U,Ca as V,Da as W,Ea as X,Fa as Y,Ga as Z,Ha as _,I as l,Ia as $,J as m,Ja as aa,K as n,Ka as ba,L as o,La as ca,M as p,Ma as da,Na as ea,P as q,R as r,S as s,T as t,U as u,V as v,W as w,X as x,Y as y,Z as z,_ as A,aa as C,b as a,ba as D,c as b,ca as E,d as c,e as d,ea as F,f as e,fa as G,g as f,ga as H,h as g,ha as I,i as h,j as i,k as j,l as k,pa as J,qa as K,ra as L,sa as M,ta as N,ua as O,wa as P,xa as Q,ya as R,za as S}from"./chunk-6LBMTCN6.js";import"./chunk-NZS35HPL.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,w as ManagedOAuthDeliveryError,v as SIGNED_TUNNEL_REPLAY_WINDOW_MS,Q as attachManagedRefreshAuth,G as buildBrowserDeliveryRedirectUrl,S as createConnectSessionJti,X as createConnectTokenJti,q as createHubConnectSession,r as createHubPermissionSession,R as createHubRouteHandlers,ba as createPermissionSessionJti,F as createSignedTokenJti,W as decodeConnectSessionTokenFromPath,aa as decodeConnectTokenFromPath,ea as decodePermissionTokenFromPath,E as deliverSignedEnvelope,$ as encodeConnectTokenForPath,s as formatHubApprovalMessage,a as formatProviderDisplayName,D as formatServerDeliveryError,T as getConnectSessionExpiryMs,t as getConnectStatusForTenant,Y as getConnectTokenExpiryMs,e as getHubConfig,P as getManagedAccessToken,J as handleHubDeliveryGet,K as handleHubDeliveryPost,M as handleHubDeliveryRequest,L as hubDeliveryToResponse,l as isLoopbackDeliveryUrl,C as isServerDeliveryAckSuccessful,d as normalizeHubConfig,g as parseConnectSessionResponse,j as parseConnectStatusResponse,k as parseHubApiErrorBody,i as parseOAuthRefreshResponse,h as parsePermissionSessionResponse,B as parseServerDeliveryAckBody,x as processManagedOAuthDelivery,m as resolveConnectSourceFromDeliveryUrl,f as resolveHubOAuthCallbackUrl,N as respondToHubDelivery,O as respondToHubDeliveryFromRequest,o as shouldUseBrowserConnectDelivery,n as shouldUseBrowserDelivery,H as signBrowserDeliveryToken,U as signConnectSessionToken,Z as signConnectToken,y as signDeliveryEnvelope,ca as signPermissionToken,p as validateExplicitConnectSource,I as verifyBrowserDeliveryToken,V as verifyConnectSessionToken,_ as verifyConnectToken,z as verifyDeliveryEnvelope,da as verifyPermissionToken,A as verifySignedTunnelDelivery};
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{$a as M,A as P,B as x,C as b,D as I,N as R,Oa as L,Pa as A,Q as w,Qa as v,Ra as $,Va as d,Wa as g,Xa as C,Y as S,Ya as f,_a as E,ab as W,bb as F,cb as _,db as N,eb as D,ib as H,jb as j,kb as k,lb as J,oa as O,va as T}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";var u=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 U(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:c,...t}=r;return new u(n.status,o,e,t)}function q(n){let r=U(n.baseURL),o=n.fetch??((...t)=>globalThis.fetch(...t));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 c=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:t=>a("/tenants",t),get:t=>e(`/tenants/${c(t)}`)},plugins:{list:()=>e("/plugins"),get:t=>e(`/plugins/${c(t)}`)},connectionStatus:{get:t=>{let s={};return t?.tenantId&&(s.tenantId=t.tenantId),e("/connection-status",s)}},permissions:{get:t=>"id"in t?e(`/permissions/${c(t.id)}`):a("/permissions/lookup-by-token",{token:t.token})},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 B(n,r){let o=g(l(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
1
+ import{$a as M,A as P,B as x,C as b,D as I,N as R,Oa as L,Pa as A,Q as w,Qa as v,Ra as $,Va as d,Wa as g,Xa as C,Ya as f,_a as E,ab as W,bb as F,cb as _,da as S,db as N,eb as D,ib as H,jb as j,kb as k,lb as J,oa as O,va as T}from"./chunk-6LBMTCN6.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";var u=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 U(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:c,...t}=r;return new u(n.status,o,e,t)}function q(n){let r=U(n.baseURL),o=n.fetch??((...t)=>globalThis.fetch(...t));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 c=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:t=>a("/tenants",t),get:t=>e(`/tenants/${c(t)}`)},plugins:{list:()=>e("/plugins"),get:t=>e(`/plugins/${c(t)}`)},connectionStatus:{get:t=>{let s={};return t?.tenantId&&(s.tenantId=t.tenantId),e("/connection-status",s)}},permissions:{get:t=>"id"in t?e(`/permissions/${c(t.id)}`):a("/permissions/lookup-by-token",{token:t.token})},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 B(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{T as AuthMissingError,u as CorsairClientError,N as asRecord,W as collectPluginWebhookMatchers,J as createCorsair,q as createCorsairClient,j as decodePubSubData,Q as executePermission,H as firstString,f as formatDocSchemaShape,F as getHeader,G as getSchema,Y as getStructuredSchema,B as listOperations,L as managementHandler,E as matchWebhookPlugin,M as matchWebhookPluginAndTenant,O as processCorsair,S as processWebhook,D as readBodyRecord,x as resolveAccountFromWebhookLink,w as resolveConnectLink,I as resolveTenantFromWebhookLink,b as resolveTenantIdFromWebhookLink,P as setWebhookTenantLink,R as setupCorsair,A as toExpressHandler,_ as toExternalId,v as toHonoHandler,$ as toNextJsHandler};
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{E as c,F as d,G as e,H as f,m as a,n as b}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{d as OAuthCallbackError,c as buildOAuthAuthorizeUrl,b as decodeOAuthState,a as encodeOAuthState,e as generateOAuthUrl,f as processOAuthCallback};
1
+ import{E as c,F as d,G as e,H as f,m as a,n as b}from"./chunk-6LBMTCN6.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{d as OAuthCallbackError,c as buildOAuthAuthorizeUrl,b as decodeOAuthState,a as encodeOAuthState,e as generateOAuthUrl,f as processOAuthCallback};
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{N as a,O as b}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{b as applySetupCredentials,a as setupCorsair};
1
+ import{N as a,O as b}from"./chunk-6LBMTCN6.js";import"./chunk-NZS35HPL.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{A as a,B as b,C as c,D as d,ha as e,ia as f,ja as g,ka as h,la as i,ma as j,na as k,oa as l}from"./chunk-2LV4I6JX.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{k as applyPermissionDecision,g as isAuthCredentialsBrowserDelivery,j as isByoOAuthBrowserDelivery,f as isConnectStatusBrowserDelivery,i as isManagedBrowserDelivery,h as isPermissionBrowserDelivery,l as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,e as verifyBrowserDeliveryToken};
1
+ import{A as a,B as b,C as c,D as d,ha as e,ia as f,ja as g,ka as h,la as i,ma as j,na as k,oa as l}from"./chunk-6LBMTCN6.js";import"./chunk-NZS35HPL.js";import"./chunk-IGGCNGU2.js";import"./chunk-QAIKSQAD.js";export{k as applyPermissionDecision,g as isAuthCredentialsBrowserDelivery,j as isByoOAuthBrowserDelivery,f as isConnectStatusBrowserDelivery,i as isManagedBrowserDelivery,h as isPermissionBrowserDelivery,l as processCorsair,b as resolveAccountFromWebhookLink,d as resolveTenantFromWebhookLink,c as resolveTenantIdFromWebhookLink,a as setWebhookTenantLink,e as verifyBrowserDeliveryToken};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.84",
3
+ "version": "0.1.85",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",