corsair 0.1.75 → 0.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ import{a as Ke,b as Pe}from"./chunk-OZHME3EO.js";import{a as Ze}from"./chunk-FL4GOHVN.js";var L=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}};import{createCipheriv as Be,createDecipheriv as He,randomBytes as ie,scrypt as In}from"crypto";import{promisify as _n}from"util";var Le=_n(In),se="aes-256-gcm",je=12,ae=16,Dn=16,te=32;function j(){return ie(te).toString("base64")}async function W(e,n){let t=ie(Dn),r=await Le(n,t,te),o=ie(je),i=Be(se,r,o,{authTagLength:ae}),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 N(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"),d=Buffer.from(o,"base64"),u=Buffer.from(i,"base64"),c=await Le(n,s,te),p=He(se,c,a,{authTagLength:ae});return p.setAuthTag(d),Buffer.concat([p.update(u),p.final()]).toString("utf8")}function Te(e,n){let t=Buffer.from(n,"base64"),r=ie(je),o=Be(se,t,r,{authTagLength:ae}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function xe(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"),d=Buffer.from(o,"base64"),u=He(se,i,s,{authTagLength:ae});return u.setAuthTag(a),Buffer.concat([u.update(d),u.final()]).toString("utf8")}function Q(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=Te(o,n);return t}function U(e,n){let t={};for(let[r,o]of Object.entries(e))t[r]=xe(o,n);return t}function re(e,n,t){let r=U(e,n);return Q(r,t)}function ce(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.
2
+
3
+ To generate a KEK, run: openssl rand -base64 ${te}`)}})}var q={oauth_2:{integration:["client_id","client_secret","redirect_url"],account:["access_token","refresh_token","expires_at","scope","webhook_signature"]},api_key:{integration:[],account:["api_key","webhook_signature"]},bot_token:{integration:[],account:["bot_token","webhook_signature"]}};function We(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 Ae=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function Z(e){let{authType:n,integrationName:t,kek:r,database:o,extraIntegrationFields:i=[]}=e,s=[...q[n].integration,...i],a=null,d={kek:r,integrationName:t,getIntegration:async()=>{if(a)return a;let l=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!l)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return a={id:l.id,config:Ae(l.config),dek:l.dek??null},a},updateIntegration:async l=>{let m=await d.getIntegration();await o.db.updateTable("corsair_integrations").set({...l.config!==void 0?{config:l.config}:{},...l.dek!==void 0?{dek:l.dek}:{},updated_at:new Date}).where("id","=",m.id).execute(),a=null}},u=null,c=async()=>{if(u)return u;let l=await d.getIntegration();if(!l.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return u=await N(l.dek,r),u},p=async()=>{let l=await d.getIntegration(),m=await c(),b=l.config;return!b||Object.keys(b).length===0?{}:U(b,m)};return{get_dek:c,issue_new_dek:async()=>{let l=await d.getIntegration(),m=j(),b={};if(l.dek){let w=await N(l.dek,r),T=l.config;T&&Object.keys(T).length>0&&(b=re(T,w,m))}let k=await W(m,r);return await d.updateIntegration({config:b,dek:k}),u=m,m},...We(p,async l=>{let m=await c(),b;try{b=await p()}catch(T){console.error(`[corsair] Failed to decrypt config for integration "${t}", starting fresh:`,T),b={}}let k={...b};for(let[T,y]of Object.entries(l))y===null?delete k[T]:k[T]=y;let w=Q(k,m);await d.updateIntegration({config:w})},s)}}function de(e){let{authType:n,integrationName:t,tenantId:r,kek:o,database:i,extraAccountFields:s=[]}=e,a=[...q[n].account,...s],d=null,u=null,c=async()=>{if(u)return u;let y=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!y)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);return u={id:y.id,config:Ae(y.config),dek:y.dek??null},u},p={kek:o,integrationName:t,tenantId:r,getIntegration:c,getAccount:async()=>{if(d)return d;let y=await c(),h=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",y.id).executeTakeFirst();if(!h)throw new Error(`Account not found for tenant "${r}" and integration "${t}". Make sure to create the account first.`);return d={id:h.id,config:Ae(h.config),dek:h.dek??null},d},updateAccount:async y=>{let h=await p.getAccount();await i.db.updateTable("corsair_accounts").set({...y.config!==void 0?{config:y.config}:{},...y.dek!==void 0?{dek:y.dek}:{},updated_at:new Date}).where("id","=",h.id).execute(),d=null}},f=null,g=null,l=async()=>{if(f)return f;let y=await p.getAccount();if(!y.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${t}"). Initialize the account first.`);return f=await N(y.dek,o),f},m=async()=>{if(g)return g;let y=await p.getIntegration();if(!y.dek)throw new Error(`No DEK found for integration "${t}". Initialize the integration first.`);return g=await N(y.dek,o),g},b=async()=>{let y=await p.getAccount(),h=await l(),P=y.config;return!P||Object.keys(P).length===0?{}:U(P,h)},k=async()=>{let y=await p.getIntegration(),h=await m(),P=y.config;return!P||Object.keys(P).length===0?{}:U(P,h)},T={get_dek:l,issue_new_dek:async()=>{let y=await p.getAccount(),h=j(),P={};if(y.dek){let _=await N(y.dek,o),C=y.config;C&&Object.keys(C).length>0&&(P=re(C,_,h))}let A=await W(h,o);return await p.updateAccount({config:P,dek:A}),f=h,h},...We(b,async y=>{let h=await l(),P;try{P=await b()}catch(C){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${t}"), starting fresh:`,C),P={}}let A={...P};for(let[C,M]of Object.entries(y))M===null?delete A[C]:A[C]=M;let _=Q(A,h);await p.updateAccount({config:_})},a)};return n==="oauth_2"&&(T.get_integration_credentials=async()=>{let y=await k();return{client_id:y.client_id||null,client_secret:y.client_secret||null,redirect_url:y.redirect_url??null}}),T}async function Ue(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=j(),i=await W(o,t);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function qe(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=j(),a=await W(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}import*as oe from"crypto";function ze(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function vn(e,{maxAgeMs:n}={}){try{let t=e.includes(".")?e.split(".")[0]:e,r=JSON.parse(Buffer.from(t,"base64url").toString("utf-8"));if(r!==null&&typeof r=="object"&&"plugin"in r&&"tenantId"in r&&typeof r.plugin=="string"&&typeof r.tenantId=="string"){let o=r;return n!==void 0&&typeof o.iat=="number"&&Date.now()-o.iat>n?null:o}return null}catch{return null}}function Ge(e,n){let t=oe.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${t}`}var Sn=600*1e3;function Je(e,n){let t=e.lastIndexOf(".");if(t===-1)return null;let r=e.slice(0,t),o=e.slice(t+1),i=oe.createHmac("sha256",n).update(r).digest("base64url"),s=Buffer.from(o,"base64url"),a=Buffer.from(i,"base64url");return s.length!==a.length||!oe.timingSafeEqual(s,a)?null:vn(r,{maxAgeMs:Sn})}var On=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Ve(e,n,t,r,o){let i={pluginId:n,operation:t,input:r,originalError:e},s=Object.keys(o).find(u=>o[u]?.match(e,i));return await(o[s||"DEFAULT"]?.handler||On)(e,i)}import{randomBytes as Mn}from"crypto";import{v4 as Fn}from"uuid";var $n={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 Nn(e,n,t){return t!==void 0?t:$n[n][e]}function Qe(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 Xe(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 Ye(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 en(e){let n=Nn(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}'.`,`
4
+ Action: ${r}`,`
5
+ To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let o=JSON.stringify(e.args),i=new Date().toISOString(),s=e.tenantId??"default",a=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",o).where("tenant_id","=",s).where("expires_at",">",i).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(a){if(a.status==="approved"){let l=e.db,m=a.id;return{result:"allow",onComplete:async()=>{await l.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",m).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
6
+ Action: ${r}`,`
7
+ Permission ID: ${a.id}`,`
8
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Ye(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:a.id,token:a.token})}let d=Fn(),u=Mn(32).toString("hex"),c=e.timeoutMs??600*1e3,p=new Date(Date.now()+c).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:d,created_at:new Date,updated_at:new Date,token:u,plugin:e.pluginId,endpoint:e.endpointPath,args:o,tenant_id:s,status:"pending",expires_at:p}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
9
+ Action: ${r}`,`
10
+ Permission ID: ${d}`,`
11
+ Permission token: ${u}`,`
12
+ Expires at: ${p}`,`
13
+ Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Ye(e.db,d,c):{result:"blocked",reason:"pending",id:d,token:u}}function Zn(e){return typeof e=="function"}function Kn(e,n,t){let r=Ge(ze(e,n.tenantId??t??"default"),n.kek),o=new URL(n.baseUrl);o.searchParams.set("state",r);let i=o.toString(),s=n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:i,state:r}):`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${i}`;return new Error(s)}function Re({endpoints:e,hooks:n,ctx:t,tree:r,pluginId:o,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:d,endpointMeta:u,database:c,approvalConfig:p,tenantId:f,connectConfig:g}){for(let[l,m]of Object.entries(e)){let b=n?.[l];if(Zn(m)){let k=b,w=[...s,l].join("."),T=async(y={})=>{let h;if(d){let R=u?.[w],{result:Y,reason:O,onComplete:ne,token:F,id:H}=await en({pluginId:o,endpointPath:w,args:y,mode:d.mode,override:d.overrides?.[w],riskLevel:R?.riskLevel??"write",meta:R,db:c,timeoutMs:p?Qe(p.timeout):void 0,tenantId:f,approvalMode:p?.mode});if(Y==="blocked"){let x;throw O==="denied"?x=`Action '${w}' was denied by the user. Await further instructions before proceeding.`:O==="policy"?x=`Action '${w}' is blocked by the permission policy. Update the corsair config to allow it.`:O==="timeout"?x=`Action '${w}' timed out waiting for approval.`:p?.formatAsyncMessage&&F&&H?x=p.formatAsyncMessage({token:F,id:H,plugin:o,endpoint:w,args:y}):x=`Action '${w}' requires user approval before it can run.`,new Error(x)}h=ne}let P=async(R,Y,O)=>{try{return await m(Y,O)}catch(ne){if(ne instanceof Error){let F=await Ve(ne,o,w,typeof O=="object"&&O!==null?O:{args:O},i);if(R<(F.maxRetries||0)){let H=R+1;console.log(`Retrying (${H} / ${F.maxRetries})...`);let x;if(F.headersRetryAfterMs)x=F.headersRetryAfterMs;else switch(F.retryStrategy){case"exponential_backoff":x=Math.pow(2,H-1)*1e3;break;case"exponential_backoff_jitter":let Ce=Math.pow(2,H-1)*1e3,En=(Math.random()-.5)*1e3;x=Math.max(0,Ce+En);break;case"linear_1s":x=1e3;break;case"linear_2s":x=2e3;break;case"linear_3s":x=3e3;break;case"linear_4s":x=4e3;break;default:x=1e3;break}await new Promise(Ce=>setTimeout(Ce,x)),await P(H,Y,O),console.log(`[corsair:${o}:${w}] Retry strategy:`,F)}}throw ne}},A;try{A=a?await a(t,"endpoint"):void 0}catch(R){throw g?.oauthConfig&&g.kek&&R instanceof L&&R.authType==="oauth_2"?Kn(o,g,f):R}if(!k?.before&&!k?.after){let R=await P(0,{...t,key:A},y);return await h?.(),R}let _={...t,key:A},C=k.before?await k.before(_,y):{ctx:_,args:y,continue:!0,passToAfter:void 0};if(C.continue===!1)return;let M=await P(0,C.ctx,C.args);return await k.after?.(C.ctx,M,C.passToAfter),await h?.(),M};r[l]=T}else if(m&&typeof m=="object"){let k={};Re({endpoints:m,hooks:b,ctx:t,tree:k,pluginId:o,errorHandlers:i,currentPath:[...s,l],keyBuilder:a,permissionsConfig:d,endpointMeta:u,database:c,approvalConfig:p,tenantId:f,connectConfig:g}),r[l]=k}}}function Bn(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Ee({webhooks:e,hooks:n,ctx:t,webhooksTree:r,keyBuilder:o}){for(let[i,s]of Object.entries(e)){let a=n?.[i];if(Bn(s)){let d=a,u=async c=>{let p=(g,l)=>s.handler(g,l),f=o?await o(t,"webhook"):void 0;return!d?.before&&!d?.after?p({...t,key:f},c):(async()=>{let g={...t,key:f},l=d.before?await d.before(g,c):{ctx:g,args:c,continue:!0,passToAfter:void 0};if(l.continue===!1)return;let m=await p(l.ctx,l.args);return m?.success===!0&&await d.after?.(l.ctx,m,l.passToAfter),m})()};r[i]={match:s.match,handler:u}}else if(s&&typeof s=="object"){let d={};Ee({webhooks:s,hooks:a,ctx:t,webhooksTree:d,keyBuilder:o}),r[i]=d}}}function Hn(e,n,t){let r=null;return async()=>{if(r)return r;if(!e)throw new Error("Database not configured");let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!o)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);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}". Make sure to create the account first.`);return r=i.id,r}}function Ln(e,n,t,r,o){return e?Pe(e.db,n,t,r,o):{findByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function Ie(e,n){let{database:t,tenantId:r,kek:o,rootErrorHandlers:i,approvalConfig:s,connectConfig:a}=n,d={},u={};for(let c of e)d[c.id]={},u[c.id]={};for(let c of e){let p=c.schema,f=r??"default",g=Hn(t,c.id,f);if(p?.entities){let C={};for(let[M,R]of Object.entries(p.entities)){let Y=t?Pe(t.db,g,M,p.version,R):Ln(void 0,g,M,p.version,R);C[M]=Y}u[c.id].db=C,d[c.id].db=C}let l=c.options,m=c.authConfig,b;if(t&&o&&l?.authType){let C=m?.[l.authType]?.account??[];b=de({authType:l.authType,integrationName:c.id,tenantId:f,kek:o,database:t,extraAccountFields:C}),d[c.id].keys=b}let k={database:t,db:u[c.id]?.db??{},$getAccountId:g,...c.options?{options:c.options}:{},...b?{keys:b,authType:l?.authType}:{},...r?{tenantId:r}:{}},w=c.endpoints??{},T=c.hooks,y={...i,...c.errorHandlers},h={},P=c.options?.permissions;Re({endpoints:w,hooks:T,ctx:k,tree:h,pluginId:c.id,errorHandlers:y,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:P,endpointMeta:c.endpointMeta,database:t,approvalConfig:s,tenantId:r,connectConfig:a?{...a,oauthConfig:c.oauthConfig,kek:o,tenantId:f}:void 0}),Object.keys(h).length>0&&(d[c.id].api=h),k.endpoints=h;let A=c.webhooks??{},_=c.webhookHooks;if(Object.keys(A).length>0){let C={};Ee({webhooks:A,hooks:_,ctx:k,webhooksTree:C,keyBuilder:c.keyBuilder}),d[c.id].webhooks=C,c.pluginWebhookMatcher&&(d[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher)}}return d}function nn(e,n,t){let r={};for(let o of e){let i=o.options,s=o.authConfig;if(i?.authType){let a=s?.[i.authType]?.integration??[],d=Z({authType:i.authType,integrationName:o.id,kek:t,database:n,extraIntegrationFields:a});r[o.id]=d}}return r}var z=class extends Error{status;code;extra;constructor(n,t,r,o={}){super(r??t),this.name="ManagementApiError",this.status=n,this.code=t,this.extra=o}};function E(e,n){return new Response(JSON.stringify(n),{status:e,headers:{"content-type":"application/json"}})}function tn(e){let n={error:e.code,message:e.message,...e.extra};return E(e.status,n)}function K(e){return new z(404,"not_found",e)}function _e(e,n={}){return new z(400,"bad_request",e,n)}function jn(e,n){let t=e.plugins.find(r=>r.id===n);if(!t)throw K(`Plugin '${n}' not found`);return t}async function rn(e,n){let t=e.options?.authType;if(!t||!n.database||!n.kek)return{configured:!1,missingFields:[]};let r=Z({authType:t,integrationName:e.id,kek:n.kek,database:n.database}),o=q[t].integration,i=r,s;try{s=await Promise.all(o.map(u=>i[`get_${u}`]()))}catch{s=o.map(()=>null)}let a=o.filter((u,c)=>s[c]==null),d;return t==="oauth_2"?d=!a.includes("client_id")&&!a.includes("client_secret"):d=a.length===0,{configured:d,missingFields:a}}async function on(e,n){let t=e.options?.authType??null,r=e.oauthConfig,{configured:o,missingFields:i}=await rn(e,n);return{id:e.id,authType:t,configured:o,missingFields:i,oauth:r?{providerName:r.providerName,scopes:r.scopes,requiresRegisteredRedirect:!!r.requiresRegisteredRedirect}:null}}function ue(){return{ok:!0}}async function le(e){return Promise.all(e.plugins.map(n=>on(n,e)))}async function pe(e,n){let t=jn(e,n);return on(t,e)}async function sn(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 an(e,n){let t=await sn(e,n),r=t.filter(o=>o.hasCredentials).map(o=>o.integrationName);return{id:n,accounts:t,connectedPlugins:r}}async function ge(e){let n=new Map;if(n.set("default",{id:"default",accounts:[],connectedPlugins:[]}),e.database){let t=await e.database.db.selectFrom("corsair_accounts as a").innerJoin("corsair_integrations as i","i.id","a.integration_id").select(["a.tenant_id","a.dek as dek","i.name as integrationName"]).execute();for(let r of t){let o=r.tenant_id;if(!o)continue;let i=n.get(o);i||(i={id:o,accounts:[],connectedPlugins:[]},n.set(o,i));let s=!!r.dek;i.accounts.push({integrationName:r.integrationName,hasCredentials:s}),s&&i.connectedPlugins.push(r.integrationName)}}return[...n.values()]}async function fe(e,n){if(!n)throw _e("Tenant id must be a non-empty string");return an(e,n)}async function ye(e,n){let t=n?.id?.trim();if(!t)throw _e("Tenant id is required",{missingFields:["id"]});return an(e,t)}async function me(e,n){let t=n?.trim()||"default",r={},o=e.database?await sn(e,t):[],i=new Map(o.map(s=>[s.integrationName,s]));for(let s of e.plugins){if(!(await rn(s,e)).configured){r[s.id]="missing_credentials";continue}let d=i.get(s.id),u;d&&d.hasCredentials?u="connected":u="not_connected",r[s.id]=u}return r}async function he(e,n){if(!e.database)throw K(`Permission '${n}' not found`);let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("id","=",n).executeTakeFirst();if(!t)throw K(`Permission '${n}' not found`);return t}async function ke(e,n){if(!e.database)throw K("Permission not found");let t=await e.database.db.selectFrom("corsair_permissions").selectAll().where("token","=",n).executeTakeFirst();if(!t)throw K("Permission not found");return t}var cn=[{method:"GET",pattern:"/ok",handler:async()=>E(200,ue())},{method:"GET",pattern:"/tenants",handler:async({internal:e})=>E(200,await ge(e))},{method:"POST",pattern:"/tenants",handler:async({internal:e,body:n})=>E(201,await ye(e,n))},{method:"GET",pattern:"/tenants/:id",handler:async({internal:e,params:n})=>E(200,await fe(e,n.id))},{method:"GET",pattern:"/plugins",handler:async({internal:e})=>E(200,await le(e))},{method:"GET",pattern:"/plugins/:id",handler:async({internal:e,params:n})=>E(200,await pe(e,n.id))},{method:"GET",pattern:"/connection-status",handler:async({internal:e,query:n})=>E(200,await me(e,n.tenantId))},{method:"GET",pattern:"/permissions/:id",handler:async({internal:e,params:n})=>E(200,await he(e,n.id))},{method:"POST",pattern:"/permissions/lookup-by-token",handler:async({internal:e,body:n})=>{let t=n?.token?.trim();return t?E(200,await ke(e,t)):E(400,{error:"bad_request",message:"token is required",missingFields:["token"]})}}];(()=>{let e=new Set;for(let n of cn){let t=`${n.method} ${n.pattern}`;if(e.has(t))throw new Error(`Duplicate management route registered: ${t}`);e.add(t)}})();function Wn(e,n){let t=e.split("/").filter(Boolean),r=n.split("/").filter(Boolean);if(t.length!==r.length)return null;let o={};for(let i=0;i<t.length;i++){let s=t[i],a=r[i];if(s.startsWith(":"))o[s.slice(1)]=decodeURIComponent(a);else if(s!==a)return null}return o}function Un(e,n){if(!n)return e;let t=n.endsWith("/")?n.slice(0,-1):n;return e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length):e}function qn(e){let n=e[J];if(!n)throw new Error("managementHandler: invalid corsair instance (missing internal config)");return n}async function zn(e){if(!(e.method==="GET"||e.method==="HEAD"||!(e.headers.get("content-type")??"").includes("application/json")))try{let t=await e.text();return t?JSON.parse(t):void 0}catch{throw new z(400,"invalid_json","Request body is not valid JSON")}}var Gn="/api/corsair";function G(e,n={}){let t=n.basePath??Gn,r=qn(e);return async o=>{try{let i=new URL(o.url),s=Un(i.pathname,t),a=o.method.toUpperCase(),d=Object.fromEntries(i.searchParams);for(let u of cn){if(u.method!==a)continue;let c=Wn(u.pattern,s);if(!c)continue;let p=await zn(o);return await u.handler({internal:r,req:o,params:c,query:d,body:p})}throw K(`No route for ${a} ${s}`)}catch(i){if(n.onError){let a=await n.onError(i,o);if(a)return a}if(i instanceof z)return tn(i);let s=i instanceof Error?i.message:"Internal server error";return E(500,{error:"internal_error",message:s})}}}function Jn(e){let n=e.get?.("host")??"localhost",t=e.protocol??"http",r=e.originalUrl??e.url,o=`${t}://${n}${r}`,i=new Headers;for(let[d,u]of Object.entries(e.headers))if(u!=null)if(Array.isArray(u))for(let c of u)i.append(d,c);else i.set(d,u);let s=e.method!=="GET"&&e.method!=="HEAD",a={method:e.method,headers:i};return s&&e.body!==void 0&&(a.body=typeof e.body=="string"?e.body:JSON.stringify(e.body),i.has("content-type")||i.set("content-type","application/json")),new Request(o,a)}async function Vn(e,n){e.status(n.status),n.headers.forEach((r,o)=>e.setHeader(o,r));let t=Buffer.from(await n.arrayBuffer());e.send(t)}function dn(e,n){let t=G(e,n);return async(r,o,i)=>{try{let s=await t(Jn(r));await Vn(o,s)}catch(s){i(s)}}}function un(e,n){let t=G(e,n);return r=>t(r.req.raw)}function ln(e,n){let t=G(e,n);return{GET:t,POST:t}}function pn(e){return{ok:ue,tenants:{list:()=>ge(e),create:n=>ye(e,n),get:n=>fe(e,n)},plugins:{list:()=>le(e),get:n=>pe(e,n)},connectionStatus:{get:n=>me(e,n?.tenantId)},permissions:{get:n=>he(e,n),getByToken:n=>ke(e,n)}}}async function gn(e,n,t,r,o="pending"){if(!e)return null;try{let i=Ke(),s=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:s,updated_at:s,account_id:n,event_type:t,payload:r,status:o}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function Yn(e,n,t,r="pending"){try{let o=await e.$getAccountId();return gn(e.database,o,n,t,r)}catch(o){return console.warn("Failed to log event:",o),null}}import*as fn from"https";import*as yn from"querystring";function mn(e,n,t,r,o){let i=new URL(r.tokenUrl),s=r.tokenAuthMethod==="basic";return new Promise((a,d)=>{let u={code:e.trim(),redirect_uri:o,grant_type:"authorization_code"};s||(u.client_id=n,u.client_secret=t);let c=yn.stringify(u),p={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(c).toString()};s&&(p.Authorization=`Basic ${Buffer.from(`${n}:${t}`).toString("base64")}`);let f=fn.request({hostname:i.hostname,...i.port?{port:Number(i.port)}:{},path:i.pathname+i.search,method:"POST",headers:p},g=>{let l="";g.on("data",m=>{l+=m}),g.on("end",()=>{if(g.statusCode!==200){d(new Error(`Token exchange failed (${g.statusCode}): ${l}`));return}try{a(JSON.parse(l))}catch{d(new Error(`Token endpoint returned non-JSON response: ${l}`))}})});f.on("error",g=>d(new Error(`Request failed: ${g.message}`))),f.write(c),f.end()})}import*as hn from"querystring";function Qn(e){let n=e[J];if(!n)throw new Error("Invalid corsair instance");return n}function Xn(e,n){let t=e.plugins.find(r=>r.id===n);if(!t)throw new Error(`Plugin '${n}' not found`);return t}function et(e){let n=e.oauthConfig;if(!n)throw new Error(`Plugin '${e.id}' has no oauthConfig`);return n}async function nt(e,n){let t=Qn(e);if(!t.database)throw new Error("No database configured on corsair instance");let r=t.connect?.redirectUri;if(!r)throw new Error("No redirectUri configured. Set connect.redirectUri in createCorsair().");let o=Je(n,t.kek);if(!o)throw new Error("Invalid or tampered state parameter");let{plugin:i,tenantId:s}=o,a=Xn(t,i),d=et(a),c=await Z({authType:"oauth_2",integrationName:i,kek:t.kek,database:t.database}).get_client_id();if(!c)throw new Error(`client_id not configured for '${i}'`);let p={...d.authParams,client_id:c,redirect_uri:r,response_type:"code",scope:d.scopes.join(" "),state:n},f=`${d.authUrl}?${hn.stringify(p)}`;return{plugin:i,tenantId:s,providerName:d.providerName,oauthUrl:f,state:n}}var kn=["airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gitlab","gmail","googlecalendar","googledrive","googlesheets","grafana","hackernews","hubspot","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","tally","tavily","teams","telegram","todoist","trello","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zohomail","zoom"];var bn=" ";function v(e){let n=e;return n._def??n.def??{}}function S(e){let n=e.typeName;if(n)return n;let t=e.type;if(t)return`Zod${t.split("_").map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("")}`}function D(e){return e.innerType??e.schema??e.out??e.in}function Cn(e,n){switch(n){case"ZodPipe":return e.in??e.innerType;case"ZodEffects":return e.schema??e.innerType;case"ZodTransform":return e.schema??e.innerType??e.in;default:return D(e)}}function Pn(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function we(e,n){let t=n.shape??e.shape;return typeof t=="function"?t():t}function X(e){return Array.isArray(e.options)?e.options:Array.isArray(e.values)?e.values:e.entries!==null&&typeof e.entries=="object"&&!Array.isArray(e.entries)?Object.values(e.entries):[]}function Tn(e,n){return e.description??n.description}function tt(e){let n=e;for(;n;){let t=v(n),r=Tn(n,t);if(r)return r;let o=S(t);if(Me(o)||o==="ZodPipe"||o==="ZodEffects"||o==="ZodTransform"){n=Cn(t,o);continue}break}}function Me(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function I(e){let n=v(e),t=S(n);switch(t){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"Date";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(n.value??X(n)[0]??"unknown");case"ZodEnum":return X(n).map(r=>String(r)).join(" | ");case"ZodOptional":{let r=D(n);return r?I(r):"unknown"}case"ZodNullable":{let r=D(n);return`${r?I(r):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let r=D(n);return r?I(r):"unknown"}case"ZodArray":{let r=Pn(n);if(!r)return"unknown[]";let o=v(r),i=S(o)==="ZodUnion",s=I(r);return`${i?`(${s})`:s}[]`}case"ZodRecord":return"{}";case"ZodObject":{let r=we(e,n),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([s,a])=>{let d=S(v(a));return`${d==="ZodOptional"||d==="ZodNullable"?s+"?":s}: ${I(a)}`}).join(", ")} }`}case"ZodUnion":return X(n).map(r=>I(r)).join(" | ");case"ZodIntersection":return`${I(n.left)} & ${I(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=Cn(n,t);return r?I(r):"unknown"}default:return(t??"unknown").replace("Zod","").toLowerCase()}}function $(e){let n=v(e),t=S(n),r=Tn(e,n);switch(t){case"ZodString":return{kind:"string",optional:!1,description:r};case"ZodNumber":return{kind:"number",optional:!1,description:r};case"ZodBoolean":return{kind:"boolean",optional:!1,description:r};case"ZodLiteral":{let o=n.value??X(n)[0],i=typeof o=="string"||typeof o=="number"||typeof o=="boolean"?o:String(o??"");return{kind:"literal",optional:!1,description:r,value:i}}case"ZodEnum":{let o=X(n).map(i=>String(i));return{kind:"string",optional:!1,description:r,enum:o}}case"ZodOptional":{let o=D(n),i=o?$(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodNullable":{let o=D(n),i=o?$(o):{kind:"unknown",optional:!1};return{...i,optional:!0,description:r??i.description}}case"ZodDefault":case"ZodCatch":{let o=D(n);return o?{...$(o),description:r}:{kind:"unknown",optional:!1,description:r}}case"ZodArray":{let o=Pn(n);return{kind:"array",optional:!1,description:r,items:o?$(o):{kind:"unknown",optional:!1}}}case"ZodObject":{let o=we(e,n),i={};for(let[s,a]of Object.entries(o))i[s]=$(a);return{kind:"object",optional:!1,description:r,fields:i}}case"ZodRecord":return{kind:"unknown",optional:!1,description:r};case"ZodUnion":{let o=X(n);for(let i of o){let s=v(i);if(S(s)==="ZodObject")return{...$(i),description:r}}return{kind:"unknown",optional:!1,description:r}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let o=D(n);return o?{...$(o),description:r}:{kind:"unknown",optional:!1,description:r}}default:return{kind:"unknown",optional:!1,description:r}}}function Cr(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r===-1)return null;let o=t.slice(0,r),i=t.slice(r+1),s=e.find(c=>c.id===o);if(!s)return null;let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=B(s.endpointMeta,a),u=B(s.endpointSchemas,a);return!d&&!u?null:{input:u?.input?$(u.input):null,output:u?.output?$(u.output):null,description:d?.description}}var Fe=["equals","contains","startsWith","endsWith","in"],rt=["equals","gt","gte","lt","lte","in"],ot=["equals"],it=["equals","before","after","between"];function xn(e){let n=v(e);switch(S(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let r=D(n);return r?xn(r):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function $e(e){let n=v(e),t=S(n);if(Me(t)){let i=D(n);return i?$e(i):{}}if(t!=="ZodObject")return{};let r=we(e,n),o={};for(let[i,s]of Object.entries(r)){let a=xn(s);a==="string"?o[i]={type:"string",operators:Fe}:a==="number"?o[i]={type:"number",operators:rt}:a==="boolean"?o[i]={type:"boolean",operators:ot}:a==="date"&&(o[i]={type:"date",operators:it})}return o}function An(e,n){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return[t,r]}function ve(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];typeof o=="function"?t.push(i.join(".")):o!==null&&typeof o=="object"&&ve(o,i,t)}}function Se(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function Oe(e,n,t){for(let[r,o]of Object.entries(e)){let i=[...n,r];Se(o)?t.push(i.join(".")):o!==null&&typeof o=="object"&&Oe(o,i,t)}}function Ne(e,n){if(n.length===0)return null;let[t,...r]=n,o=Object.entries(e).find(([a])=>a.toLowerCase()===t);if(!o)return null;let[i,s]=o;if(r.length===0)return Se(s)?[i]:null;if(s!==null&&typeof s=="object"&&!Se(s)){let a=Ne(s,r);if(a!==null)return[i,...a]}return null}function Rn(e,n){let t=[];t.push(`${e}({`),t.push(" webhookHooks: {");for(let i=0;i<n.length;i++){let s=" ".repeat(i+2);t.push(`${s}${n[i]}: {`)}let r=" ".repeat(n.length+2),o=r+" ";t.push(`${r}before(ctx, args) {`),t.push(`${o}return { ctx, args };`),t.push(`${r}},`),t.push(`${r}after(ctx, response) {`),t.push(`${r}},`);for(let i=n.length-1;i>=0;i--){let s=" ".repeat(i+2);t.push(`${s}},`)}return t.push(" },"),t.push("})"),t.join(`
14
+ `)}var st=new Set(kn);function V(e,n){let t=n?.type??"api",r=n?.plugin;if(r!==void 0){let i=e.find(a=>a.id===r);if(!i)return st.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:V(e);if(t==="webhooks"){if(!i.webhooks)return[];let a=[];return Oe(i.webhooks,[],a),a.map(d=>`${i.id}.webhooks.${d}`)}if(t==="db"){let a=i.schema?.entities;return a?Object.keys(a).map(d=>`${i.id}.db.${d}.search`):[]}if(!i.endpoints)return[];let s=[];return ve(i.endpoints,[],s),s.map(a=>`${i.id}.api.${a}`)}let o={};if(t==="webhooks")for(let i of e){if(!i.webhooks)continue;let s=[];Oe(i.webhooks,[],s),o[i.id]=s.map(a=>`${i.id}.webhooks.${a}`)}else if(t==="db")for(let i of e){let s=i.schema?.entities;s&&(o[i.id]=Object.keys(s).map(a=>`${i.id}.db.${a}.search`))}else for(let i of e){if(!i.endpoints)continue;let s=[];ve(i.endpoints,[],s),o[i.id]=s.map(a=>`${i.id}.api.${a}`)}return o}function B(e,n){if(e){for(let[t,r]of Object.entries(e))if(t.toLowerCase()===n)return r}}function at(e,n){let t=e.toLowerCase(),r=n.toLowerCase();if(!t.startsWith(`${r}.`)){let i=t.slice(n.length+1),s=i.startsWith(".")?i.slice(1):i;return s.startsWith("api.")&&(s=s.slice(4)),{shortPath:s,lookupKey:s}}let o=e.slice(n.length+1);return o.toLowerCase().startsWith("api.")&&(o=o.slice(4)),{shortPath:o,lookupKey:o.toLowerCase()}}function De(e,n){return typeof e=="string"?e:Array.isArray(e)?`${n}:
15
+ ${e.join(", ")}`:`${n}:
16
+ `+Object.entries(e).map(([t,r])=>` ${t}: ${r.join(", ")}`).join(`
17
+ `)}function Pr(e,n){let t=n.toLowerCase(),r=t.indexOf(".");if(r!==-1){let o=t.slice(0,r),i=t.slice(r+1),s=e.find(a=>a.id===o);if(s){if(i.startsWith("db.")){let c=i.slice(3),p=c.lastIndexOf(".");if(p!==-1){let f=c.slice(0,p),g=c.slice(p+1),l=s.schema?.entities;if(g==="search"&&l){let m=An(l,f);if(m){let[b,k]=m,w=$e(k),T=[`Search ${o} ${b} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Fe.join(", ")}]`];for(let[y,h]of Object.entries(w))T.push(` ${y}?: ${h.type} [${h.operators.join(", ")}]`);return T.push("}"),T.join(`
18
+ `)}}}return De(V(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let c=i.slice(9);if(s.webhooks){let p=Ne(s.webhooks,c.split("."));if(p!==null){let f=p.join("."),g=B(s.webhookSchemas,f.toLowerCase()),l=g?.response?I(g.response):null,m=[];return g?.description&&m.push(g.description),g?.payload&&m.push(`payload ${be(ee(g.payload))}`),l&&m.push(`response: ${l}`),m.push(`usage:
19
+ ${Rn(o,p)}`),m.join(`
20
+
21
+ `)}}return De(V(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=B(s.endpointMeta,a),u=B(s.endpointSchemas,a);if(d||u){let c=[],p=[d?.riskLevel?`[${d.riskLevel}]`:"",d?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),f=[d?.description,p].filter(Boolean).join(" ");return f&&c.push(f),u?.input&&c.push(`input ${be(ee(u.input))}`),u?.output&&c.push(`output ${be(ee(u.output))}`),c.join(`
22
+
23
+ `)}}}return De(V(e),"Path not found. Available operations")}function wn(e){let n=e;for(;;){let t=v(n),r=S(t);if(Me(r)){let o=D(t);if(!o)return n;n=o;continue}return n}}function ee(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=wn(e),t=v(n);if(S(t)==="ZodObject"){let o=we(n,t),i=[];for(let[s,a]of Object.entries(o)){let d=v(a),u=S(d),c=u==="ZodOptional"||u==="ZodNullable",p=wn(a),f=tt(a);i.push({key:s,optional:c,type:I(p),...f!==void 0?{description:f}:{}})}return{kind:"object",fields:i}}return{kind:"inline",type:I(n)}}function be(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=bn.repeat(n+1),r=bn.repeat(n);return`{
24
+ ${e.fields.map(i=>{let s=i.optional?`${i.key}?`:i.key,a=i.description?` // ${i.description}`:"";return`${t}${s}: ${i.type}${a}`}).join(`
25
+ `)}
26
+ ${r}}`}return"unknown"}function ct(e,n){let t=V(e,{plugin:n,type:"api"});if(typeof t=="string")return{ok:!1,error:t};if(!Array.isArray(t))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(c=>c.id===n);if(!r)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let o=[];for(let c of t){let{shortPath:p,lookupKey:f}=at(c,n),g=B(r.endpointMeta,f),l=B(r.endpointSchemas,f);!g&&!l||o.push({path:c,shortPath:p,description:g?.description,riskLevel:g?.riskLevel,irreversible:g?.irreversible,input:ee(l?.input),output:ee(l?.output)})}o.sort((c,p)=>c.path.localeCompare(p.path));let i=[],s=V(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let c of s){let f=c.toLowerCase().slice(n.length+1),g=f.startsWith(".")?f.slice(1):f;if(!g.startsWith("webhooks."))continue;let l=g.slice(9),m=Ne(r.webhooks,l.split("."));if(m===null)continue;let b=m.join("."),k=B(r.webhookSchemas,b.toLowerCase()),w=k?.response?I(k.response):void 0;i.push({path:c,description:k?.description,payload:ee(k?.payload),responseType:w,usageExample:Rn(n,m)})}i.sort((c,p)=>c.path.localeCompare(p.path));let a=[],d=V(e,{plugin:n,type:"db"}),u=r.schema?.entities;if(Array.isArray(d)&&u)for(let c of d){let f=c.toLowerCase().slice(n.length+1),g=f.startsWith(".")?f.slice(1):f;if(!g.startsWith("db."))continue;let l=g.slice(3),m=l.lastIndexOf(".");if(m===-1)continue;let b=l.slice(0,m);if(l.slice(m+1)!=="search")continue;let w=An(u,b);if(!w)continue;let[T,y]=w,h=$e(y),P=Object.entries(h).map(([A,_])=>({field:A,type:_.type,operators:_.operators}));a.push({path:c,entityName:T,filters:[{field:"entity_id",type:"string",operators:Fe},...P]})}return a.sort((c,p)=>c.path.localeCompare(p.path)),{ok:!0,data:{pluginId:n,api:o,webhooks:i,db:a}}}var J=Symbol.for("corsair:internal");function _r(e){let n=e.database?Ze(e.database):void 0,t=n&&e.kek?nn(e.plugins,n,e.kek):ce(!!n,!!e.kek),r={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,approval:e.approval,connect:e.connect},o=Xe(n),i=pn(r);if(e.multiTenancy)return Object.assign({withTenant:a=>{if(!a)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let d=Ie(e.plugins,{database:n,tenantId:a,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval,connectConfig:e.connect});return Object.assign(d,{[J]:r})},keys:t,permissions:o,manage:i},{[J]:r});let s=Ie(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval,connectConfig:e.connect});return Object.assign({},s,{keys:t,permissions:o,manage:i,[J]:r})}export{L as a,j as b,W as c,N as d,Te as e,xe as f,Q as g,U as h,re as i,q as j,Z as k,de as l,Ue as m,qe as n,ze as o,vn as p,Ge as q,Je as r,G as s,dn as t,un as u,ln as v,gn as w,Yn as x,mn as y,nt as z,kn as A,Cr as B,V as C,Pr as D,be as E,ct as F,J as G,_r as H};
@@ -1,5 +1,5 @@
1
- import{C as R,D as v,j as m,k as A,l as _}from"./chunk-PCO6RKXN.js";import{a as j}from"./chunk-UBM25HVI.js";import{Kysely as F}from"kysely";import{ZodBoolean as x,ZodDate as E,ZodEnum as D,ZodNullable as K,ZodNumber as N,ZodObject as B,ZodOptional as Z,ZodRecord as L,ZodString as U,ZodType as W}from"zod";var I={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},repositories:{list:{}}},discord:{guilds:{list:{}},channels:{list:{}}},hubspot:{contacts:{getMany:{}},companies:{getMany:{}},deals:{getMany:{}}},gmail:{messages:{list:{}},labels:{list:{}},drafts:{list:{}},threads:{list:{}}},googlecalendar:{events:{getMany:{}}},googledrive:{files:{list:{}},folders:{list:{}},sharedDrives:{list:{}}},notion:{databases:{getManyDatabases:{}},databasePages:{getManyDatabasePages:{}},users:{getManyUsers:{}}},airtable:{bases:{getMany:{}}},todoist:{projects:{getMany:{}},tasks:{getMany:{}}},cal:{bookings:{list:{}}}};async function pn(n,e){let s=[],i=d=>{s.push(d),console.log(d)},a=d=>{s.push(d),console.warn(d)},t=e?.caller??"script",f=q(n);if(!f)throw new Error("setupCorsair: invalid corsair instance");if(!f.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let o=Q(n,f.plugins,e),r={...f,database:f.database},c=r.database.db;await X(c,a);let l=await nn(c,r,o.tenantId,o.provisionAccounts,i);e?.credentials&&Object.keys(e.credentials).length>0&&await sn(n,o,e.credentials,r,i,a);let y=await rn(l,o,i,t);if(e?.backfill){i("[corsair:setup] Starting backfill...");let d=v({plugins:f.plugins,database:c,kek:f.kek,multiTenancy:!0}).withTenant(o.tenantId);await on(d,f.plugins,y,i,a),i("[corsair:setup] Backfill complete.")}return s.join(`
2
- `)}function w(n){return typeof n=="object"&&n!==null}function Y(n){return!w(n)||!Array.isArray(n.plugins)||typeof n.kek!="string"||typeof n.multiTenancy!="boolean"?!1:n.database===void 0?!0:w(n.database)?n.database.db instanceof F:!1}function q(n){let e=Object.getOwnPropertyDescriptor(n,R);if(e)return Y(e.value)?e.value:void 0}function H(n){return n==="oauth_2"||n==="api_key"||n==="bot_token"}function P(n){let e=n.options?.authType;return H(e)?e:void 0}function J(n){return"withTenant"in n&&typeof n.withTenant=="function"}function $(n,e,s){let i=s==="integration"?n.authConfig?.[e]?.integration??[]:n.authConfig?.[e]?.account??[];return new Set([...m[e][s],...i])}function z(n,e){if(!n)return!1;for(let[s,i]of Object.entries(n)){let a=e.find(o=>o.id===s);if(!a)continue;let t=P(a);if(!t)continue;let f=$(a,t,"account");for(let o of Object.keys(i))if(f.has(o))return!0}return!1}function Q(n,e,s){let i=J(n),a=s?.tenantId?.trim(),t=a!==void 0&&a.length>0;if(i&&s?.backfill&&!t)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(i&&z(s?.credentials,e)&&!t)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(t&&!a)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:i,tenantIdProvided:t,tenantId:t?a:"default",provisionAccounts:!i||t}}function C(n,e){if(!w(n))return;let s=n[e];return typeof s=="function"?(...i)=>Reflect.apply(s,n,i):void 0}function O(n,e){return w(n)?e===0?!0:Object.values(n).every(s=>O(s,e-1)):!1}function V(n){return O(n,4)}var G={...j};function S(n){if(n instanceof B){let e={};for(let[s,i]of Object.entries(n.shape))e[s]=i instanceof W?S(i):"unknown";return e}return n instanceof K?`${S(n.unwrap())} | null`:n instanceof Z?`${S(n.unwrap())} | undefined`:n instanceof D?n.options.join(" | "):n instanceof U?"string":n instanceof N?"number":n instanceof x?"boolean":n instanceof E?"date":n instanceof L?"jsonb":"unknown"}async function X(n,e){let s=await n.introspection.getTables(),i=new Set(s.map(a=>a.name));for(let[a,t]of Object.entries(G))i.has(a)||e(`[corsair:setup] Table "${a}" does not exist. Run your database migrations before calling setupCorsair.
1
+ import{G as R,H as v,j as m,k as A,l as _}from"./chunk-LIZVHWQK.js";import{a as j}from"./chunk-UBM25HVI.js";import{Kysely as F}from"kysely";import{ZodBoolean as x,ZodDate as E,ZodEnum as D,ZodNullable as K,ZodNumber as N,ZodObject as B,ZodOptional as Z,ZodRecord as L,ZodString as U,ZodType as W}from"zod";var I={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},repositories:{list:{}}},discord:{guilds:{list:{}},channels:{list:{}}},hubspot:{contacts:{getMany:{}},companies:{getMany:{}},deals:{getMany:{}}},gmail:{messages:{list:{}},labels:{list:{}},drafts:{list:{}},threads:{list:{}}},googlecalendar:{events:{getMany:{}}},googledrive:{files:{list:{}},folders:{list:{}},sharedDrives:{list:{}}},notion:{databases:{getManyDatabases:{}},databasePages:{getManyDatabasePages:{}},users:{getManyUsers:{}}},airtable:{bases:{getMany:{}}},todoist:{projects:{getMany:{}},tasks:{getMany:{}}},cal:{bookings:{list:{}}},zohomail:{folders:{list:{}},messages:{list:{}}}};async function pn(n,e){let s=[],i=d=>{s.push(d),console.log(d)},a=d=>{s.push(d),console.warn(d)},t=e?.caller??"script",f=q(n);if(!f)throw new Error("setupCorsair: invalid corsair instance");if(!f.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let o=Q(n,f.plugins,e),r={...f,database:f.database},c=r.database.db;await X(c,a);let l=await nn(c,r,o.tenantId,o.provisionAccounts,i);e?.credentials&&Object.keys(e.credentials).length>0&&await sn(n,o,e.credentials,r,i,a);let y=await rn(l,o,i,t);if(e?.backfill){i("[corsair:setup] Starting backfill...");let d=v({plugins:f.plugins,database:c,kek:f.kek,multiTenancy:!0}).withTenant(o.tenantId);await on(d,f.plugins,y,i,a),i("[corsair:setup] Backfill complete.")}return s.join(`
2
+ `)}function w(n){return typeof n=="object"&&n!==null}function Y(n){return!w(n)||!Array.isArray(n.plugins)||typeof n.kek!="string"||typeof n.multiTenancy!="boolean"?!1:n.database===void 0?!0:w(n.database)?n.database.db instanceof F:!1}function q(n){let e=Object.getOwnPropertyDescriptor(n,R);if(e)return Y(e.value)?e.value:void 0}function z(n){return n==="oauth_2"||n==="api_key"||n==="bot_token"}function P(n){let e=n.options?.authType;return z(e)?e:void 0}function H(n){return"withTenant"in n&&typeof n.withTenant=="function"}function $(n,e,s){let i=s==="integration"?n.authConfig?.[e]?.integration??[]:n.authConfig?.[e]?.account??[];return new Set([...m[e][s],...i])}function J(n,e){if(!n)return!1;for(let[s,i]of Object.entries(n)){let a=e.find(o=>o.id===s);if(!a)continue;let t=P(a);if(!t)continue;let f=$(a,t,"account");for(let o of Object.keys(i))if(f.has(o))return!0}return!1}function Q(n,e,s){let i=H(n),a=s?.tenantId?.trim(),t=a!==void 0&&a.length>0;if(i&&s?.backfill&&!t)throw new Error("setupCorsair: tenantId is required for backfill on a multi-tenant instance");if(i&&J(s?.credentials,e)&&!t)throw new Error("setupCorsair: tenantId is required when setting account-level credentials on a multi-tenant instance");if(t&&!a)throw new Error("setupCorsair: tenantId must be a non-empty string");return{multiTenant:i,tenantIdProvided:t,tenantId:t?a:"default",provisionAccounts:!i||t}}function C(n,e){if(!w(n))return;let s=n[e];return typeof s=="function"?(...i)=>Reflect.apply(s,n,i):void 0}function O(n,e){return w(n)?e===0?!0:Object.values(n).every(s=>O(s,e-1)):!1}function V(n){return O(n,4)}var G={...j};function S(n){if(n instanceof B){let e={};for(let[s,i]of Object.entries(n.shape))e[s]=i instanceof W?S(i):"unknown";return e}return n instanceof K?`${S(n.unwrap())} | null`:n instanceof Z?`${S(n.unwrap())} | undefined`:n instanceof D?n.options.join(" | "):n instanceof U?"string":n instanceof N?"number":n instanceof x?"boolean":n instanceof E?"date":n instanceof L?"jsonb":"unknown"}async function X(n,e){let s=await n.introspection.getTables(),i=new Set(s.map(a=>a.name));for(let[a,t]of Object.entries(G))i.has(a)||e(`[corsair:setup] Table "${a}" does not exist. Run your database migrations before calling setupCorsair.
3
3
  Schema: ${JSON.stringify(S(t),null,2)}`)}async function nn(n,e,s,i,a){let t=new Date,f=new Map;for(let o of e.plugins){let r=o.id,c=P(o),l=await n.selectFrom("corsair_integrations").selectAll().where("name","=",r).executeTakeFirst();if(!l){let u=crypto.randomUUID();await n.insertInto("corsair_integrations").values({id:u,name:r,config:{},created_at:t,updated_at:t}).execute(),l=await n.selectFrom("corsair_integrations").selectAll().where("id","=",u).executeTakeFirst(),a(`[corsair:setup] Created integration: ${r}`)}let y=c?o.authConfig?.[c]?.integration??[]:[],d=c?o.authConfig?.[c]?.account??[]:[],g=c&&l?A({authType:c,integrationName:r,kek:e.kek,database:e.database,extraIntegrationFields:y}):void 0;if(l&&!l.dek&&g&&(await g.issue_new_dek(),a(`[corsair:setup] Issued integration DEK: ${r}`)),!l||!c||!g)continue;let p;if(i){let u=await n.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",s).where("integration_id","=",l.id).executeTakeFirst();if(!u){let h=crypto.randomUUID();await n.insertInto("corsair_accounts").values({id:h,tenant_id:s,integration_id:l.id,config:{},created_at:t,updated_at:t}).execute(),u=await n.selectFrom("corsair_accounts").selectAll().where("id","=",h).executeTakeFirst(),a(`[corsair:setup] Created account: ${r}`)}p=u&&_({authType:c,integrationName:r,tenantId:s,kek:e.kek,database:e.database,extraAccountFields:d}),u&&p&&!u.dek&&(await p.issue_new_dek(),a(`[corsair:setup] Issued account DEK: ${r}`))}f.set(r,{pluginId:r,authType:c,integration:g,account:p,integrationFields:[...m[c].integration,...y],accountFields:i?[...m[c].account,...d]:[]})}return f}function en(n){if(!w(n))return;let e=n.keys;return w(e)?e:void 0}function tn(n,e){return"withTenant"in n&&typeof n.withTenant=="function"?n.withTenant(e):n}async function sn(n,e,s,i,a,t){let f=en(n),o=e.provisionAccounts?tn(n,e.tenantId):void 0;for(let[r,c]of Object.entries(s)){let l=i.plugins.find(b=>b.id===r);if(!l){t(`[corsair:setup] Unknown plugin '${r}' \u2014 skipping credentials.`);continue}let y=P(l);if(!y){t(`[corsair:setup] Plugin '${r}' has no auth type \u2014 skipping credentials.`);continue}let d=$(l,y,"integration"),g=$(l,y,"account"),p=f?.[r],u=o?.[r],h=w(u)?u.keys:void 0;for(let[b,T]of Object.entries(c))if(T){if(d.has(b)){if(e.multiTenant&&e.tenantIdProvided)throw new Error(`[corsair:setup] '${r}.${b}' is an integration-level credential shared across all tenants. You passed tenantId="${e.tenantId}", which only scopes account-level credentials. Run setup without --tenant if you intend to change this credential globally.`);let k=C(p,`set_${b}`);if(!k){t(`[corsair:setup] Cannot set integration field '${b}' for '${r}'.`);continue}await k(T),a(`[corsair:setup] Set ${r} integration.${b}`);continue}if(g.has(b)){if(e.multiTenant&&!e.tenantIdProvided)throw new Error(`setupCorsair: tenantId is required to set account-level credential '${r}.${b}' on a multi-tenant instance`);let k=C(h,`set_${b}`);if(!k){t(`[corsair:setup] Cannot set account field '${b}' for '${r}'.`);continue}await k(T),a(`[corsair:setup] Set ${r} account.${b} (tenant=${e.tenantId})`);continue}t(`[corsair:setup] Unknown credential field '${b}' for plugin '${r}'.`)}}}var M=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function an(n,e,s,i,a,t,f,o,r){let c=[],l=[];for(let d of a){if(M.has(d))continue;let g=C(s,`get_${d}`);if(!g)continue;let p=null;try{let u=await g();p=typeof u=="string"?u:null}catch{}p||c.push(d)}if(i&&t.length>0)for(let d of t){if(M.has(d))continue;let g=C(i,`get_${d}`);if(!g)continue;let p=null;try{let u=await g();p=typeof u=="string"?u:null}catch{}p||l.push(d)}let y=c.length===0&&l.length===0;if(y)o(`[corsair:setup] '${n}' (${e}) is configured \u2713`);else{let d=[...c,...l];if(r==="cli"){let g=d.map(p=>`${p}=VALUE`).join(" ");o(`[corsair:setup] '${n}' (${e}) needs credentials. Run:
4
4
  corsair setup --${n} ${g}`)}else{let g=[`[corsair:setup] '${n}' (${e}) needs credentials. Call:`];for(let p of c)g.push(` await corsair.keys.${n}.set_${p}(value)`);for(let p of l){let u=f.provisionAccounts?f.tenantId==="default"?`corsair.${n}`:`corsair.withTenant(${JSON.stringify(f.tenantId)}).${n}`:`corsair.withTenant(<tenant>).${n}`;g.push(` await ${u}.keys.set_${p}(value)`)}o(g.join(`
5
5
  `))}}return y}async function rn(n,e,s,i){let a=new Set;for(let t of n.values())await an(t.pluginId,t.authType,t.integration,t.account,t.integrationFields,t.accountFields,e,s,i)&&a.add(t.pluginId);return a}async function on(n,e,s,i,a){if(!V(I)){a("[corsair:setup] Backfill config is invalid - skipping backfill.");return}let t=I,f=new Set(e.map(o=>o.id));for(let[o,r]of Object.entries(t)){if(!f.has(o))continue;if(!s.has(o)){i(`[corsair:setup] Skipping backfill for '${o}' \u2014 auth not configured.`);continue}let c=w(n)?n[o]:void 0,l=w(c)?c.api:void 0;if(l)for(let[y,d]of Object.entries(r))for(let[g,p]of Object.entries(d)){i(`[corsair:setup] Backfilling ${o} \u203A ${y}.${g}...`);try{let u=w(l)?l[y]:void 0;await C(u,g)?.(p)}catch(u){a(`[corsair:setup] ${o} \u203A ${y}.${g} failed: `+(u instanceof Error?u.message:String(u)))}}}}export{pn as a,sn as b};
package/dist/core.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { O as OAuthConfig, A as AuthTypes, g as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './index-DLSRcm5o.js';
2
- export { j as AccountFieldNames, p as AllProviders, o as BASE_AUTH_FIELDS, k as BaseAuthFieldConfig, l as BaseKeyManager, e as BaseProviders, M as BeforeHookResult, r as BindEndpoints, a6 as BindWebhooks, a4 as Bivariant, s as BoundEndpointFn, t as BoundEndpointTree, a7 as BoundWebhook, B as BoundWebhookTree, h as CORSAIR_INTERNAL, c as CorsairClient, u as CorsairContext, v as CorsairEndpoint, y as CorsairErrorHandler, N as CorsairIntegration, i as CorsairInternalConfig, Q as CorsairKeyBuilder, S as CorsairKeyBuilderBase, d as CorsairPermissionsNamespace, a as CorsairPlugin, T as CorsairPluginContext, C as CorsairSingleTenantClient, b as CorsairTenantWrapper, a8 as CorsairWebhook, a9 as CorsairWebhookHandler, aa as CorsairWebhookMatcher, U as EndpointHooks, V as EndpointMetaEntry, w as EndpointPathsOf, E as EndpointRiskLevel, x as EndpointTree, K as EnforcePermissionOptions, L as EnforcePermissionResult, z as ErrorContext, D as ErrorHandler, F as ErrorHandlerAndMatchFunction, G as ErrorMatcher, m as IntegrationFieldNames, X as KeyBuilderContext, n as OAuth2IntegrationCredentials, Y as PermissionMode, Z as PermissionPolicy, q as PickAuth, P as PluginAuthConfig, _ as PluginEndpointMeta, $ as PluginPermissionsConfig, R as RawWebhookRequest, a0 as RequiredPluginEndpointMeta, a1 as RequiredPluginEndpointSchemas, a2 as RequiredPluginWebhookSchemas, H as RetryStrategies, J as RetryStrategy, a5 as UnionToIntersection, a3 as WebhookHooks, ab as WebhookPathsOf, ac as WebhookRequest, W as WebhookResponse, ad as WebhookTree, f as createCorsair } from './index-DLSRcm5o.js';
1
+ import { O as OAuthConfig, A as AuthTypes, a as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './index-DSVPkmM-.js';
2
+ export { e as AccountFieldNames, m as AllProviders, i as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, f as BaseKeyManager, n as BaseProviders, K as BeforeHookResult, p as BindEndpoints, a3 as BindWebhooks, a1 as Bivariant, q as BoundEndpointFn, r as BoundEndpointTree, a4 as BoundWebhook, a5 as BoundWebhookTree, b as CORSAIR_INTERNAL, j as CorsairClient, s as CorsairContext, t as CorsairEndpoint, w as CorsairErrorHandler, L as CorsairIntegration, c as CorsairInternalConfig, M as CorsairKeyBuilder, N as CorsairKeyBuilderBase, G as CorsairPermissionsNamespace, C as CorsairPlugin, Q as CorsairPluginContext, k as CorsairSingleTenantClient, l as CorsairTenantWrapper, a6 as CorsairWebhook, a7 as CorsairWebhookHandler, a8 as CorsairWebhookMatcher, S as EndpointHooks, T as EndpointMetaEntry, u as EndpointPathsOf, E as EndpointRiskLevel, v as EndpointTree, H as EnforcePermissionOptions, J as EnforcePermissionResult, x as ErrorContext, y as ErrorHandler, z as ErrorHandlerAndMatchFunction, D as ErrorMatcher, g as IntegrationFieldNames, U as KeyBuilderContext, h as OAuth2IntegrationCredentials, V as PermissionMode, W as PermissionPolicy, o as PickAuth, P as PluginAuthConfig, X as PluginEndpointMeta, Y as PluginPermissionsConfig, a9 as RawWebhookRequest, Z as RequiredPluginEndpointMeta, _ as RequiredPluginEndpointSchemas, $ as RequiredPluginWebhookSchemas, R as RetryStrategies, F as RetryStrategy, a2 as UnionToIntersection, a0 as WebhookHooks, aa as WebhookPathsOf, ab as WebhookRequest, ac as WebhookResponse, ad as WebhookTree, d as createCorsair } from './index-DSVPkmM-.js';
3
3
  import { CorsairDatabase } from './db.js';
4
- export { A as AuthMissingError, D as DocSchemaFieldRow, a as DocSchemaShape, b as DocsApiEndpoint, c as DocsDbEntity, d as DocsDbFilterField, e as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, R as ResolveConnectLinkResult, f as formatDocSchemaShape, i as introspectPluginForDocs, r as resolveConnectLink } from './index-nV76ScYN.js';
4
+ export { A as AuthMissingError, D as DocSchemaFieldRow, a as DocSchemaShape, b as DocsApiEndpoint, c as DocsDbEntity, d as DocsDbFilterField, e as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, R as ResolveConnectLinkResult, f as formatDocSchemaShape, i as introspectPluginForDocs, r as resolveConnectLink } from './index-BnkJ_TYy.js';
5
5
  import 'zod';
6
6
  import './orm.js';
7
7
  import 'kysely';
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{A as s,B as t,C as u,D as v,a,b,c,d,e,f,g,h,i,j,k,l,m,n,s as o,t as p,u as q,v as r}from"./chunk-PCO6RKXN.js";import"./chunk-OZHME3EO.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";export{a as AuthMissingError,j as BASE_AUTH_FIELDS,u as CORSAIR_INTERNAL,l as createAccountKeyManager,v as createCorsair,k as createIntegrationKeyManager,h as decryptConfig,d as decryptDEK,f as decryptWithDEK,g as encryptConfig,c as encryptDEK,e as encryptWithDEK,q as exchangeCodeForTokens,s as formatDocSchemaShape,b as generateDEK,n as initializeAccountDEK,m as initializeIntegrationDEK,t as introspectPluginForDocs,o as logEvent,p as logEventFromContext,i as reEncryptConfig,r as resolveConnectLink};
1
+ import{E as s,F as t,G as u,H as v,a,b,c,d,e,f,g,h,i,j,k,l,m,n,w as o,x as p,y as q,z as r}from"./chunk-LIZVHWQK.js";import"./chunk-OZHME3EO.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";export{a as AuthMissingError,j as BASE_AUTH_FIELDS,u as CORSAIR_INTERNAL,l as createAccountKeyManager,v as createCorsair,k as createIntegrationKeyManager,h as decryptConfig,d as decryptDEK,f as decryptWithDEK,g as encryptConfig,c as encryptDEK,e as encryptWithDEK,q as exchangeCodeForTokens,s as formatDocSchemaShape,b as generateDEK,n as initializeAccountDEK,m as initializeIntegrationDEK,t as introspectPluginForDocs,o as logEvent,p as logEventFromContext,i as reEncryptConfig,r as resolveConnectLink};
@@ -1,4 +1,4 @@
1
- import { E as EndpointRiskLevel, a as CorsairPlugin } from './index-DLSRcm5o.js';
1
+ import { E as EndpointRiskLevel, C as CorsairPlugin } from './index-DSVPkmM-.js';
2
2
 
3
3
  /**
4
4
  * Error thrown when a plugin endpoint is called but the required auth credentials
@@ -1,10 +1,10 @@
1
- import { CorsairDatabase, CorsairDatabaseInput, CorsairPermission } from './db.js';
1
+ import { CorsairDatabase, CorsairPermission, CorsairDatabaseInput } from './db.js';
2
2
  import { ZodTypeAny } from 'zod';
3
3
  import { CorsairPluginSchema, PluginEntityClients } from './orm.js';
4
4
 
5
5
  type AllErrors = 'RATE_LIMIT_ERROR' | 'AUTH_ERROR' | 'PERMISSION_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT_ERROR' | 'SERVER_ERROR' | 'VALIDATION_ERROR' | 'NOT_FOUND_ERROR' | 'BAD_REQUEST_ERROR' | 'PARSING_ERROR' | 'DEFAULT' | (string & {});
6
- declare const BaseProviders: readonly ["airtable", "amplitude", "asana", "bitwarden", "bluesky", "box", "cal", "calendly", "cloudflare", "cursor", "discord", "dodopayments", "dropbox", "exa", "figma", "firecrawl", "fireflies", "github", "gitlab", "gmail", "googlecalendar", "googledrive", "googlesheets", "grafana", "hackernews", "hubspot", "intercom", "jira", "linear", "monday", "notion", "onedrive", "openweathermap", "oura", "outlook", "pagerduty", "posthog", "razorpay", "reddit", "resend", "sentry", "sharepoint", "slack", "spotify", "strava", "stripe", "tally", "tavily", "teams", "telegram", "todoist", "trello", "twitter", "twitterapiio", "typeform", "vapi", "xquik", "youtube", "zendesk", "zoom"];
7
- type AllProviders = 'airtable' | 'amplitude' | 'asana' | 'bitwarden' | 'bluesky' | 'box' | 'cal' | 'calendly' | 'cloudflare' | 'cursor' | 'discord' | 'dodopayments' | 'dropbox' | 'exa' | 'figma' | 'firecrawl' | 'fireflies' | 'github' | 'gitlab' | 'gmail' | 'googlecalendar' | 'googledrive' | 'googlesheets' | 'grafana' | 'hackernews' | 'hubspot' | 'intercom' | 'jira' | 'linear' | 'monday' | 'notion' | 'onedrive' | 'openweathermap' | 'oura' | 'outlook' | 'pagerduty' | 'posthog' | 'razorpay' | 'reddit' | 'resend' | 'sentry' | 'sharepoint' | 'slack' | 'spotify' | 'strava' | 'stripe' | 'tally' | 'tavily' | 'teams' | 'telegram' | 'todoist' | 'trello' | 'twitter' | 'twitterapiio' | 'typeform' | 'vapi' | 'xquik' | 'youtube' | 'zendesk' | 'zoom' | (string & {});
6
+ declare const BaseProviders: readonly ["airtable", "amplitude", "asana", "bitwarden", "bluesky", "box", "cal", "calendly", "cloudflare", "cursor", "discord", "dodopayments", "dropbox", "exa", "figma", "firecrawl", "fireflies", "github", "gitlab", "gmail", "googlecalendar", "googledrive", "googlesheets", "grafana", "hackernews", "hubspot", "intercom", "jira", "linear", "monday", "notion", "onedrive", "openweathermap", "oura", "outlook", "pagerduty", "posthog", "razorpay", "reddit", "resend", "sentry", "sharepoint", "slack", "spotify", "strava", "stripe", "tally", "tavily", "teams", "telegram", "todoist", "trello", "twitter", "twitterapiio", "typeform", "vapi", "xquik", "youtube", "zendesk", "zohomail", "zoom"];
7
+ type AllProviders = 'airtable' | 'amplitude' | 'asana' | 'bitwarden' | 'bluesky' | 'box' | 'cal' | 'calendly' | 'cloudflare' | 'cursor' | 'discord' | 'dodopayments' | 'dropbox' | 'exa' | 'figma' | 'firecrawl' | 'fireflies' | 'github' | 'gitlab' | 'gmail' | 'googlecalendar' | 'googledrive' | 'googlesheets' | 'grafana' | 'hackernews' | 'hubspot' | 'intercom' | 'jira' | 'linear' | 'monday' | 'notion' | 'onedrive' | 'openweathermap' | 'oura' | 'outlook' | 'pagerduty' | 'posthog' | 'razorpay' | 'reddit' | 'resend' | 'sentry' | 'sharepoint' | 'slack' | 'spotify' | 'strava' | 'stripe' | 'tally' | 'tavily' | 'teams' | 'telegram' | 'todoist' | 'trello' | 'twitter' | 'twitterapiio' | 'typeform' | 'vapi' | 'xquik' | 'youtube' | 'zendesk' | 'zohomail' | 'zoom' | (string & {});
8
8
  type AuthTypes = 'oauth_2' | 'api_key' | 'bot_token';
9
9
  type PickAuth<T extends AuthTypes> = T;
10
10
 
@@ -279,6 +279,57 @@ type CorsairErrorHandler = {
279
279
  [K in AllErrors]?: ErrorHandlerAndMatchFunction;
280
280
  };
281
281
 
282
+ type Tenant = {
283
+ id: string;
284
+ accounts: Array<{
285
+ integrationName: string;
286
+ hasCredentials: boolean;
287
+ }>;
288
+ connectedPlugins: string[];
289
+ };
290
+ type CreateTenantInput = {
291
+ id: string;
292
+ };
293
+ type PluginInfo = {
294
+ id: string;
295
+ authType: AuthTypes | null;
296
+ configured: boolean;
297
+ missingFields: string[];
298
+ oauth: {
299
+ providerName: string;
300
+ scopes: string[];
301
+ requiresRegisteredRedirect: boolean;
302
+ } | null;
303
+ };
304
+ type PluginConnectionState = 'connected' | 'missing_credentials' | 'not_connected';
305
+ type ConnectionStatus = Record<string, PluginConnectionState>;
306
+ type ManagementOk = {
307
+ ok: true;
308
+ };
309
+ type PermissionRecord = CorsairPermission;
310
+
311
+ type CorsairManageNamespace = {
312
+ ok: () => ManagementOk;
313
+ tenants: {
314
+ list: () => Promise<Tenant[]>;
315
+ create: (input: CreateTenantInput) => Promise<Tenant>;
316
+ get: (id: string) => Promise<Tenant>;
317
+ };
318
+ plugins: {
319
+ list: () => Promise<PluginInfo[]>;
320
+ get: (id: string) => Promise<PluginInfo>;
321
+ };
322
+ connectionStatus: {
323
+ get: (query?: {
324
+ tenantId?: string;
325
+ }) => Promise<ConnectionStatus>;
326
+ };
327
+ permissions: {
328
+ get: (id: string) => Promise<PermissionRecord>;
329
+ getByToken: (token: string) => Promise<PermissionRecord>;
330
+ };
331
+ };
332
+
282
333
  /**
283
334
  * Raw incoming webhook data for matching (before full parsing).
284
335
  * Used by matcher functions to determine if a webhook should be handled.
@@ -1123,6 +1174,12 @@ type CorsairTenantWrapper<Plugins extends readonly CorsairPlugin[]> = {
1123
1174
  * Available at the root regardless of multi-tenancy setting.
1124
1175
  */
1125
1176
  permissions: CorsairPermissionsNamespace;
1177
+ /**
1178
+ * Management control plane namespace — in-process equivalent of the HTTP
1179
+ * `managementHandler`. Lists tenants, plugins, connection status, and
1180
+ * permission records without going through HTTP.
1181
+ */
1182
+ manage: CorsairManageNamespace;
1126
1183
  };
1127
1184
  /**
1128
1185
  * Single-tenant client that includes both plugin APIs and integration-level keys.
@@ -1138,6 +1195,12 @@ type CorsairSingleTenantClient<Plugins extends readonly CorsairPlugin[]> = Corsa
1138
1195
  * Available at the root regardless of multi-tenancy setting.
1139
1196
  */
1140
1197
  permissions: CorsairPermissionsNamespace;
1198
+ /**
1199
+ * Management control plane namespace — in-process equivalent of the HTTP
1200
+ * `managementHandler`. Lists tenants, plugins, connection status, and
1201
+ * permission records without going through HTTP.
1202
+ */
1203
+ manage: CorsairManageNamespace;
1141
1204
  };
1142
1205
 
1143
1206
  declare const CORSAIR_INTERNAL: unique symbol;
@@ -1189,4 +1252,4 @@ declare function createCorsair<const Plugins extends readonly CorsairPlugin[]>(c
1189
1252
  multiTenancy?: false | undefined;
1190
1253
  }): CorsairSingleTenantClient<Plugins>;
1191
1254
 
1192
- export { type PluginPermissionsConfig as $, type AuthTypes as A, type BoundWebhookTree as B, type CorsairSingleTenantClient as C, type ErrorHandler as D, type EndpointRiskLevel as E, type ErrorHandlerAndMatchFunction as F, type ErrorMatcher as G, type RetryStrategies as H, type IntegrationKeyManagerFor as I, type RetryStrategy as J, type EnforcePermissionOptions as K, type EnforcePermissionResult as L, type BeforeHookResult as M, type CorsairIntegration as N, type OAuthConfig as O, type PluginAuthConfig as P, type CorsairKeyBuilder as Q, type RawWebhookRequest as R, type CorsairKeyBuilderBase as S, type CorsairPluginContext as T, type EndpointHooks as U, type EndpointMetaEntry as V, type WebhookResponse as W, type KeyBuilderContext as X, type PermissionMode as Y, type PermissionPolicy as Z, type PluginEndpointMeta as _, type CorsairPlugin as a, type RequiredPluginEndpointMeta as a0, type RequiredPluginEndpointSchemas as a1, type RequiredPluginWebhookSchemas as a2, type WebhookHooks as a3, type Bivariant$2 as a4, type UnionToIntersection$1 as a5, type BindWebhooks as a6, type BoundWebhook as a7, type CorsairWebhook as a8, type CorsairWebhookHandler as a9, type CorsairWebhookMatcher as aa, type WebhookPathsOf as ab, type WebhookRequest as ac, type WebhookTree as ad, type CorsairTenantWrapper as b, type CorsairClient as c, type CorsairPermissionsNamespace as d, BaseProviders as e, createCorsair as f, type AccountKeyManagerFor as g, CORSAIR_INTERNAL as h, type CorsairInternalConfig as i, type AccountFieldNames as j, type BaseAuthFieldConfig as k, type BaseKeyManager as l, type IntegrationFieldNames as m, type OAuth2IntegrationCredentials as n, BASE_AUTH_FIELDS as o, type AllProviders as p, type PickAuth as q, type BindEndpoints as r, type BoundEndpointFn as s, type BoundEndpointTree as t, type CorsairContext as u, type CorsairEndpoint as v, type EndpointPathsOf as w, type EndpointTree as x, type CorsairErrorHandler as y, type ErrorContext as z };
1255
+ export { type RequiredPluginWebhookSchemas as $, type AuthTypes as A, type BaseAuthFieldConfig as B, type CorsairPlugin as C, type ErrorMatcher as D, type EndpointRiskLevel as E, type RetryStrategy as F, type CorsairPermissionsNamespace as G, type EnforcePermissionOptions as H, type IntegrationKeyManagerFor as I, type EnforcePermissionResult as J, type BeforeHookResult as K, type CorsairIntegration as L, type CorsairKeyBuilder as M, type CorsairKeyBuilderBase as N, type OAuthConfig as O, type PluginAuthConfig as P, type CorsairPluginContext as Q, type RetryStrategies as R, type EndpointHooks as S, type EndpointMetaEntry as T, type KeyBuilderContext as U, type PermissionMode as V, type PermissionPolicy as W, type PluginEndpointMeta as X, type PluginPermissionsConfig as Y, type RequiredPluginEndpointMeta as Z, type RequiredPluginEndpointSchemas as _, type AccountKeyManagerFor as a, type WebhookHooks as a0, type Bivariant$2 as a1, type UnionToIntersection$1 as a2, type BindWebhooks as a3, type BoundWebhook as a4, type BoundWebhookTree as a5, type CorsairWebhook as a6, type CorsairWebhookHandler as a7, type CorsairWebhookMatcher as a8, type RawWebhookRequest as a9, type WebhookPathsOf as aa, type WebhookRequest as ab, type WebhookResponse as ac, type WebhookTree as ad, type ManagementOk as ae, type Tenant as af, type CreateTenantInput as ag, type PluginInfo as ah, type ConnectionStatus as ai, type PermissionRecord as aj, type CorsairManageNamespace as ak, type PluginConnectionState as al, CORSAIR_INTERNAL as b, type CorsairInternalConfig as c, createCorsair as d, type AccountFieldNames as e, type BaseKeyManager as f, type IntegrationFieldNames as g, type OAuth2IntegrationCredentials as h, BASE_AUTH_FIELDS as i, type CorsairClient as j, type CorsairSingleTenantClient as k, type CorsairTenantWrapper as l, type AllProviders as m, BaseProviders as n, type PickAuth as o, type BindEndpoints as p, type BoundEndpointFn as q, type BoundEndpointTree as r, type CorsairContext as s, type CorsairEndpoint as t, type EndpointPathsOf as u, type EndpointTree as v, type CorsairErrorHandler as w, type ErrorContext as x, type ErrorHandler as y, type ErrorHandlerAndMatchFunction as z };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { C as CorsairSingleTenantClient, a as CorsairPlugin, b as CorsairTenantWrapper, c as CorsairClient, d as CorsairPermissionsNamespace, B as BoundWebhookTree, R as RawWebhookRequest, e as BaseProviders, W as WebhookResponse } from './index-DLSRcm5o.js';
2
- export { f as createCorsair } from './index-DLSRcm5o.js';
3
- import { F as FormFieldSchema, L as ListOperationsOptions } from './index-nV76ScYN.js';
4
- export { A as AuthMissingError, R as ResolveConnectLinkResult, f as formatDocSchemaShape, r as resolveConnectLink } from './index-nV76ScYN.js';
1
+ import { ae as ManagementOk, af as Tenant, ag as CreateTenantInput, ah as PluginInfo, ai as ConnectionStatus, aj as PermissionRecord, k as CorsairSingleTenantClient, C as CorsairPlugin, l as CorsairTenantWrapper, j as CorsairClient, G as CorsairPermissionsNamespace, a5 as BoundWebhookTree, a9 as RawWebhookRequest, n as BaseProviders, ac as WebhookResponse } from './index-DSVPkmM-.js';
2
+ export { ak as CorsairManageNamespace, al as PluginConnectionState, d as createCorsair } from './index-DSVPkmM-.js';
3
+ import { F as FormFieldSchema, L as ListOperationsOptions } from './index-BnkJ_TYy.js';
4
+ export { A as AuthMissingError, R as ResolveConnectLinkResult, f as formatDocSchemaShape, r as resolveConnectLink } from './index-BnkJ_TYy.js';
5
5
  export { SetupCorsairOptions, setupCorsair } from './setup.js';
6
6
  import './db.js';
7
7
  import 'kysely';
@@ -10,6 +10,81 @@ import 'pg';
10
10
  import 'postgres';
11
11
  import './orm.js';
12
12
 
13
+ type ManagementHandlerOptions = {
14
+ /** Path prefix the handler is mounted at, e.g. '/api/corsair'. Stripped before dispatch. */
15
+ basePath?: string;
16
+ /** Override the default error response. Return undefined to fall through. */
17
+ onError?: (err: unknown, req: Request) => Response | Promise<Response> | undefined;
18
+ };
19
+ declare function managementHandler(corsair: unknown, opts?: ManagementHandlerOptions): (req: Request) => Promise<Response>;
20
+
21
+ type ExpressLikeRequest = {
22
+ method: string;
23
+ originalUrl: string;
24
+ url: string;
25
+ headers: Record<string, string | string[] | undefined>;
26
+ body?: unknown;
27
+ protocol?: string;
28
+ get?: (name: string) => string | undefined;
29
+ };
30
+ type ExpressLikeResponse = {
31
+ status: (code: number) => ExpressLikeResponse;
32
+ setHeader: (name: string, value: string) => void;
33
+ send: (body: string | Buffer) => void;
34
+ };
35
+ type ExpressLikeNext = (err?: unknown) => void;
36
+ type ExpressHandler = (req: ExpressLikeRequest, res: ExpressLikeResponse, next: ExpressLikeNext) => Promise<void>;
37
+ declare function toExpressHandler(corsair: unknown, opts?: ManagementHandlerOptions): ExpressHandler;
38
+
39
+ type HonoLikeContext = {
40
+ req: {
41
+ raw: Request;
42
+ };
43
+ };
44
+ type HonoHandler = (c: HonoLikeContext) => Response | Promise<Response>;
45
+ declare function toHonoHandler(corsair: unknown, opts?: ManagementHandlerOptions): HonoHandler;
46
+
47
+ declare function toNextJsHandler(corsair: unknown, opts?: ManagementHandlerOptions): {
48
+ GET: (req: Request) => Promise<Response>;
49
+ POST: (req: Request) => Promise<Response>;
50
+ };
51
+
52
+ type CorsairClientOptions = {
53
+ /** Origin + base path of the mounted handler, e.g. 'https://api.example.com/api/corsair'. */
54
+ baseURL: string;
55
+ /** Optional fetch override. Defaults to globalThis.fetch. */
56
+ fetch?: typeof fetch;
57
+ };
58
+ type CorsairManagementClient = {
59
+ ok: () => Promise<ManagementOk>;
60
+ tenants: {
61
+ list: () => Promise<Tenant[]>;
62
+ create: (input: CreateTenantInput) => Promise<Tenant>;
63
+ get: (id: string) => Promise<Tenant>;
64
+ };
65
+ plugins: {
66
+ list: () => Promise<PluginInfo[]>;
67
+ get: (id: string) => Promise<PluginInfo>;
68
+ };
69
+ connectionStatus: {
70
+ get: (query?: {
71
+ tenantId?: string;
72
+ }) => Promise<ConnectionStatus>;
73
+ };
74
+ permissions: {
75
+ get: (id: string) => Promise<PermissionRecord>;
76
+ getByToken: (token: string) => Promise<PermissionRecord>;
77
+ };
78
+ };
79
+ declare class CorsairClientError extends Error {
80
+ readonly status: number;
81
+ readonly code: string;
82
+ readonly extra: Record<string, unknown>;
83
+ constructor(status: number, code: string, message: string, extra?: Record<string, unknown>);
84
+ }
85
+
86
+ declare function createCorsairClient(opts: CorsairClientOptions): CorsairManagementClient;
87
+
13
88
  type InspectCorsairPlugin = {
14
89
  id: CorsairPlugin['id'];
15
90
  };
@@ -170,4 +245,4 @@ declare function processWebhook(corsair: CorsairInstance, headers: WebhookHeader
170
245
  [x: string]: string | string[] | undefined;
171
246
  }): Promise<WebhookFilterResult>;
172
247
 
173
- export { type AnyCorsairInstance, FormFieldSchema, ListOperationsOptions, type PermissionExecuteResult, executePermission, getSchema, getStructuredSchema, listOperations, processWebhook };
248
+ export { type AnyCorsairInstance, ConnectionStatus, CorsairClientError, type CorsairClientOptions, type CorsairManagementClient, CreateTenantInput, type ExpressHandler, FormFieldSchema, type HonoHandler, ListOperationsOptions, type ManagementHandlerOptions, ManagementOk, type PermissionExecuteResult, PermissionRecord, PluginInfo, Tenant, createCorsairClient, executePermission, getSchema, getStructuredSchema, listOperations, managementHandler, processWebhook, toExpressHandler, toHonoHandler, toNextJsHandler };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{a as A}from"./chunk-6OUDU5GH.js";import{A as x,C,D as T,a as I,v as O,w as k,x as y,y as b,z as w}from"./chunk-PCO6RKXN.js";import"./chunk-UBM25HVI.js";import"./chunk-OZHME3EO.js";import"./chunk-3USHGH6P.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";function h(n){let r=n[C];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=b(h(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
2
- `):Object.values(o).flat().join(`
3
- `)}function E(n,r){return w(h(n),r)}function F(n,r){return y(h(n),r)}var $=Symbol.for("corsair:internal");function j(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 S(n){return n[$]?.database}async function _(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=S(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 t=e.tenant_id??"default",g=(n.withTenant?n.withTenant(t):n)[e.plugin];if(!g?.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 c=j(g.api,e.endpoint.split("."));if(!c)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,u=await c(i);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:u}}catch(i){let u=i instanceof Error?i.message:String(i),d=S(n);return d&&await d.db.updateTable("corsair_permissions").set({status:"failed",error:u,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:u}}}function v(n){return n!==null&&typeof n=="object"&&"match"in n&&"handler"in n&&typeof n.match=="function"&&typeof n.handler=="function"}function R(n,r,o=[]){for(let[e,t]of Object.entries(n))if(v(t)){if(t.match(r))return{webhook:t,path:[...o,e]}}else if(t&&typeof t=="object"){let s=R(t,r,[...o,e]);if(s)return s}return null}function N(n){let r={};for(let[o,e]of Object.entries(n))r[o.toLowerCase()]=Array.isArray(e)?e[0]:e;return r}function L(n){let r=n["x-goog-resource-uri"],o=n["x-goog-channel-id"];if(!r||!o)return null;let e={resourceId:n["x-goog-resource-id"]||"",resourceState:n["x-goog-resource-state"]||"",resourceUri:r,channelId:o,channelExpiration:n["x-goog-channel-expiration"]||""};return r.includes("/drive/")&&(e.kind="drive#change"),{message:{data:Buffer.from(JSON.stringify(e)).toString("base64"),messageId:n["x-goog-message-number"]||""}}}async function D(n,r,o,e){let t=N(r),s=typeof o=="string"?JSON.parse(o):o;(!s||typeof s=="object"&&Object.keys(s).length===0)&&t["x-goog-resource-uri"]&&(s=L(t)||s);let c={headers:t,body:s},i=e?.tenantId||"default",u=n.withTenant?n.withTenant(i):n,d=k;for(let l of d){let p=u[l];if(!p||!p.webhooks||p.pluginWebhookMatcher&&!p.pluginWebhookMatcher(c))continue;let f=R(p.webhooks,c);if(!f)continue;let m=f.path.join("."),P={payload:s,headers:t,rawBody:typeof o=="string"?o:JSON.stringify(o)};try{let a=await f.webhook.handler(P),W=!!Object.keys(a.returnToSender||{})?.length;return{plugin:l,action:m,body:s,response:W?{...a?.returnToSender,success:!0}:{success:!0},...a.responseHeaders&&{responseHeaders:a.responseHeaders}}}catch(a){return console.error(`Error executing webhook handler for ${l}.${m}:`,a),{plugin:l,action:m,body:s,response:{success:!1,error:a instanceof Error?a.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}export{I as AuthMissingError,T as createCorsair,_ as executePermission,x as formatDocSchemaShape,E as getSchema,F as getStructuredSchema,B as listOperations,D as processWebhook,O as resolveConnectLink,A as setupCorsair};
1
+ import{a as H}from"./chunk-UPIMTWVI.js";import{A as k,B as C,C as b,D as w,E as x,G as P,H as j,a as W,s as E,t as $,u as B,v as M,z as A}from"./chunk-LIZVHWQK.js";import"./chunk-UBM25HVI.js";import"./chunk-OZHME3EO.js";import"./chunk-3USHGH6P.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";var l=class extends Error{status;code;extra;constructor(t,r,e,s={}){super(e),this.name="CorsairClientError",this.status=t,this.code=r,this.extra=s}};function _(n){return n.endsWith("/")?n.slice(0,-1):n}async function R(n){let t={};try{t=await n.json()}catch{}let r=typeof t.error=="string"?t.error:"request_failed",e=typeof t.message=="string"?t.message:`Request failed (${n.status})`,{error:s,message:i,...o}=t;return new l(n.status,r,e,o)}function F(n){let t=_(n.baseURL),r=n.fetch??globalThis.fetch.bind(globalThis);async function e(o,u){let a=u&&Object.keys(u).length?`?${new URLSearchParams(u).toString()}`:"",c=await r(`${t}${o}${a}`,{method:"GET"});if(!c.ok)throw await R(c);return await c.json()}async function s(o,u){let a=await r(`${t}${o}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(u)});if(!a.ok)throw await R(a);return await a.json()}let i=encodeURIComponent;return{ok:()=>e("/ok"),tenants:{list:()=>e("/tenants"),create:o=>s("/tenants",o),get:o=>e(`/tenants/${i(o)}`)},plugins:{list:()=>e("/plugins"),get:o=>e(`/plugins/${i(o)}`)},connectionStatus:{get:o=>{let u={};return o?.tenantId&&(u.tenantId=o.tenantId),e("/connection-status",u)}},permissions:{get:o=>e(`/permissions/${i(o)}`),getByToken:o=>s("/permissions/lookup-by-token",{token:o})}}}function y(n){let t=n[P];if(!t)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return t.plugins}function L(n,t){let r=b(y(n),t);return typeof r=="string"?r:Array.isArray(r)?r.join(`
2
+ `):Object.values(r).flat().join(`
3
+ `)}function N(n,t){return w(y(n),t)}function v(n,t){return C(y(n),t)}var D=Symbol.for("corsair:internal");function q(n,t){let r=n;for(let e of t){if(!r||typeof r!="object")return null;r=r[e]}return typeof r=="function"?r:null}function S(n){return n[D]?.database}async function J(n,t){let r=new Date().toISOString(),e=await n.permissions.find_by_token(t);if(!e)return console.error("executePermission: no permission found for token."),{error:"executePermission: no permission found for token."};if(e.status!=="approved")return console.error(`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`),{endpoint:e.endpoint,plugin:e.plugin,result:null,error:`executePermission: permission '${e.id}' is '${e.status}', expected 'approved'.`};if(e.expires_at<r){let a=S(n);return a&&await a.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 s=e.tenant_id??"default",o=(n.withTenant?n.withTenant(s):n)[e.plugin];if(!o?.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 u=q(o.api,e.endpoint.split("."));if(!u)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 a=typeof e.args=="string"?JSON.parse(e.args):e.args,c=await u(a);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:c}}catch(a){let c=a instanceof Error?a.message:String(a),g=S(n);return g&&await g.db.updateTable("corsair_permissions").set({status:"failed",error:c,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:c}}}function U(n){return n!==null&&typeof n=="object"&&"match"in n&&"handler"in n&&typeof n.match=="function"&&typeof n.handler=="function"}function I(n,t,r=[]){for(let[e,s]of Object.entries(n))if(U(s)){if(s.match(t))return{webhook:s,path:[...r,e]}}else if(s&&typeof s=="object"){let i=I(s,t,[...r,e]);if(i)return i}return null}function z(n){let t={};for(let[r,e]of Object.entries(n))t[r.toLowerCase()]=Array.isArray(e)?e[0]:e;return t}function G(n){let t=n["x-goog-resource-uri"],r=n["x-goog-channel-id"];if(!t||!r)return null;let e={resourceId:n["x-goog-resource-id"]||"",resourceState:n["x-goog-resource-state"]||"",resourceUri:t,channelId:r,channelExpiration:n["x-goog-channel-expiration"]||""};return t.includes("/drive/")&&(e.kind="drive#change"),{message:{data:Buffer.from(JSON.stringify(e)).toString("base64"),messageId:n["x-goog-message-number"]||""}}}async function Y(n,t,r,e){let s=z(t),i=typeof r=="string"?JSON.parse(r):r;(!i||typeof i=="object"&&Object.keys(i).length===0)&&s["x-goog-resource-uri"]&&(i=G(s)||i);let u={headers:s,body:i},a=e?.tenantId||"default",c=n.withTenant?n.withTenant(a):n,g=k;for(let m of g){let d=c[m];if(!d||!d.webhooks||d.pluginWebhookMatcher&&!d.pluginWebhookMatcher(u))continue;let f=I(d.webhooks,u);if(!f)continue;let h=f.path.join("."),T={payload:i,headers:s,rawBody:typeof r=="string"?r:JSON.stringify(r)};try{let p=await f.webhook.handler(T),O=!!Object.keys(p.returnToSender||{})?.length;return{plugin:m,action:h,body:i,response:O?{...p?.returnToSender,success:!0}:{success:!0},...p.responseHeaders&&{responseHeaders:p.responseHeaders}}}catch(p){return console.error(`Error executing webhook handler for ${m}.${h}:`,p),{plugin:m,action:h,body:i,response:{success:!1,error:p instanceof Error?p.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}export{W as AuthMissingError,l as CorsairClientError,j as createCorsair,F as createCorsairClient,J as executePermission,x as formatDocSchemaShape,N as getSchema,v as getStructuredSchema,L as listOperations,E as managementHandler,Y as processWebhook,A as resolveConnectLink,H as setupCorsair,$ as toExpressHandler,B as toHonoHandler,M as toNextJsHandler};
package/dist/oauth.js CHANGED
@@ -1 +1 @@
1
- import{C as x,b as C,c as O,k as p,l as m,o as f,p as _,q as A,r as y,u as b}from"./chunk-PCO6RKXN.js";import{b as P}from"./chunk-UBM25HVI.js";import"./chunk-OZHME3EO.js";import"./chunk-3USHGH6P.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";import*as E from"querystring";function I(n){let e=n[x];if(!e)throw new Error("Invalid corsair instance");return e}function U(n,e){let o=n.plugins.find(a=>a.id===e);if(!o)throw new Error(`Plugin '${e}' not found`);return o}function N(n){let e=n.oauthConfig;if(!e)throw new Error(`Plugin '${n.id}' has no oauthConfig`);return e}async function R(n,e,o,a){let i=P(n),t=await i.integrations.findByName(e);if(!t)throw new Error(`Integration '${e}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:o,integration_id:t.id}))return;let r=C(),s=await O(r,a);await i.accounts.create({tenant_id:o,integration_id:t.id,config:{},dek:s})}async function S(n,e,o){let{tenantId:a,redirectUri:i}=o,t=I(n);if(!t.database)throw new Error("No database configured on corsair instance");let u=U(t,e),r=N(u),d=await p({authType:"oauth_2",integrationName:e,kek:t.kek,database:t.database}).get_client_id();if(!d)throw new Error(`client_id not configured for '${e}'`);let g=A(f(e,a),t.kek),l={...r.authParams,client_id:d,redirect_uri:i,response_type:"code",scope:r.scopes.join(" "),state:g};return{url:`${r.authUrl}?${E.stringify(l)}`,state:g}}async function K(n,e){let{code:o,state:a,redirectUri:i}=e,t=I(n),u=y(a,t.kek);if(!u)throw new Error("Invalid or tampered state parameter");let{plugin:r,tenantId:s}=u;if(!t.database)throw new Error("No database configured on corsair instance");let d=U(t,r),g=N(d),l=p({authType:"oauth_2",integrationName:r,kek:t.kek,database:t.database}),k=await l.get_client_id(),w=await l.get_client_secret();if(!k||!w)throw new Error(`Credentials not configured for '${r}'`);await R(t.database,r,s,t.kek);let c=await b(o,k,w,g,i);if(!c.access_token)throw new Error(`No access_token returned from ${g.providerName}`);let h=m({authType:"oauth_2",integrationName:r,tenantId:s,kek:t.kek,database:t.database});return await h.set_access_token(c.access_token),c.refresh_token&&await h.set_refresh_token(c.refresh_token),c.expires_in&&await h.set_expires_at(String(Math.floor(Date.now()/1e3)+c.expires_in)),{plugin:r,tenantId:s}}export{_ as decodeOAuthState,f as encodeOAuthState,S as generateOAuthUrl,K as processOAuthCallback};
1
+ import{G as x,b as C,c as O,k as p,l as m,o as f,p as _,q as A,r as y,y as b}from"./chunk-LIZVHWQK.js";import{b as P}from"./chunk-UBM25HVI.js";import"./chunk-OZHME3EO.js";import"./chunk-3USHGH6P.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";import*as E from"querystring";function I(n){let e=n[x];if(!e)throw new Error("Invalid corsair instance");return e}function U(n,e){let o=n.plugins.find(a=>a.id===e);if(!o)throw new Error(`Plugin '${e}' not found`);return o}function N(n){let e=n.oauthConfig;if(!e)throw new Error(`Plugin '${n.id}' has no oauthConfig`);return e}async function R(n,e,o,a){let i=P(n),t=await i.integrations.findByName(e);if(!t)throw new Error(`Integration '${e}' not found. Run setupCorsair first.`);if(await i.accounts.findOne({tenant_id:o,integration_id:t.id}))return;let r=C(),s=await O(r,a);await i.accounts.create({tenant_id:o,integration_id:t.id,config:{},dek:s})}async function S(n,e,o){let{tenantId:a,redirectUri:i}=o,t=I(n);if(!t.database)throw new Error("No database configured on corsair instance");let u=U(t,e),r=N(u),d=await p({authType:"oauth_2",integrationName:e,kek:t.kek,database:t.database}).get_client_id();if(!d)throw new Error(`client_id not configured for '${e}'`);let g=A(f(e,a),t.kek),l={...r.authParams,client_id:d,redirect_uri:i,response_type:"code",scope:r.scopes.join(" "),state:g};return{url:`${r.authUrl}?${E.stringify(l)}`,state:g}}async function K(n,e){let{code:o,state:a,redirectUri:i}=e,t=I(n),u=y(a,t.kek);if(!u)throw new Error("Invalid or tampered state parameter");let{plugin:r,tenantId:s}=u;if(!t.database)throw new Error("No database configured on corsair instance");let d=U(t,r),g=N(d),l=p({authType:"oauth_2",integrationName:r,kek:t.kek,database:t.database}),k=await l.get_client_id(),w=await l.get_client_secret();if(!k||!w)throw new Error(`Credentials not configured for '${r}'`);await R(t.database,r,s,t.kek);let c=await b(o,k,w,g,i);if(!c.access_token)throw new Error(`No access_token returned from ${g.providerName}`);let h=m({authType:"oauth_2",integrationName:r,tenantId:s,kek:t.kek,database:t.database});return await h.set_access_token(c.access_token),c.refresh_token&&await h.set_refresh_token(c.refresh_token),c.expires_in&&await h.set_expires_at(String(Math.floor(Date.now()/1e3)+c.expires_in)),{plugin:r,tenantId:s}}export{_ as decodeOAuthState,f as encodeOAuthState,S as generateOAuthUrl,K as processOAuthCallback};
package/dist/setup.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as CorsairPlugin, C as CorsairSingleTenantClient, b as CorsairTenantWrapper, i as CorsairInternalConfig } from './index-DLSRcm5o.js';
1
+ import { C as CorsairPlugin, k as CorsairSingleTenantClient, l as CorsairTenantWrapper, c as CorsairInternalConfig } from './index-DSVPkmM-.js';
2
2
  import { CorsairDatabase } from './db.js';
3
3
  import 'zod';
4
4
  import './orm.js';
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{a as o,b as r}from"./chunk-6OUDU5GH.js";import"./chunk-PCO6RKXN.js";import"./chunk-UBM25HVI.js";import"./chunk-OZHME3EO.js";import"./chunk-3USHGH6P.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";export{r as applySetupCredentials,o as setupCorsair};
1
+ import{a as o,b as r}from"./chunk-UPIMTWVI.js";import"./chunk-LIZVHWQK.js";import"./chunk-UBM25HVI.js";import"./chunk-OZHME3EO.js";import"./chunk-3USHGH6P.js";import"./chunk-FL4GOHVN.js";import"./chunk-QAIKSQAD.js";export{r as applySetupCredentials,o as setupCorsair};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.75",
3
+ "version": "0.1.76",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,26 +0,0 @@
1
- import{a as Pe,b as de}from"./chunk-OZHME3EO.js";import{a as xe}from"./chunk-FL4GOHVN.js";var N=class extends Error{pluginId;authType;constructor(n,o,t){super(t??`[auth-missing:${n}:${o}]`),Object.setPrototypeOf(this,new.target.prototype),this.name="AuthMissingError",this.pluginId=n,this.authType=o}};import{createCipheriv as Ee,createDecipheriv as Re,randomBytes as ne,scrypt as on}from"crypto";import{promisify as rn}from"util";var Ie=rn(on),te="aes-256-gcm",De=12,oe=16,sn=16,V=32;function B(){return ne(V).toString("base64")}async function j(e,n){let o=ne(sn),t=await Ie(n,o,V),r=ne(De),i=Ee(te,t,r,{authTagLength:oe}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[o.toString("base64"),r.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function M(e,n){let[o,t,r,i]=e.split(":");if(!o||!t||!r||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(o,"base64"),a=Buffer.from(t,"base64"),d=Buffer.from(r,"base64"),p=Buffer.from(i,"base64"),c=await Ie(n,s,V),l=Re(te,c,a,{authTagLength:oe});return l.setAuthTag(d),Buffer.concat([l.update(p),l.final()]).toString("utf8")}function ue(e,n){let o=Buffer.from(n,"base64"),t=ne(De),r=Ee(te,o,t,{authTagLength:oe}),i=Buffer.concat([r.update(e,"utf8"),r.final()]),s=r.getAuthTag();return[t.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function le(e,n){let[o,t,r]=e.split(":");if(!o||!t||!r)throw new Error("Invalid encrypted data format");let i=Buffer.from(n,"base64"),s=Buffer.from(o,"base64"),a=Buffer.from(t,"base64"),d=Buffer.from(r,"base64"),p=Re(te,i,s,{authTagLength:oe});return p.setAuthTag(a),Buffer.concat([p.update(d),p.final()]).toString("utf8")}function H(e,n){let o={};for(let[t,r]of Object.entries(e))o[t]=ue(r,n);return o}function L(e,n){let o={};for(let[t,r]of Object.entries(e))o[t]=le(r,n);return o}function Y(e,n,o){let t=L(e,n);return H(t,o)}function re(e,n){let o=[];e||o.push("database"),n||o.push("kek");let t={};return new Proxy(t,{get(r,i){let s=o.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${o.join(" and ")} ${s?"are":"is"} not configured. Provide both 'database' and 'kek' in createCorsair() to enable key management.
2
-
3
- To generate a KEK, run: openssl rand -base64 ${V}`)}})}var Q={oauth_2:{integration:["client_id","client_secret","redirect_url"],account:["access_token","refresh_token","expires_at","scope","webhook_signature"]},api_key:{integration:[],account:["api_key","webhook_signature"]},bot_token:{integration:[],account:["bot_token","webhook_signature"]}};function ve(e,n,o){let t={};for(let r of o)t[`get_${r}`]=async()=>(await e())[r]??null,t[`set_${r}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await n({[r]:s})};return t}var pe=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function q(e){let{authType:n,integrationName:o,kek:t,database:r,extraIntegrationFields:i=[]}=e,s=[...Q[n].integration,...i],a=null,d={kek:t,integrationName:o,getIntegration:async()=>{if(a)return a;let u=await r.db.selectFrom("corsair_integrations").selectAll().where("name","=",o).executeTakeFirst();if(!u)throw new Error(`Integration "${o}" not found. Make sure to create the integration first.`);return a={id:u.id,config:pe(u.config),dek:u.dek??null},a},updateIntegration:async u=>{let h=await d.getIntegration();await r.db.updateTable("corsair_integrations").set({...u.config!==void 0?{config:u.config}:{},...u.dek!==void 0?{dek:u.dek}:{},updated_at:new Date}).where("id","=",h.id).execute(),a=null}},p=null,c=async()=>{if(p)return p;let u=await d.getIntegration();if(!u.dek)throw new Error(`No DEK found for integration "${o}". Initialize the integration first.`);return p=await M(u.dek,t),p},l=async()=>{let u=await d.getIntegration(),h=await c(),b=u.config;return!b||Object.keys(b).length===0?{}:L(b,h)};return{get_dek:c,issue_new_dek:async()=>{let u=await d.getIntegration(),h=B(),b={};if(u.dek){let w=await M(u.dek,t),A=u.config;A&&Object.keys(A).length>0&&(b=Y(A,w,h))}let k=await j(h,t);return await d.updateIntegration({config:b,dek:k}),p=h,h},...ve(l,async u=>{let h=await c(),b;try{b=await l()}catch(A){console.error(`[corsair] Failed to decrypt config for integration "${o}", starting fresh:`,A),b={}}let k={...b};for(let[A,y]of Object.entries(u))y===null?delete k[A]:k[A]=y;let w=H(k,h);await d.updateIntegration({config:w})},s)}}function ie(e){let{authType:n,integrationName:o,tenantId:t,kek:r,database:i,extraAccountFields:s=[]}=e,a=[...Q[n].account,...s],d=null,p=null,c=async()=>{if(p)return p;let y=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",o).executeTakeFirst();if(!y)throw new Error(`Integration "${o}" not found. Make sure to create the integration first.`);return p={id:y.id,config:pe(y.config),dek:y.dek??null},p},l={kek:r,integrationName:o,tenantId:t,getIntegration:c,getAccount:async()=>{if(d)return d;let y=await c(),m=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",t).where("integration_id","=",y.id).executeTakeFirst();if(!m)throw new Error(`Account not found for tenant "${t}" and integration "${o}". Make sure to create the account first.`);return d={id:m.id,config:pe(m.config),dek:m.dek??null},d},updateAccount:async y=>{let m=await l.getAccount();await i.db.updateTable("corsair_accounts").set({...y.config!==void 0?{config:y.config}:{},...y.dek!==void 0?{dek:y.dek}:{},updated_at:new Date}).where("id","=",m.id).execute(),d=null}},f=null,g=null,u=async()=>{if(f)return f;let y=await l.getAccount();if(!y.dek)throw new Error(`No DEK found for account (tenant: "${t}", integration: "${o}"). Initialize the account first.`);return f=await M(y.dek,r),f},h=async()=>{if(g)return g;let y=await l.getIntegration();if(!y.dek)throw new Error(`No DEK found for integration "${o}". Initialize the integration first.`);return g=await M(y.dek,r),g},b=async()=>{let y=await l.getAccount(),m=await u(),T=y.config;return!T||Object.keys(T).length===0?{}:L(T,m)},k=async()=>{let y=await l.getIntegration(),m=await h(),T=y.config;return!T||Object.keys(T).length===0?{}:L(T,m)},A={get_dek:u,issue_new_dek:async()=>{let y=await l.getAccount(),m=B(),T={};if(y.dek){let I=await M(y.dek,r),C=y.config;C&&Object.keys(C).length>0&&(T=Y(C,I,m))}let P=await j(m,r);return await l.updateAccount({config:T,dek:P}),f=m,m},...ve(b,async y=>{let m=await u(),T;try{T=await b()}catch(C){console.error(`[corsair] Failed to decrypt config for account (tenant: "${t}", integration: "${o}"), starting fresh:`,C),T={}}let P={...T};for(let[C,O]of Object.entries(y))O===null?delete P[C]:P[C]=O;let I=H(P,m);await l.updateAccount({config:I})},a)};return n==="oauth_2"&&(A.get_integration_credentials=async()=>{let y=await k();return{client_id:y.client_id||null,client_secret:y.client_secret||null,redirect_url:y.redirect_url??null}}),A}async function _e(e,n,o){let t=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!t)throw new Error(`Integration "${n}" not found.`);let r=B(),i=await j(r,o);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",t.id).execute(),r}async function Se(e,n,o,t){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!r)throw new Error(`Integration "${n}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",o).where("integration_id","=",r.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${o}" and integration "${n}".`);let s=B(),a=await j(s,t);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}import*as X from"crypto";function Oe(e,n){return Buffer.from(JSON.stringify({plugin:e,tenantId:n,iat:Date.now()})).toString("base64url")}function an(e,{maxAgeMs:n}={}){try{let o=e.includes(".")?e.split(".")[0]:e,t=JSON.parse(Buffer.from(o,"base64url").toString("utf-8"));if(t!==null&&typeof t=="object"&&"plugin"in t&&"tenantId"in t&&typeof t.plugin=="string"&&typeof t.tenantId=="string"){let r=t;return n!==void 0&&typeof r.iat=="number"&&Date.now()-r.iat>n?null:r}return null}catch{return null}}function Fe(e,n){let o=X.createHmac("sha256",n).update(e).digest("base64url");return`${e}.${o}`}var cn=600*1e3;function $e(e,n){let o=e.lastIndexOf(".");if(o===-1)return null;let t=e.slice(0,o),r=e.slice(o+1),i=X.createHmac("sha256",n).update(t).digest("base64url"),s=Buffer.from(r,"base64url"),a=Buffer.from(i,"base64url");return s.length!==a.length||!X.timingSafeEqual(s,a)?null:an(t,{maxAgeMs:cn})}var dn=async(e,n)=>(console.error(`[corsair:${n.pluginId}:${n.operation}]`,{error:e.message,input:n.input}),{maxRetries:0});async function Me(e,n,o,t,r){let i={pluginId:n,operation:o,input:t,originalError:e},s=Object.keys(r).find(p=>r[p]?.match(e,i));return await(r[s||"DEFAULT"]?.handler||dn)(e,i)}import{randomBytes as un}from"crypto";import{v4 as ln}from"uuid";var pn={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 gn(e,n,o){return o!==void 0?o:pn[n][e]}function Ke(e){let n=/(\d+)(d|h|m|s)/g,o=0,t;for(;(t=n.exec(e))!==null;){let r=parseInt(t[1],10);switch(t[2]){case"d":o+=r*864e5;break;case"h":o+=r*36e5;break;case"m":o+=r*6e4;break;case"s":o+=r*1e3;break}}return o>0?o:600*1e3}function Ne(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 Ze(e,n,o){let t=Date.now()+o;for(;Date.now()<t;){let r=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",n).executeTakeFirst();if(!r)return{result:"blocked",reason:"pending"};if(r.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(r.status==="denied")return{result:"blocked",reason:"denied"};if(r.status==="expired"||r.status==="failed")return{result:"blocked",reason:"timeout"};await new Promise(i=>setTimeout(i,500))}return{result:"blocked",reason:"timeout"}}async function Be(e){let n=gn(e.riskLevel,e.mode,e.override);if(n==="allow")return{result:"allow"};let o=e.meta?.irreversible?" (irreversible)":"",t=e.meta?.description?`${e.meta.description}${o}`:`${e.pluginId}.${e.endpointPath}${o}`;if(n==="deny"||!e.db)return console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 denied by permission mode '${e.mode}'.`,`
4
- Action: ${t}`,`
5
- To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked",reason:"policy"};let r=JSON.stringify(e.args),i=new Date().toISOString(),s=e.tenantId??"default",a=await e.db.db.selectFrom("corsair_permissions").selectAll().where("plugin","=",e.pluginId).where("endpoint","=",e.endpointPath).where("args","=",r).where("tenant_id","=",s).where("expires_at",">",i).where("status","in",["pending","approved","executing"]).orderBy("created_at","desc").limit(1).executeTakeFirst();if(a){if(a.status==="approved"){let u=e.db,h=a.id;return{result:"allow",onComplete:async()=>{await u.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",h).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
6
- Action: ${t}`,`
7
- Permission ID: ${a.id}`,`
8
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Ze(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked",reason:"pending",id:a.id,token:a.token})}let d=ln(),p=un(32).toString("hex"),c=e.timeoutMs??600*1e3,l=new Date(Date.now()+c).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:d,created_at:new Date,updated_at:new Date,token:p,plugin:e.pluginId,endpoint:e.endpointPath,args:r,tenant_id:s,status:"pending",expires_at:l}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
9
- Action: ${t}`,`
10
- Permission ID: ${d}`,`
11
- Permission token: ${p}`,`
12
- Expires at: ${l}`,`
13
- Use the token to approve or deny this request.`),(typeof e.approvalMode=="function"?e.approvalMode():e.approvalMode)==="synchronous"?Ze(e.db,d,c):{result:"blocked",reason:"pending",id:d,token:p}}function fn(e){return typeof e=="function"}function yn(e,n,o){let t=Fe(Oe(e,n.tenantId??o??"default"),n.kek),r=new URL(n.baseUrl);r.searchParams.set("state",t);let i=r.toString(),s=n.onAuthMissing?n.onAuthMissing({plugin:e,connectUrl:i,state:t}):`[auth-missing:${e}] Authentication required. Direct the user to connect their account: ${i}`;return new Error(s)}function ge({endpoints:e,hooks:n,ctx:o,tree:t,pluginId:r,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:d,endpointMeta:p,database:c,approvalConfig:l,tenantId:f,connectConfig:g}){for(let[u,h]of Object.entries(e)){let b=n?.[u];if(fn(h)){let k=b,w=[...s,u].join("."),A=async(y={})=>{let m;if(d){let E=p?.[w],{result:U,reason:S,onComplete:J,token:F,id:K}=await Be({pluginId:r,endpointPath:w,args:y,mode:d.mode,override:d.overrides?.[w],riskLevel:E?.riskLevel??"write",meta:E,db:c,timeoutMs:l?Ke(l.timeout):void 0,tenantId:f,approvalMode:l?.mode});if(U==="blocked"){let x;throw S==="denied"?x=`Action '${w}' was denied by the user. Await further instructions before proceeding.`:S==="policy"?x=`Action '${w}' is blocked by the permission policy. Update the corsair config to allow it.`:S==="timeout"?x=`Action '${w}' timed out waiting for approval.`:l?.formatAsyncMessage&&F&&K?x=l.formatAsyncMessage({token:F,id:K,plugin:r,endpoint:w,args:y}):x=`Action '${w}' requires user approval before it can run.`,new Error(x)}m=J}let T=async(E,U,S)=>{try{return await h(U,S)}catch(J){if(J instanceof Error){let F=await Me(J,r,w,typeof S=="object"&&S!==null?S:{args:S},i);if(E<(F.maxRetries||0)){let K=E+1;console.log(`Retrying (${K} / ${F.maxRetries})...`);let x;if(F.headersRetryAfterMs)x=F.headersRetryAfterMs;else switch(F.retryStrategy){case"exponential_backoff":x=Math.pow(2,K-1)*1e3;break;case"exponential_backoff_jitter":let ce=Math.pow(2,K-1)*1e3,tn=(Math.random()-.5)*1e3;x=Math.max(0,ce+tn);break;case"linear_1s":x=1e3;break;case"linear_2s":x=2e3;break;case"linear_3s":x=3e3;break;case"linear_4s":x=4e3;break;default:x=1e3;break}await new Promise(ce=>setTimeout(ce,x)),await T(K,U,S),console.log(`[corsair:${r}:${w}] Retry strategy:`,F)}}throw J}},P;try{P=a?await a(o,"endpoint"):void 0}catch(E){throw g?.oauthConfig&&g.kek&&E instanceof N&&E.authType==="oauth_2"?yn(r,g,f):E}if(!k?.before&&!k?.after){let E=await T(0,{...o,key:P},y);return await m?.(),E}let I={...o,key:P},C=k.before?await k.before(I,y):{ctx:I,args:y,continue:!0,passToAfter:void 0};if(C.continue===!1)return;let O=await T(0,C.ctx,C.args);return await k.after?.(C.ctx,O,C.passToAfter),await m?.(),O};t[u]=A}else if(h&&typeof h=="object"){let k={};ge({endpoints:h,hooks:b,ctx:o,tree:k,pluginId:r,errorHandlers:i,currentPath:[...s,u],keyBuilder:a,permissionsConfig:d,endpointMeta:p,database:c,approvalConfig:l,tenantId:f,connectConfig:g}),t[u]=k}}}function hn(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function fe({webhooks:e,hooks:n,ctx:o,webhooksTree:t,keyBuilder:r}){for(let[i,s]of Object.entries(e)){let a=n?.[i];if(hn(s)){let d=a,p=async c=>{let l=(g,u)=>s.handler(g,u),f=r?await r(o,"webhook"):void 0;return!d?.before&&!d?.after?l({...o,key:f},c):(async()=>{let g={...o,key:f},u=d.before?await d.before(g,c):{ctx:g,args:c,continue:!0,passToAfter:void 0};if(u.continue===!1)return;let h=await l(u.ctx,u.args);return h?.success===!0&&await d.after?.(u.ctx,h,u.passToAfter),h})()};t[i]={match:s.match,handler:p}}else if(s&&typeof s=="object"){let d={};fe({webhooks:s,hooks:a,ctx:o,webhooksTree:d,keyBuilder:r}),t[i]=d}}}function mn(e,n,o){let t=null;return async()=>{if(t)return t;if(!e)throw new Error("Database not configured");let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!r)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",o).where("integration_id","=",r.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${o}" and integration "${n}". Make sure to create the account first.`);return t=i.id,t}}function kn(e,n,o,t,r){return e?de(e.db,n,o,t,r):{findByEntityId:async()=>null,findById:async()=>null,findManyByEntityIds:async()=>[],list:async()=>[],search:async()=>[],upsertByEntityId:async()=>{throw new Error("Database not configured")},deleteById:async()=>!1,deleteByEntityId:async()=>!1,count:async()=>0}}function ye(e,n){let{database:o,tenantId:t,kek:r,rootErrorHandlers:i,approvalConfig:s,connectConfig:a}=n,d={},p={};for(let c of e)d[c.id]={},p[c.id]={};for(let c of e){let l=c.schema,f=t??"default",g=mn(o,c.id,f);if(l?.entities){let C={};for(let[O,E]of Object.entries(l.entities)){let U=o?de(o.db,g,O,l.version,E):kn(void 0,g,O,l.version,E);C[O]=U}p[c.id].db=C,d[c.id].db=C}let u=c.options,h=c.authConfig,b;if(o&&r&&u?.authType){let C=h?.[u.authType]?.account??[];b=ie({authType:u.authType,integrationName:c.id,tenantId:f,kek:r,database:o,extraAccountFields:C}),d[c.id].keys=b}let k={database:o,db:p[c.id]?.db??{},$getAccountId:g,...c.options?{options:c.options}:{},...b?{keys:b,authType:u?.authType}:{},...t?{tenantId:t}:{}},w=c.endpoints??{},A=c.hooks,y={...i,...c.errorHandlers},m={},T=c.options?.permissions;ge({endpoints:w,hooks:A,ctx:k,tree:m,pluginId:c.id,errorHandlers:y,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:T,endpointMeta:c.endpointMeta,database:o,approvalConfig:s,tenantId:t,connectConfig:a?{...a,oauthConfig:c.oauthConfig,kek:r,tenantId:f}:void 0}),Object.keys(m).length>0&&(d[c.id].api=m),k.endpoints=m;let P=c.webhooks??{},I=c.webhookHooks;if(Object.keys(P).length>0){let C={};fe({webhooks:P,hooks:I,ctx:k,webhooksTree:C,keyBuilder:c.keyBuilder}),d[c.id].webhooks=C,c.pluginWebhookMatcher&&(d[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher)}}return d}function je(e,n,o){let t={};for(let r of e){let i=r.options,s=r.authConfig;if(i?.authType){let a=s?.[i.authType]?.integration??[],d=q({authType:i.authType,integrationName:r.id,kek:o,database:n,extraIntegrationFields:a});t[r.id]=d}}return t}async function Le(e,n,o,t,r="pending"){if(!e)return null;try{let i=Pe(),s=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:s,updated_at:s,account_id:n,event_type:o,payload:t,status:r}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function bn(e,n,o,t="pending"){try{let r=await e.$getAccountId();return Le(e.database,r,n,o,t)}catch(r){return console.warn("Failed to log event:",r),null}}import*as We from"https";import*as Ue from"querystring";function He(e,n,o,t,r){let i=new URL(t.tokenUrl),s=t.tokenAuthMethod==="basic";return new Promise((a,d)=>{let p={code:e.trim(),redirect_uri:r,grant_type:"authorization_code"};s||(p.client_id=n,p.client_secret=o);let c=Ue.stringify(p),l={"Content-Type":"application/x-www-form-urlencoded","Content-Length":Buffer.byteLength(c).toString()};s&&(l.Authorization=`Basic ${Buffer.from(`${n}:${o}`).toString("base64")}`);let f=We.request({hostname:i.hostname,...i.port?{port:Number(i.port)}:{},path:i.pathname+i.search,method:"POST",headers:l},g=>{let u="";g.on("data",h=>{u+=h}),g.on("end",()=>{if(g.statusCode!==200){d(new Error(`Token exchange failed (${g.statusCode}): ${u}`));return}try{a(JSON.parse(u))}catch{d(new Error(`Token endpoint returned non-JSON response: ${u}`))}})});f.on("error",g=>d(new Error(`Request failed: ${g.message}`))),f.write(c),f.end()})}import*as qe from"querystring";function wn(e){let n=e[ee];if(!n)throw new Error("Invalid corsair instance");return n}function Cn(e,n){let o=e.plugins.find(t=>t.id===n);if(!o)throw new Error(`Plugin '${n}' not found`);return o}function Tn(e){let n=e.oauthConfig;if(!n)throw new Error(`Plugin '${e.id}' has no oauthConfig`);return n}async function An(e,n){let o=wn(e);if(!o.database)throw new Error("No database configured on corsair instance");let t=o.connect?.redirectUri;if(!t)throw new Error("No redirectUri configured. Set connect.redirectUri in createCorsair().");let r=$e(n,o.kek);if(!r)throw new Error("Invalid or tampered state parameter");let{plugin:i,tenantId:s}=r,a=Cn(o,i),d=Tn(a),c=await q({authType:"oauth_2",integrationName:i,kek:o.kek,database:o.database}).get_client_id();if(!c)throw new Error(`client_id not configured for '${i}'`);let l={...d.authParams,client_id:c,redirect_uri:t,response_type:"code",scope:d.scopes.join(" "),state:n},f=`${d.authUrl}?${qe.stringify(l)}`;return{plugin:i,tenantId:s,providerName:d.providerName,oauthUrl:f,state:n}}var ze=["airtable","amplitude","asana","bitwarden","bluesky","box","cal","calendly","cloudflare","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gitlab","gmail","googlecalendar","googledrive","googlesheets","grafana","hackernews","hubspot","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","tally","tavily","teams","telegram","todoist","trello","twitter","twitterapiio","typeform","vapi","xquik","youtube","zendesk","zoom"];var Ge=" ";function v(e){let n=e;return n._def??n.def??{}}function _(e){let n=e.typeName;if(n)return n;let o=e.type;if(o)return`Zod${o.split("_").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}`}function D(e){return e.innerType??e.schema??e.out??e.in}function Ve(e,n){switch(n){case"ZodPipe":return e.in??e.innerType;case"ZodEffects":return e.schema??e.innerType;case"ZodTransform":return e.schema??e.innerType??e.in;default:return D(e)}}function Ye(e){let n=e.type;return e.element??(typeof n=="string"?void 0:n)}function ae(e,n){let o=n.shape??e.shape;return typeof o=="function"?o():o}function z(e){return Array.isArray(e.options)?e.options:Array.isArray(e.values)?e.values:e.entries!==null&&typeof e.entries=="object"&&!Array.isArray(e.entries)?Object.values(e.entries):[]}function Qe(e,n){return e.description??n.description}function xn(e){let n=e;for(;n;){let o=v(n),t=Qe(n,o);if(t)return t;let r=_(o);if(we(r)||r==="ZodPipe"||r==="ZodEffects"||r==="ZodTransform"){n=Ve(o,r);continue}break}}function we(e){return e==="ZodOptional"||e==="ZodNullable"||e==="ZodDefault"||e==="ZodCatch"}function R(e){let n=v(e),o=_(n);switch(o){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"Date";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(n.value??z(n)[0]??"unknown");case"ZodEnum":return z(n).map(t=>String(t)).join(" | ");case"ZodOptional":{let t=D(n);return t?R(t):"unknown"}case"ZodNullable":{let t=D(n);return`${t?R(t):"unknown"} | null`}case"ZodDefault":case"ZodCatch":{let t=D(n);return t?R(t):"unknown"}case"ZodArray":{let t=Ye(n);if(!t)return"unknown[]";let r=v(t),i=_(r)==="ZodUnion",s=R(t);return`${i?`(${s})`:s}[]`}case"ZodRecord":return"{}";case"ZodObject":{let t=ae(e,n),r=Object.entries(t);return r.length===0?"{}":`{ ${r.map(([s,a])=>{let d=_(v(a));return`${d==="ZodOptional"||d==="ZodNullable"?s+"?":s}: ${R(a)}`}).join(", ")} }`}case"ZodUnion":return z(n).map(t=>R(t)).join(" | ");case"ZodIntersection":return`${R(n.left)} & ${R(n.right)}`;case"ZodPipe":case"ZodTransform":case"ZodEffects":{let t=Ve(n,o);return t?R(t):"unknown"}default:return(o??"unknown").replace("Zod","").toLowerCase()}}function $(e){let n=v(e),o=_(n),t=Qe(e,n);switch(o){case"ZodString":return{kind:"string",optional:!1,description:t};case"ZodNumber":return{kind:"number",optional:!1,description:t};case"ZodBoolean":return{kind:"boolean",optional:!1,description:t};case"ZodLiteral":{let r=n.value??z(n)[0],i=typeof r=="string"||typeof r=="number"||typeof r=="boolean"?r:String(r??"");return{kind:"literal",optional:!1,description:t,value:i}}case"ZodEnum":{let r=z(n).map(i=>String(i));return{kind:"string",optional:!1,description:t,enum:r}}case"ZodOptional":{let r=D(n),i=r?$(r):{kind:"unknown",optional:!1};return{...i,optional:!0,description:t??i.description}}case"ZodNullable":{let r=D(n),i=r?$(r):{kind:"unknown",optional:!1};return{...i,optional:!0,description:t??i.description}}case"ZodDefault":case"ZodCatch":{let r=D(n);return r?{...$(r),description:t}:{kind:"unknown",optional:!1,description:t}}case"ZodArray":{let r=Ye(n);return{kind:"array",optional:!1,description:t,items:r?$(r):{kind:"unknown",optional:!1}}}case"ZodObject":{let r=ae(e,n),i={};for(let[s,a]of Object.entries(r))i[s]=$(a);return{kind:"object",optional:!1,description:t,fields:i}}case"ZodRecord":return{kind:"unknown",optional:!1,description:t};case"ZodUnion":{let r=z(n);for(let i of r){let s=v(i);if(_(s)==="ZodObject")return{...$(i),description:t}}return{kind:"unknown",optional:!1,description:t}}case"ZodIntersection":case"ZodPipe":case"ZodTransform":case"ZodEffects":{let r=D(n);return r?{...$(r),description:t}:{kind:"unknown",optional:!1,description:t}}default:return{kind:"unknown",optional:!1,description:t}}}function wt(e,n){let o=n.toLowerCase(),t=o.indexOf(".");if(t===-1)return null;let r=o.slice(0,t),i=o.slice(t+1),s=e.find(c=>c.id===r);if(!s)return null;let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=Z(s.endpointMeta,a),p=Z(s.endpointSchemas,a);return!d&&!p?null:{input:p?.input?$(p.input):null,output:p?.output?$(p.output):null,description:d?.description}}var Ce=["equals","contains","startsWith","endsWith","in"],Pn=["equals","gt","gte","lt","lte","in"],En=["equals"],Rn=["equals","before","after","between"];function Xe(e){let n=v(e);switch(_(n)){case"ZodOptional":case"ZodNullable":case"ZodDefault":case"ZodCatch":{let t=D(n);return t?Xe(t):null}case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function Te(e){let n=v(e),o=_(n);if(we(o)){let i=D(n);return i?Te(i):{}}if(o!=="ZodObject")return{};let t=ae(e,n),r={};for(let[i,s]of Object.entries(t)){let a=Xe(s);a==="string"?r[i]={type:"string",operators:Ce}:a==="number"?r[i]={type:"number",operators:Pn}:a==="boolean"?r[i]={type:"boolean",operators:En}:a==="date"&&(r[i]={type:"date",operators:Rn})}return r}function en(e,n){for(let[o,t]of Object.entries(e))if(o.toLowerCase()===n)return[o,t]}function me(e,n,o){for(let[t,r]of Object.entries(e)){let i=[...n,t];typeof r=="function"?o.push(i.join(".")):r!==null&&typeof r=="object"&&me(r,i,o)}}function ke(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function be(e,n,o){for(let[t,r]of Object.entries(e)){let i=[...n,t];ke(r)?o.push(i.join(".")):r!==null&&typeof r=="object"&&be(r,i,o)}}function Ae(e,n){if(n.length===0)return null;let[o,...t]=n,r=Object.entries(e).find(([a])=>a.toLowerCase()===o);if(!r)return null;let[i,s]=r;if(t.length===0)return ke(s)?[i]:null;if(s!==null&&typeof s=="object"&&!ke(s)){let a=Ae(s,t);if(a!==null)return[i,...a]}return null}function nn(e,n){let o=[];o.push(`${e}({`),o.push(" webhookHooks: {");for(let i=0;i<n.length;i++){let s=" ".repeat(i+2);o.push(`${s}${n[i]}: {`)}let t=" ".repeat(n.length+2),r=t+" ";o.push(`${t}before(ctx, args) {`),o.push(`${r}return { ctx, args };`),o.push(`${t}},`),o.push(`${t}after(ctx, response) {`),o.push(`${t}},`);for(let i=n.length-1;i>=0;i--){let s=" ".repeat(i+2);o.push(`${s}},`)}return o.push(" },"),o.push("})"),o.join(`
14
- `)}var In=new Set(ze);function W(e,n){let o=n?.type??"api",t=n?.plugin;if(t!==void 0){let i=e.find(a=>a.id===t);if(!i)return In.has(t)?`This plugin (${t}) is not configured. Please add it to the Corsair instance to see its associated methods.`:W(e);if(o==="webhooks"){if(!i.webhooks)return[];let a=[];return be(i.webhooks,[],a),a.map(d=>`${i.id}.webhooks.${d}`)}if(o==="db"){let a=i.schema?.entities;return a?Object.keys(a).map(d=>`${i.id}.db.${d}.search`):[]}if(!i.endpoints)return[];let s=[];return me(i.endpoints,[],s),s.map(a=>`${i.id}.api.${a}`)}let r={};if(o==="webhooks")for(let i of e){if(!i.webhooks)continue;let s=[];be(i.webhooks,[],s),r[i.id]=s.map(a=>`${i.id}.webhooks.${a}`)}else if(o==="db")for(let i of e){let s=i.schema?.entities;s&&(r[i.id]=Object.keys(s).map(a=>`${i.id}.db.${a}.search`))}else for(let i of e){if(!i.endpoints)continue;let s=[];me(i.endpoints,[],s),r[i.id]=s.map(a=>`${i.id}.api.${a}`)}return r}function Z(e,n){if(e){for(let[o,t]of Object.entries(e))if(o.toLowerCase()===n)return t}}function Dn(e,n){let o=e.toLowerCase(),t=n.toLowerCase();if(!o.startsWith(`${t}.`)){let i=o.slice(n.length+1),s=i.startsWith(".")?i.slice(1):i;return s.startsWith("api.")&&(s=s.slice(4)),{shortPath:s,lookupKey:s}}let r=e.slice(n.length+1);return r.toLowerCase().startsWith("api.")&&(r=r.slice(4)),{shortPath:r,lookupKey:r.toLowerCase()}}function he(e,n){return typeof e=="string"?e:Array.isArray(e)?`${n}:
15
- ${e.join(", ")}`:`${n}:
16
- `+Object.entries(e).map(([o,t])=>` ${o}: ${t.join(", ")}`).join(`
17
- `)}function Ct(e,n){let o=n.toLowerCase(),t=o.indexOf(".");if(t!==-1){let r=o.slice(0,t),i=o.slice(t+1),s=e.find(a=>a.id===r);if(s){if(i.startsWith("db.")){let c=i.slice(3),l=c.lastIndexOf(".");if(l!==-1){let f=c.slice(0,l),g=c.slice(l+1),u=s.schema?.entities;if(g==="search"&&u){let h=en(u,f);if(h){let[b,k]=h,w=Te(k),A=[`Search ${r} ${b} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Ce.join(", ")}]`];for(let[y,m]of Object.entries(w))A.push(` ${y}?: ${m.type} [${m.operators.join(", ")}]`);return A.push("}"),A.join(`
18
- `)}}}return he(W(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let c=i.slice(9);if(s.webhooks){let l=Ae(s.webhooks,c.split("."));if(l!==null){let f=l.join("."),g=Z(s.webhookSchemas,f.toLowerCase()),u=g?.response?R(g.response):null,h=[];return g?.description&&h.push(g.description),g?.payload&&h.push(`payload ${se(G(g.payload))}`),u&&h.push(`response: ${u}`),h.push(`usage:
19
- ${nn(r,l)}`),h.join(`
20
-
21
- `)}}return he(W(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=Z(s.endpointMeta,a),p=Z(s.endpointSchemas,a);if(d||p){let c=[],l=[d?.riskLevel?`[${d.riskLevel}]`:"",d?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),f=[d?.description,l].filter(Boolean).join(" ");return f&&c.push(f),p?.input&&c.push(`input ${se(G(p.input))}`),p?.output&&c.push(`output ${se(G(p.output))}`),c.join(`
22
-
23
- `)}}}return he(W(e),"Path not found. Available operations")}function Je(e){let n=e;for(;;){let o=v(n),t=_(o);if(we(t)){let r=D(o);if(!r)return n;n=r;continue}return n}}function G(e){if(e===void 0)return{kind:"inline",type:"unknown"};let n=Je(e),o=v(n);if(_(o)==="ZodObject"){let r=ae(n,o),i=[];for(let[s,a]of Object.entries(r)){let d=v(a),p=_(d),c=p==="ZodOptional"||p==="ZodNullable",l=Je(a),f=xn(a);i.push({key:s,optional:c,type:R(l),...f!==void 0?{description:f}:{}})}return{kind:"object",fields:i}}return{kind:"inline",type:R(n)}}function se(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 o=Ge.repeat(n+1),t=Ge.repeat(n);return`{
24
- ${e.fields.map(i=>{let s=i.optional?`${i.key}?`:i.key,a=i.description?` // ${i.description}`:"";return`${o}${s}: ${i.type}${a}`}).join(`
25
- `)}
26
- ${t}}`}return"unknown"}function vn(e,n){let o=W(e,{plugin:n,type:"api"});if(typeof o=="string")return{ok:!1,error:o};if(!Array.isArray(o))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let t=e.find(c=>c.id===n);if(!t)return{ok:!1,error:`Plugin "${n}" is not configured on this instance.`};let r=[];for(let c of o){let{shortPath:l,lookupKey:f}=Dn(c,n),g=Z(t.endpointMeta,f),u=Z(t.endpointSchemas,f);!g&&!u||r.push({path:c,shortPath:l,description:g?.description,riskLevel:g?.riskLevel,irreversible:g?.irreversible,input:G(u?.input),output:G(u?.output)})}r.sort((c,l)=>c.path.localeCompare(l.path));let i=[],s=W(e,{plugin:n,type:"webhooks"});if(Array.isArray(s)&&t.webhooks)for(let c of s){let f=c.toLowerCase().slice(n.length+1),g=f.startsWith(".")?f.slice(1):f;if(!g.startsWith("webhooks."))continue;let u=g.slice(9),h=Ae(t.webhooks,u.split("."));if(h===null)continue;let b=h.join("."),k=Z(t.webhookSchemas,b.toLowerCase()),w=k?.response?R(k.response):void 0;i.push({path:c,description:k?.description,payload:G(k?.payload),responseType:w,usageExample:nn(n,h)})}i.sort((c,l)=>c.path.localeCompare(l.path));let a=[],d=W(e,{plugin:n,type:"db"}),p=t.schema?.entities;if(Array.isArray(d)&&p)for(let c of d){let f=c.toLowerCase().slice(n.length+1),g=f.startsWith(".")?f.slice(1):f;if(!g.startsWith("db."))continue;let u=g.slice(3),h=u.lastIndexOf(".");if(h===-1)continue;let b=u.slice(0,h);if(u.slice(h+1)!=="search")continue;let w=en(p,b);if(!w)continue;let[A,y]=w,m=Te(y),T=Object.entries(m).map(([P,I])=>({field:P,type:I.type,operators:I.operators}));a.push({path:c,entityName:A,filters:[{field:"entity_id",type:"string",operators:Ce},...T]})}return a.sort((c,l)=>c.path.localeCompare(l.path)),{ok:!0,data:{pluginId:n,api:r,webhooks:i,db:a}}}var ee=Symbol.for("corsair:internal");function Rt(e){let n=e.database?xe(e.database):void 0,o=n&&e.kek?je(e.plugins,n,e.kek):re(!!n,!!e.kek),t={plugins:e.plugins,database:n,kek:e.kek,multiTenancy:!!e.multiTenancy,approval:e.approval,connect:e.connect},r=Ne(n);if(e.multiTenancy)return Object.assign({withTenant:s=>{if(!s)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");let a=ye(e.plugins,{database:n,tenantId:s,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval,connectConfig:e.connect});return Object.assign(a,{[ee]:t})},keys:o,permissions:r},{[ee]:t});let i=ye(e.plugins,{database:n,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval,connectConfig:e.connect});return Object.assign({},i,{keys:o,permissions:r,[ee]:t})}export{N as a,B as b,j as c,M as d,ue as e,le as f,H as g,L as h,Y as i,Q as j,q as k,ie as l,_e as m,Se as n,Oe as o,an as p,Fe as q,$e as r,Le as s,bn as t,He as u,An as v,ze as w,wt as x,W as y,Ct as z,se as A,vn as B,ee as C,Rt as D};