corsair 0.1.48 → 0.1.50

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 pe,b as Q}from"./chunk-2PB34FTK.js";import{a as ge}from"./chunk-73HYPGOI.js";import{createCipheriv as fe,createDecipheriv as ye,randomBytes as H,scrypt as Ke}from"crypto";import{promisify as Me}from"util";var he=Me(Ke),U="aes-256-gcm",me=12,q=16,$e=16,B=32;function O(){return H(B).toString("base64")}async function K(e,t){let n=H($e),r=await he(t,n,B),o=H(me),i=fe(U,r,o,{authTagLength:q}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[n.toString("base64"),o.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function D(e,t){let[n,r,o,i]=e.split(":");if(!n||!r||!o||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(n,"base64"),a=Buffer.from(r,"base64"),d=Buffer.from(o,"base64"),g=Buffer.from(i,"base64"),f=await he(t,s,B),c=ye(U,f,a,{authTagLength:q});return c.setAuthTag(d),Buffer.concat([c.update(g),c.final()]).toString("utf8")}function X(e,t){let n=Buffer.from(t,"base64"),r=H(me),o=fe(U,n,r,{authTagLength:q}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function ee(e,t){let[n,r,o]=e.split(":");if(!n||!r||!o)throw new Error("Invalid encrypted data format");let i=Buffer.from(t,"base64"),s=Buffer.from(n,"base64"),a=Buffer.from(r,"base64"),d=Buffer.from(o,"base64"),g=ye(U,i,s,{authTagLength:q});return g.setAuthTag(a),Buffer.concat([g.update(d),g.final()]).toString("utf8")}function F(e,t){let n={};for(let[r,o]of Object.entries(e))n[r]=X(o,t);return n}function M(e,t){let n={};for(let[r,o]of Object.entries(e))n[r]=ee(o,t);return n}function S(e,t,n){let r=M(e,t);return F(r,n)}function z(e,t){let n=[];e||n.push("database"),t||n.push("kek");let r={};return new Proxy(r,{get(o,i){let s=n.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${n.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 ${B}`)}})}var Z={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 ke(e,t,n){let r={};for(let o of n)r[`get_${o}`]=async()=>(await e())[o]??null,r[`set_${o}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await t({[o]:s})};return r}var ne=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function G(e){let{authType:t,integrationName:n,kek:r,database:o,extraIntegrationFields:i=[]}=e,s=[...Z[t].integration,...i],a=null,d={kek:r,integrationName:n,getIntegration:async()=>{if(a)return a;let u=await o.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!u)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);return a={id:u.id,config:ne(u.config),dek:u.dek??null},a},updateIntegration:async u=>{let p=await d.getIntegration();await o.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","=",p.id).execute(),a=null}},g=null,f=async()=>{if(g)return g;let u=await d.getIntegration();if(!u.dek)throw new Error(`No DEK found for integration "${n}". Initialize the integration first.`);return g=await D(u.dek,r),g},c=async()=>{let u=await d.getIntegration(),p=await f(),m=u.config;return!m||Object.keys(m).length===0?{}:M(m,p)};return{get_dek:f,issue_new_dek:async()=>{let u=await d.getIntegration(),p=O(),m={};if(u.dek){let x=await D(u.dek,r),b=u.config;b&&Object.keys(b).length>0&&(m=S(b,x,p))}let C=await K(p,r);return await d.updateIntegration({config:m,dek:C}),g=p,p},...ke(c,async u=>{let p=await f(),m;try{m=await c()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${n}", starting fresh:`,b),m={}}let C={...m};for(let[b,l]of Object.entries(u))l===null?delete C[b]:C[b]=l;let x=F(C,p);await d.updateIntegration({config:x})},s)}}function V(e){let{authType:t,integrationName:n,tenantId:r,kek:o,database:i,extraAccountFields:s=[]}=e,a=[...Z[t].account,...s],d=null,g=null,f=async()=>{if(g)return g;let l=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!l)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);return g={id:l.id,config:ne(l.config),dek:l.dek??null},g},c={kek:o,integrationName:n,tenantId:r,getIntegration:f,getAccount:async()=>{if(d)return d;let l=await f(),k=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",l.id).executeTakeFirst();if(!k)throw new Error(`Account not found for tenant "${r}" and integration "${n}". Make sure to create the account first.`);return d={id:k.id,config:ne(k.config),dek:k.dek??null},d},updateAccount:async l=>{let k=await c.getAccount();await i.db.updateTable("corsair_accounts").set({...l.config!==void 0?{config:l.config}:{},...l.dek!==void 0?{dek:l.dek}:{},updated_at:new Date}).where("id","=",k.id).execute(),d=null}},y=null,h=null,u=async()=>{if(y)return y;let l=await c.getAccount();if(!l.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${n}"). Initialize the account first.`);return y=await D(l.dek,o),y},p=async()=>{if(h)return h;let l=await c.getIntegration();if(!l.dek)throw new Error(`No DEK found for integration "${n}". Initialize the integration first.`);return h=await D(l.dek,o),h},m=async()=>{let l=await c.getAccount(),k=await u(),w=l.config;return!w||Object.keys(w).length===0?{}:M(w,k)},C=async()=>{let l=await c.getIntegration(),k=await p(),w=l.config;return!w||Object.keys(w).length===0?{}:M(w,k)},b={get_dek:u,issue_new_dek:async()=>{let l=await c.getAccount(),k=O(),w={};if(l.dek){let A=await D(l.dek,o),P=l.config;P&&Object.keys(P).length>0&&(w=S(P,A,k))}let I=await K(k,o);return await c.updateAccount({config:w,dek:I}),y=k,k},...ke(m,async l=>{let k=await u(),w;try{w=await m()}catch(P){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${n}"), starting fresh:`,P),w={}}let I={...w};for(let[P,T]of Object.entries(l))T===null?delete I[P]:I[P]=T;let A=F(I,k);await c.updateAccount({config:A})},a)};return t==="oauth_2"&&(b.get_integration_credentials=async()=>{let l=await C();return{client_id:l.client_id||null,client_secret:l.client_secret||null,redirect_url:l.redirect_url??null}}),b}async function be(e,t,n){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!r)throw new Error(`Integration "${t}" not found.`);let o=O(),i=await K(o,n);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function we(e,t,n,r){let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!o)throw new Error(`Integration "${t}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",n).where("integration_id","=",o.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${n}" and integration "${t}".`);let s=O(),a=await K(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var Fe=async(e,t)=>(console.error(`[corsair:${t.pluginId}:${t.operation}]`,{error:e.message,input:t.input}),{maxRetries:0});async function Ce(e,t,n,r,o){let i={pluginId:t,operation:n,input:r,originalError:e},s=Object.keys(o).find(g=>o[g]?.match(e,i));return await(o[s||"DEFAULT"]?.handler||Fe)(e,i)}import{randomBytes as Ne}from"crypto";import{v4 as Be}from"uuid";var Se={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 Ze(e,t,n){return n!==void 0?n:Se[t][e]}function Te(e){let t=/(\d+)(d|h|m|s)/g,n=0,r;for(;(r=t.exec(e))!==null;){let o=parseInt(r[1],10);switch(r[2]){case"d":n+=o*864e5;break;case"h":n+=o*36e5;break;case"m":n+=o*6e4;break;case"s":n+=o*1e3;break}}return n>0?n:600*1e3}function Pe(e){return{async find_by_permission_id(t){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("id","=",t).executeTakeFirst()},async find_by_token(t){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("token","=",t).executeTakeFirst()},async set_executing(t){e&&await e.db.updateTable("corsair_permissions").set({status:"executing",updated_at:new Date}).where("id","=",t).execute()},async set_completed(t){e&&await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",t).execute()}}}async function xe(e){let t=Ze(e.riskLevel,e.mode,e.override);if(t==="allow")return{result:"allow"};let n=e.meta?.irreversible?" (irreversible)":"",r=e.meta?.description?`${e.meta.description}${n}`:`${e.pluginId}.${e.endpointPath}${n}`;if(t==="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"};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 y=e.db,h=a.id;return{result:"allow",onComplete:async()=>{await y.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: ${r}`,`
7
+ Permission ID: ${a.id}`,`
8
+ Use the token to approve or deny this request.`),{result:"blocked"})}let d=Be(),g=Ne(32).toString("hex"),f=e.timeoutMs??600*1e3,c=new Date(Date.now()+f).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:d,created_at:new Date,updated_at:new Date,token:g,plugin:e.pluginId,endpoint:e.endpointPath,args:o,tenant_id:s,status:"pending",expires_at:c}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
9
+ Action: ${r}`,`
10
+ Permission ID: ${d}`,`
11
+ Permission token: ${g}`,`
12
+ Expires at: ${c}`,`
13
+ Use the token to approve or deny this request.`),{result:"blocked"}}function je(e){return typeof e=="function"}function te({endpoints:e,hooks:t,ctx:n,tree:r,pluginId:o,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:d,endpointMeta:g,database:f,approvalConfig:c,tenantId:y}){for(let[h,u]of Object.entries(e)){let p=t?.[h];if(je(u)){let m=p,C=[...s,h].join("."),x=async(b={})=>{let l;if(d){let T=g?.[C],{result:v,onComplete:E}=await xe({pluginId:o,endpointPath:C,args:b,mode:d.mode,override:d.overrides?.[C],riskLevel:T?.riskLevel??"write",meta:T,db:f,timeoutMs:c?Te(c.timeout):void 0,tenantId:y});if(v==="blocked")return null;l=E}let k=async(T,v,E)=>{try{return await u(v,E)}catch(N){if(N instanceof Error){let $=await Ce(N,o,C,typeof E=="object"&&E!==null?E:{args:E},i);if(T<($.maxRetries||0)){let L=T+1;console.log(`Retrying (${L} / ${$.maxRetries})...`);let _;if($.headersRetryAfterMs)_=$.headersRetryAfterMs;else switch($.retryStrategy){case"exponential_backoff":_=Math.pow(2,L-1)*1e3;break;case"exponential_backoff_jitter":let Y=Math.pow(2,L-1)*1e3,Oe=(Math.random()-.5)*1e3;_=Math.max(0,Y+Oe);break;case"linear_1s":_=1e3;break;case"linear_2s":_=2e3;break;case"linear_3s":_=3e3;break;case"linear_4s":_=4e3;break;default:_=1e3;break}await new Promise(Y=>setTimeout(Y,_)),await k(L,v,E),console.log(`[corsair:${o}:${C}] Retry strategy:`,$)}}throw N}},w=a?await a(n,"endpoint"):void 0;if(!m?.before&&!m?.after){let T=await k(0,{...n,key:w},b);return await l?.(),T}let I={...n,key:w},A=m.before?await m.before(I,b):{ctx:I,args:b,continue:!0,passToAfter:void 0};if(A.continue===!1)return;let P=await k(0,A.ctx,A.args);return await m.after?.(A.ctx,P,A.passToAfter),await l?.(),P};r[h]=x}else if(u&&typeof u=="object"){let m={};te({endpoints:u,hooks:p,ctx:n,tree:m,pluginId:o,errorHandlers:i,currentPath:[...s,h],keyBuilder:a,permissionsConfig:d,endpointMeta:g,database:f,approvalConfig:c,tenantId:y}),r[h]=m}}}var Ae=["airtable","amplitude","asana","box","cal","calendly","discord","dropbox","exa","figma","fireflies","github","gmail","googlecalendar","googledrive","googlesheets","hackernews","hubspot","intercom","jira","linear","monday","notion","oura","pagerduty","posthog","resend","sentry","slack","spotify","stripe","tavily","teams","telegram","todoist","trello","twitter","twitterapiio","typeform","zoom"];var Ee=" ";function R(e){let t=e._def,n=t.typeName;switch(n){case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodNull":return"null";case"ZodUnknown":case"ZodAny":return"any";case"ZodLiteral":return String(t.value);case"ZodEnum":return t.values.map(r=>String(r)).join(" | ");case"ZodOptional":return R(t.innerType);case"ZodNullable":return`${R(t.innerType)} | null`;case"ZodArray":return`${R(t.type)}[]`;case"ZodRecord":return"{}";case"ZodObject":{let r=t.shape(),o=Object.entries(r);return o.length===0?"{}":`{ ${o.map(([s,a])=>{let d=a._def.typeName;return`${d==="ZodOptional"||d==="ZodNullable"?s+"?":s}: ${R(a)}`}).join(", ")} }`}case"ZodUnion":return t.options.map(R).join(" | ");case"ZodIntersection":return`${R(t.left)} & ${R(t.right)}`;case"ZodEffects":return R(t.schema);default:return(n??"unknown").replace("Zod","").toLowerCase()}}function j(e,t){let n=e._def,r=n.typeName;if(r==="ZodOptional"||r==="ZodEffects")return j(r==="ZodOptional"?n.innerType:n.schema,t);if(r!=="ZodObject")return R(e);let o=n.shape(),i=Object.entries(o);if(i.length===0)return"{}";let s=Ee.repeat(t+1),a=Ee.repeat(t),d=[];for(let[g,f]of i){let c=f._def,y=c.typeName,u=y==="ZodOptional"||y==="ZodNullable"?`${g}?`:g,p=y==="ZodOptional"||y==="ZodNullable"?c.innerType:f;p?._def?.typeName==="ZodObject"?d.push(`${s}${u}: ${j(p,t+1)}`):d.push(`${s}${u}: ${R(f)}`)}return`{
14
+ ${d.join(`
15
+ `)}
16
+ ${a}}`}var Re=["equals","contains","startsWith","endsWith","in"],We=["equals","gt","gte","lt","lte","in"],Le=["equals"],He=["equals","before","after","between"];function ie(e){let t=e._def;switch(t.typeName){case"ZodOptional":case"ZodNullable":case"ZodDefault":return ie(t.innerType);case"ZodEffects":return ie(t.schema);case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function se(e){let t=e._def,n=t.typeName;if(n==="ZodOptional"||n==="ZodNullable"||n==="ZodDefault")return se(t.innerType);if(n==="ZodEffects")return se(t.schema);if(n!=="ZodObject")return{};let r=t.shape(),o={};for(let[i,s]of Object.entries(r)){let a=ie(s);a==="string"?o[i]={type:"string",operators:Re}:a==="number"?o[i]={type:"number",operators:We}:a==="boolean"?o[i]={type:"boolean",operators:Le}:a==="date"&&(o[i]={type:"date",operators:He})}return o}function Ue(e,t){for(let[n,r]of Object.entries(e))if(n.toLowerCase()===t)return[n,r]}function ae(e,t,n){for(let[r,o]of Object.entries(e)){let i=[...t,r];typeof o=="function"?n.push(i.join(".")):o!==null&&typeof o=="object"&&ae(o,i,n)}}function ce(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function de(e,t,n){for(let[r,o]of Object.entries(e)){let i=[...t,r];ce(o)?n.push(i.join(".")):o!==null&&typeof o=="object"&&de(o,i,n)}}function Ie(e,t){if(t.length===0)return null;let[n,...r]=t,o=Object.entries(e).find(([a])=>a.toLowerCase()===n);if(!o)return null;let[i,s]=o;if(r.length===0)return ce(s)?[i]:null;if(s!==null&&typeof s=="object"&&!ce(s)){let a=Ie(s,r);if(a!==null)return[i,...a]}return null}function qe(e,t,n){let r=[];r.push(`${e}({`),r.push(" webhookHooks: {");for(let s=0;s<t.length;s++){let a=" ".repeat(s+2);r.push(`${a}${t[s]}: {`)}let o=" ".repeat(t.length+2),i=o+" ";r.push(`${o}before(ctx, args) {`),r.push(`${i}return { ctx, args };`),r.push(`${o}},`),r.push(`${o}after(ctx, response) {`),r.push(n!==null?`${i}// response.data: ${n}`:`${i}// response.data: unknown (register webhookSchemas to see the type)`),r.push(`${o}},`);for(let s=t.length-1;s>=0;s--){let a=" ".repeat(s+2);r.push(`${a}},`)}return r.push(" },"),r.push("})"),r.join(`
17
+ `)}var ze=new Set(Ae);function W(e,t){let n=t?.type??"api",r=t?.plugin;if(r!==void 0){let i=e.find(a=>a.id===r);if(!i)return ze.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:W(e);if(n==="webhooks"){if(!i.webhooks)return[];let a=[];return de(i.webhooks,[],a),a.map(d=>`${i.id}.webhooks.${d}`)}if(n==="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 ae(i.endpoints,[],s),s.map(a=>`${i.id}.api.${a}`)}let o={};if(n==="webhooks")for(let i of e){if(!i.webhooks)continue;let s=[];de(i.webhooks,[],s),o[i.id]=s.map(a=>`${i.id}.webhooks.${a}`)}else if(n==="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=[];ae(i.endpoints,[],s),o[i.id]=s.map(a=>`${i.id}.api.${a}`)}return o}function re(e,t){if(e){for(let[n,r]of Object.entries(e))if(n.toLowerCase()===t)return r}}function oe(e,t){return typeof e=="string"?e:Array.isArray(e)?`${t}:
18
+ ${e.join(", ")}`:`${t}:
19
+ `+Object.entries(e).map(([n,r])=>` ${n}: ${r.join(", ")}`).join(`
20
+ `)}function Ge(e,t){let n=t.toLowerCase(),r=n.indexOf(".");if(r!==-1){let o=n.slice(0,r),i=n.slice(r+1),s=e.find(a=>a.id===o);if(s){if(i.startsWith("db.")){let f=i.slice(3),c=f.lastIndexOf(".");if(c!==-1){let y=f.slice(0,c),h=f.slice(c+1),u=s.schema?.entities;if(h==="search"&&u){let p=Ue(u,y);if(p){let[m,C]=p,x=se(C),b=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${Re.join(", ")}]`];for(let[l,k]of Object.entries(x))b.push(` ${l}?: ${k.type} [${k.operators.join(", ")}]`);return b.push("}"),b.join(`
21
+ `)}}}return oe(W(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let f=i.slice(9);if(s.webhooks){let c=Ie(s.webhooks,f.split("."));if(c!==null){let y=c.join("."),h=re(s.webhookSchemas,y.toLowerCase()),u=h?.response?R(h.response):null,p=[];return h?.description&&p.push(h.description),h?.payload&&p.push(`payload ${j(h.payload,0)}`),u&&p.push(`response: ${u}`),p.push(`usage:
22
+ ${qe(o,c,u)}`),p.join(`
23
+
24
+ `)}}return oe(W(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=re(s.endpointMeta,a),g=re(s.endpointSchemas,a);if(d||g){let f=[],c=[d?.riskLevel?`[${d.riskLevel}]`:"",d?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),y=[d?.description,c].filter(Boolean).join(" ");return y&&f.push(y),g?.input&&f.push(`input ${j(g.input,0)}`),g?.output&&f.push(`output ${j(g.output,0)}`),f.join(`
25
+
26
+ `)}}}return oe(W(e),"Path not found. Available operations")}function J(e){return{list_operations(t){return W(e,t)},get_schema(t){return Ge(e,t)}}}function Ve(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function ue({webhooks:e,hooks:t,ctx:n,webhooksTree:r,keyBuilder:o}){for(let[i,s]of Object.entries(e)){let a=t?.[i];if(Ve(s)){let d=a,g=async f=>{let c=(h,u)=>s.handler(h,u),y=o?await o(n,"webhook"):void 0;return!d?.before&&!d?.after?c({...n,key:y},f):(async()=>{let h={...n,key:y},u=d.before?await d.before(h,f):{ctx:h,args:f,continue:!0,passToAfter:void 0};if(u.continue===!1)return;let p=await c(u.ctx,u.args);return p?.success===!0&&await d.after?.(u.ctx,p,u.passToAfter),p})()};r[i]={match:s.match,handler:g}}else if(s&&typeof s=="object"){let d={};ue({webhooks:s,hooks:a,ctx:n,webhooksTree:d,keyBuilder:o}),r[i]=d}}}function Je(e,t,n){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","=",t).executeTakeFirst();if(!o)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",n).where("integration_id","=",o.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${n}" and integration "${t}". Make sure to create the account first.`);return r=i.id,r}}function Ye(e,t,n,r,o){return e?Q(e.db,t,n,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 le(e,t){let{database:n,tenantId:r,kek:o,rootErrorHandlers:i,approvalConfig:s}=t,a={},d={};for(let c of e)a[c.id]={},d[c.id]={};for(let c of e){let y=c.schema,h=r??"default",u=Je(n,c.id,h);if(y?.entities){let T={};for(let[v,E]of Object.entries(y.entities)){let N=n?Q(n.db,u,v,y.version,E):Ye(void 0,u,v,y.version,E);T[v]=N}d[c.id].db=T,a[c.id].db=T}let p=c.options,m=c.authConfig,C;if(n&&o&&p?.authType){let T=m?.[p.authType]?.account??[];C=V({authType:p.authType,integrationName:c.id,tenantId:h,kek:o,database:n,extraAccountFields:T}),a[c.id].keys=C}let x={database:n,db:d[c.id]?.db??{},$getAccountId:u,...c.options?{options:c.options}:{},...C?{keys:C,authType:p?.authType}:{},...r?{tenantId:r}:{}},b=c.endpoints??{},l=c.hooks,k={...i,...c.errorHandlers},w={},I=c.options?.permissions;te({endpoints:b,hooks:l,ctx:x,tree:w,pluginId:c.id,errorHandlers:k,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:I,endpointMeta:c.endpointMeta,database:n,approvalConfig:s,tenantId:r}),Object.keys(w).length>0&&(a[c.id].api=w),x.endpoints=w;let A=c.webhooks??{},P=c.webhookHooks;if(Object.keys(A).length>0){let T={};ue({webhooks:A,hooks:P,ctx:x,webhooksTree:T,keyBuilder:c.keyBuilder}),a[c.id].webhooks=T,c.pluginWebhookMatcher&&(a[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher)}}let g=a,f=J(e);return{...g,...f}}function _e(e,t,n){let r={};for(let o of e){let i=o.options,s=o.authConfig;if(i?.authType){let a=s?.[i.authType]?.integration??[],d=G({authType:i.authType,integrationName:o.id,kek:n,database:t,extraIntegrationFields:a});r[o.id]=d}}return r}async function ve(e,t,n,r,o="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:t,event_type:n,payload:r,status:o}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function Qe(e,t,n,r="pending"){try{let o=await e.$getAccountId();return ve(e.database,o,t,n,r)}catch(o){return console.warn("Failed to log event:",o),null}}var De=Symbol.for("corsair:internal");function Zn(e){let t=e.database?ge(e.database):void 0,n=t&&e.kek?_e(e.plugins,t,e.kek):z(!!t,!!e.kek),r={plugins:e.plugins,database:t,kek:e.kek,multiTenancy:!!e.multiTenancy,approval:e.approval},o=Pe(t);if(e.multiTenancy)return Object.assign({withTenant:s=>{if(!s)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");return le(e.plugins,{database:t,tenantId:s,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval})},keys:n,permissions:o,...J(e.plugins)},{[De]:r});let i=le(e.plugins,{database:t,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval});return Object.assign({},i,{keys:n,permissions:o,[De]:r})}export{O as a,K as b,D as c,X as d,ee as e,F as f,M as g,S as h,Z as i,G as j,V as k,be as l,we as m,Ae as n,ve as o,Qe as p,De as q,Zn as r};
@@ -1,4 +1,4 @@
1
- import{q as k,r as w}from"./chunk-5XRKMGCV.js";import{a as m}from"./chunk-7IH5DNUL.js";import{ZodBoolean as h,ZodDate as _,ZodEffects as $,ZodEnum as P,ZodNullable as K,ZodNumber as M,ZodObject as T,ZodOptional as v,ZodRecord as A,ZodString as j}from"zod";var b={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},pullRequests:{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 Y(e,c){let l=[],r=t=>{l.push(t),console.log(t)},o=t=>{l.push(t),console.warn(t)},g=c?.caller??"script",s=e[k];if(!s)throw new Error("setupCorsair: invalid corsair instance");if(s.multiTenancy)throw new Error("setupCorsair: multi-tenancy instances are not supported. Create your corsair instance without multiTenancy: true.");if(!s.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let u=s.database.db,n=w({plugins:s.plugins,database:s.database.db,kek:s.kek});await D(u,o),await E(u,n,s.plugins,r),c?.credentials&&Object.keys(c.credentials).length>0&&await I(n,c.credentials,r,o);let a=await Z(n,s.plugins,r,g);return c?.backfill&&(r("[corsair:setup] Starting backfill..."),await L(n,s.plugins,a,r,o),r("[corsair:setup] Backfill complete.")),l.join(`
1
+ import{q as k,r as w}from"./chunk-642IYEGX.js";import{a as m}from"./chunk-7IH5DNUL.js";import{ZodBoolean as h,ZodDate as _,ZodEffects as $,ZodEnum as P,ZodNullable as K,ZodNumber as M,ZodObject as T,ZodOptional as v,ZodRecord as A,ZodString as j}from"zod";var b={slack:{channels:{list:{}},users:{list:{}}},linear:{projects:{list:{}},issues:{list:{}},users:{list:{}}},github:{issues:{list:{}},pullRequests:{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 Y(e,c){let l=[],r=t=>{l.push(t),console.log(t)},o=t=>{l.push(t),console.warn(t)},g=c?.caller??"script",s=e[k];if(!s)throw new Error("setupCorsair: invalid corsair instance");if(s.multiTenancy)throw new Error("setupCorsair: multi-tenancy instances are not supported. Create your corsair instance without multiTenancy: true.");if(!s.database)throw new Error("setupCorsair: a database must be configured on the corsair instance");let u=s.database.db,n=w({plugins:s.plugins,database:s.database.db,kek:s.kek});await D(u,o),await E(u,n,s.plugins,r),c?.credentials&&Object.keys(c.credentials).length>0&&await I(n,c.credentials,r,o);let a=await Z(n,s.plugins,r,g);return c?.backfill&&(r("[corsair:setup] Starting backfill..."),await L(n,s.plugins,a,r,o),r("[corsair:setup] Backfill complete.")),l.join(`
2
2
  `)}var O={...m};function p(e){if(e instanceof T){let c={};for(let[l,r]of Object.entries(e.shape))c[l]=p(r);return c}return e instanceof $?p(e.innerType()):e instanceof K?`${p(e.unwrap())} | null`:e instanceof v?`${p(e.unwrap())} | undefined`:e instanceof P?e.options.join(" | "):e instanceof j?"string":e instanceof M?"number":e instanceof h?"boolean":e instanceof _?"date":e instanceof A?"jsonb":"unknown"}async function D(e,c){let l=await e.introspection.getTables(),r=new Set(l.map(o=>o.name));for(let[o,g]of Object.entries(O))r.has(o)||c(`[corsair:setup] Table "${o}" does not exist. Run your database migrations before calling setupCorsair.
3
3
  Schema: ${JSON.stringify(p(g),null,2)}`)}var C="default";async function E(e,c,l,r){let o=new Date,g=c.keys,s=c;for(let u of l){let n=u.id,a=await e.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!a){let f=crypto.randomUUID();await e.insertInto("corsair_integrations").values({id:f,name:n,config:{},created_at:o,updated_at:o}).execute(),a=await e.selectFrom("corsair_integrations").selectAll().where("id","=",f).executeTakeFirst(),r(`[corsair:setup] Created integration: ${n}`)}let t=g[n];if(a&&!a.dek&&t&&(await t.issue_new_dek(),r(`[corsair:setup] Issued integration DEK: ${n}`)),!a)continue;let i=await e.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",C).where("integration_id","=",a.id).executeTakeFirst();if(!i){let f=crypto.randomUUID();await e.insertInto("corsair_accounts").values({id:f,tenant_id:C,integration_id:a.id,config:{},created_at:o,updated_at:o}).execute(),i=await e.selectFrom("corsair_accounts").selectAll().where("id","=",f).executeTakeFirst(),r(`[corsair:setup] Created account: ${n}`)}let d=s[n]?.keys;i&&!i.dek&&d&&(await d.issue_new_dek(),r(`[corsair:setup] Issued account DEK: ${n}`))}}async function I(e,c,l,r){let o=e.keys,g=e;for(let[s,u]of Object.entries(c)){let n=o[s],a=g[s]?.keys;for(let[t,i]of Object.entries(u)){let d=`set_${t}`;n&&typeof n[d]=="function"?(await n[d](i),l(`[corsair:setup] Set integration credential: ${s}.${t}`)):a&&typeof a[d]=="function"?(await a[d](i),l(`[corsair:setup] Set account credential: ${s}.${t}`)):r(`[corsair:setup] No setter found for '${s}.${t}' \u2014 skipping.`)}}}var S=new Set(["webhook_signature","expires_at","scope","redirect_url"]);async function x(e,c,l,r,o,g){let s=[],u=[];for(let a of Object.keys(l)){if(!a.startsWith("set_"))continue;let t=a.slice(4);if(S.has(t))continue;let i=l[`get_${t}`];if(!i)continue;let d=null;try{d=await i()}catch{}d||s.push(t)}for(let a of Object.keys(r)){if(!a.startsWith("set_"))continue;let t=a.slice(4);if(S.has(t))continue;let i=r[`get_${t}`];if(!i)continue;let d=null;try{d=await i()}catch{}d||u.push(t)}let n=s.length===0&&u.length===0;if(n)o(`[corsair:setup] '${e}' (${c}) is configured \u2713`);else{let a=[...s,...u];if(g==="cli"){let t=a.map(i=>`${i}=VALUE`).join(" ");o(`[corsair:setup] '${e}' (${c}) needs credentials. Run:
4
4
  corsair setup --${e} ${t}`)}else{let t=[`[corsair:setup] '${e}' (${c}) needs credentials. Call:`];for(let i of s)t.push(` await corsair.keys.${e}.set_${i}(value)`);for(let i of u)t.push(` await corsair.${e}.keys.set_${i}(value)`);o(t.join(`
package/dist/core.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-mtAgyrsC.js';
2
- import { A as AuthTypes, f as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './index-CNwyqNCs.js';
3
- export { g as AccountFieldNames, m as AllProviders, k as BASE_AUTH_FIELDS, h as BaseAuthFieldConfig, i as BaseKeyManager, e as BaseProviders, K as BeforeHookResult, o as BindEndpoints, a5 as BindWebhooks, a3 as Bivariant, p as BoundEndpointFn, q as BoundEndpointTree, a6 as BoundWebhook, B as BoundWebhookTree, l as CorsairClient, r as CorsairContext, s as CorsairEndpoint, u as CorsairErrorHandler, F as CorsairInspectMethods, a as CorsairIntegration, L as CorsairKeyBuilder, M as CorsairKeyBuilderBase, d as CorsairPermissionsNamespace, C as CorsairPlugin, Q as CorsairPluginContext, c as CorsairSingleTenantClient, b as CorsairTenantWrapper, a7 as CorsairWebhook, a8 as CorsairWebhookHandler, a9 as CorsairWebhookMatcher, S as EndpointHooks, T as EndpointMetaEntry, E as EndpointPathsOf, U as EndpointRiskLevel, G as EndpointSchemaResult, t as EndpointTree, H as EnforcePermissionOptions, J as EnforcePermissionResult, v as ErrorContext, w as ErrorHandler, x as ErrorHandlerAndMatchFunction, y as ErrorMatcher, j as IntegrationFieldNames, V as KeyBuilderContext, O as OAuth2IntegrationCredentials, N as OAuthConfig, X as PermissionMode, Y as PermissionPolicy, n as PickAuth, P as PluginAuthConfig, Z as PluginEndpointMeta, _ as PluginPermissionsConfig, R as RawWebhookRequest, $ as RequiredPluginEndpointMeta, a0 as RequiredPluginEndpointSchemas, a1 as RequiredPluginWebhookSchemas, z as RetryStrategies, D as RetryStrategy, a4 as UnionToIntersection, a2 as WebhookHooks, aa as WebhookPathsOf, ab as WebhookRequest, W as WebhookResponse, ac as WebhookTree } from './index-CNwyqNCs.js';
1
+ export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-DpPKj1ZX.js';
2
+ import { A as AuthTypes, f as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './index-D_Ah5Tz6.js';
3
+ export { g as AccountFieldNames, m as AllProviders, k as BASE_AUTH_FIELDS, h as BaseAuthFieldConfig, i as BaseKeyManager, e as BaseProviders, K as BeforeHookResult, o as BindEndpoints, a5 as BindWebhooks, a3 as Bivariant, p as BoundEndpointFn, q as BoundEndpointTree, a6 as BoundWebhook, B as BoundWebhookTree, l as CorsairClient, r as CorsairContext, s as CorsairEndpoint, u as CorsairErrorHandler, F as CorsairInspectMethods, a as CorsairIntegration, L as CorsairKeyBuilder, M as CorsairKeyBuilderBase, d as CorsairPermissionsNamespace, C as CorsairPlugin, Q as CorsairPluginContext, c as CorsairSingleTenantClient, b as CorsairTenantWrapper, a7 as CorsairWebhook, a8 as CorsairWebhookHandler, a9 as CorsairWebhookMatcher, S as EndpointHooks, T as EndpointMetaEntry, E as EndpointPathsOf, U as EndpointRiskLevel, G as EndpointSchemaResult, t as EndpointTree, H as EnforcePermissionOptions, J as EnforcePermissionResult, v as ErrorContext, w as ErrorHandler, x as ErrorHandlerAndMatchFunction, y as ErrorMatcher, j as IntegrationFieldNames, V as KeyBuilderContext, O as OAuth2IntegrationCredentials, N as OAuthConfig, X as PermissionMode, Y as PermissionPolicy, n as PickAuth, P as PluginAuthConfig, Z as PluginEndpointMeta, _ as PluginPermissionsConfig, R as RawWebhookRequest, $ as RequiredPluginEndpointMeta, a0 as RequiredPluginEndpointSchemas, a1 as RequiredPluginWebhookSchemas, z as RetryStrategies, D as RetryStrategy, a4 as UnionToIntersection, a2 as WebhookHooks, aa as WebhookPathsOf, ab as WebhookRequest, W as WebhookResponse, ac as WebhookTree } from './index-D_Ah5Tz6.js';
4
4
  import { CorsairDatabase } from './db.js';
5
5
  import 'zod';
6
6
  import './orm.js';
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- import{a,b,c,d,e,f,g,h,i,j,k,l,m,o as n,p as o,q as p,r as q}from"./chunk-5XRKMGCV.js";import"./chunk-2PB34FTK.js";import"./chunk-73HYPGOI.js";export{i as BASE_AUTH_FIELDS,p as CORSAIR_INTERNAL,k as createAccountKeyManager,q as createCorsair,j as createIntegrationKeyManager,g as decryptConfig,c as decryptDEK,e as decryptWithDEK,f as encryptConfig,b as encryptDEK,d as encryptWithDEK,a as generateDEK,m as initializeAccountDEK,l as initializeIntegrationDEK,n as logEvent,o as logEventFromContext,h as reEncryptConfig};
1
+ import{a,b,c,d,e,f,g,h,i,j,k,l,m,o as n,p as o,q as p,r as q}from"./chunk-642IYEGX.js";import"./chunk-2PB34FTK.js";import"./chunk-73HYPGOI.js";export{i as BASE_AUTH_FIELDS,p as CORSAIR_INTERNAL,k as createAccountKeyManager,q as createCorsair,j as createIntegrationKeyManager,g as decryptConfig,c as decryptDEK,e as decryptWithDEK,f as encryptConfig,b as encryptDEK,d as encryptWithDEK,a as generateDEK,m as initializeAccountDEK,l as initializeIntegrationDEK,n as logEvent,o as logEventFromContext,h as reEncryptConfig};
@@ -917,71 +917,15 @@ type CorsairIntegration<Plugins extends readonly CorsairPlugin[]> = {
917
917
  };
918
918
  };
919
919
 
920
- type DbFieldType = 'string' | 'number' | 'boolean' | 'date';
920
+ /** @deprecated get_schema now returns a plain string. This type is kept for backwards compatibility. */
921
921
  type EndpointSchemaResult = {
922
- /** Human-readable description of what this endpoint does. */
923
922
  description?: string;
924
- /** Risk classification: 'read' | 'write' | 'destructive' */
925
923
  riskLevel?: 'read' | 'write' | 'destructive';
926
- /** Whether this action cannot be undone. */
927
924
  irreversible?: boolean;
928
- /** JSON Schema representation of the input arguments object. */
929
925
  input?: unknown;
930
- /** JSON Schema representation of the response object. */
931
926
  output?: unknown;
932
- /**
933
- * Present when the requested method was not found.
934
- * Lists all available full-form paths so the caller can pick a valid one.
935
- */
936
927
  availableMethods?: Record<string, string[]>;
937
928
  };
938
- type WebhookSchemaResult = {
939
- /** Human-readable description of what triggers this webhook. */
940
- description?: string;
941
- /** JSON Schema for the webhook payload — the type of `request.payload` in the before hook. */
942
- payload?: unknown;
943
- /** JSON Schema for the webhook response data — the type of `response.data` in the after hook. */
944
- response?: unknown;
945
- /**
946
- * Ready-to-copy code example showing exactly how to configure this webhook,
947
- * including response.data type as an inline comment.
948
- */
949
- usage?: string;
950
- /**
951
- * Present when the requested webhook path was not found.
952
- * Lists all available webhook dot-paths per plugin so the caller can self-correct.
953
- */
954
- availableWebhooks?: Record<string, string[]>;
955
- };
956
- type DbSearchSchemaResult = {
957
- /**
958
- * What this entity type represents and how to search it.
959
- * Pass `limit` and `offset` as numbers for pagination.
960
- */
961
- description: string;
962
- /**
963
- * Filterable fields for the search() call.
964
- * All active filters are AND-combined. Omit a field to skip filtering on it.
965
- *
966
- * Each operator shorthand: passing a raw value (string/number/boolean/Date) is
967
- * equivalent to `{ equals: value }`.
968
- */
969
- filters: {
970
- /** Filter by the entity's external platform ID (e.g. a Slack channel ID). */
971
- entity_id: {
972
- type: 'string';
973
- operators: string[];
974
- };
975
- /**
976
- * Filter by fields inside the entity's data payload.
977
- * Only flat primitive fields are listed — nested objects are not filterable.
978
- */
979
- data: Record<string, {
980
- type: DbFieldType;
981
- operators: string[];
982
- }>;
983
- };
984
- };
985
929
  type ListOperationsOptions = {
986
930
  /**
987
931
  * Filter to a specific plugin by its ID (e.g. 'slack', 'github').
@@ -1033,29 +977,23 @@ type CorsairInspectMethods = {
1033
977
  */
1034
978
  list_operations(options?: ListOperationsOptions): Record<string, string[]> | string[] | string;
1035
979
  /**
1036
- * Returns schema and metadata for a specific API endpoint, webhook, or database entity search.
980
+ * Returns a plain-text TypeScript-style type declaration for a specific operation path.
1037
981
  * The path format determines which kind of schema is returned:
1038
- * - API path (`plugin.api.group.method`) → `EndpointSchemaResult`
1039
- * - Webhook path (`plugin.webhooks.group.event`) → `WebhookSchemaResult`
1040
- * - DB path (`plugin.db.entityType.search`) → `DbSearchSchemaResult`
982
+ * - API path (`plugin.api.group.method`) → description, risk level, input/output types
983
+ * - Webhook path (`plugin.webhooks.group.event`) → description, payload/response types, usage snippet
984
+ * - DB path (`plugin.db.entityType.search`) → description, filterable fields with operators
1041
985
  *
1042
986
  * Casing is ignored — the path is lowercased before lookup.
1043
- * If the path is not found, returns an object with available paths for self-correction.
987
+ * If the path is not found, returns a list of available paths for self-correction.
1044
988
  *
1045
989
  * @example
1046
- * corsair.get_schema('slack.api.channels.list')
1047
- * // { description: '...', riskLevel: 'read', input: { type: 'object', ... }, output: { ... } }
1048
- *
1049
- * corsair.get_schema('slack.webhooks.messages.message')
1050
- * // { description: '...', usage: '...', payload: { ... }, response: { ... } }
1051
- *
1052
- * corsair.get_schema('slack.db.messages.search')
1053
- * // { description: '...', filters: { entity_id: { ... }, data: { text: { type: 'string', operators: [...] }, ... } } }
990
+ * corsair.get_schema('slack.api.messages.post')
991
+ * // "Post a message to a channel [write]\n\ninput {\n channel: string\n text?: string\n ..."
1054
992
  *
1055
993
  * corsair.get_schema('slack.api.invalid')
1056
- * // { availableMethods: { slack: ['slack.api.channels.list', ...], ... } }
994
+ * // "Path not found. Available operations:\n slack: slack.api.channels.list, ..."
1057
995
  */
1058
- get_schema(path: string): EndpointSchemaResult | WebhookSchemaResult | DbSearchSchemaResult;
996
+ get_schema(path: string): string;
1059
997
  };
1060
998
 
1061
999
  /**
@@ -1,5 +1,5 @@
1
1
  import { CorsairDatabase } from './db.js';
2
- import { C as CorsairPlugin, a as CorsairIntegration, b as CorsairTenantWrapper, c as CorsairSingleTenantClient } from './index-CNwyqNCs.js';
2
+ import { C as CorsairPlugin, a as CorsairIntegration, b as CorsairTenantWrapper, c as CorsairSingleTenantClient } from './index-D_Ah5Tz6.js';
3
3
 
4
4
  declare const CORSAIR_INTERNAL: unique symbol;
5
5
  type CorsairInternalConfig = {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { c as createCorsair } from './index-mtAgyrsC.js';
2
- import { d as CorsairPermissionsNamespace, B as BoundWebhookTree, R as RawWebhookRequest, e as BaseProviders, W as WebhookResponse } from './index-CNwyqNCs.js';
1
+ export { c as createCorsair } from './index-DpPKj1ZX.js';
2
+ import { d as CorsairPermissionsNamespace, B as BoundWebhookTree, R as RawWebhookRequest, e as BaseProviders, W as WebhookResponse } from './index-D_Ah5Tz6.js';
3
3
  export { SetupCorsairOptions, setupCorsair } from './setup.js';
4
4
  import './db.js';
5
5
  import 'kysely';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{a as W}from"./chunk-34QKYT53.js";import{n as k,r as x}from"./chunk-5XRKMGCV.js";import"./chunk-7IH5DNUL.js";import"./chunk-2PB34FTK.js";import"./chunk-HO245J34.js";import"./chunk-73HYPGOI.js";var R=Symbol.for("corsair:internal");function P(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 b(n){return n[R]?.database}async function I(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=b(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 d=P(g.api,e.endpoint.split("."));if(!d)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,a=await d(i);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:a}}catch(i){let a=i instanceof Error?i.message:String(i),c=b(n);return c&&await c.db.updateTable("corsair_permissions").set({status:"failed",error:a,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:a}}}function B(n){return n!==null&&typeof n=="object"&&"match"in n&&"handler"in n&&typeof n.match=="function"&&typeof n.handler=="function"}function m(n,r,o=[]){for(let[e,t]of Object.entries(n))if(B(t)){if(t.match(r))return{webhook:t,path:[...o,e]}}else if(t&&typeof t=="object"){let s=m(t,r,[...o,e]);if(s)return s}return null}function C(n){let r={};for(let[o,e]of Object.entries(n))r[o.toLowerCase()]=Array.isArray(e)?e[0]:e;return r}function S(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 T(n,r,o,e){let t=C(r),s=typeof o=="string"?JSON.parse(o):o;(!s||typeof s=="object"&&Object.keys(s).length===0)&&t["x-goog-resource-uri"]&&(s=S(t)||s);let d={headers:t,body:s},i=e?.tenantId||"default",a=n.withTenant?n.withTenant(i):n,c=k;for(let l of c){let p=a[l];if(!p||!p.webhooks||p.pluginWebhookMatcher&&!p.pluginWebhookMatcher(d))continue;let f=m(p.webhooks,d);if(!f)continue;let h=f.path.join("."),w={payload:s,headers:t,rawBody:typeof o=="string"?o:JSON.stringify(o)};try{let u=await f.webhook.handler(w),y=!!Object.keys(u.returnToSender||{})?.length;return{plugin:l,action:h,body:s,response:y?{...u?.returnToSender,success:!0}:{success:!0},...u.responseHeaders&&{responseHeaders:u.responseHeaders}}}catch(u){return console.error(`Error executing webhook handler for ${l}.${h}:`,u),{plugin:l,action:h,body:s,response:{success:!1,error:u instanceof Error?u.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}export{x as createCorsair,I as executePermission,T as processWebhook,W as setupCorsair};
1
+ import{a as W}from"./chunk-CZV54LHV.js";import{n as k,r as x}from"./chunk-642IYEGX.js";import"./chunk-7IH5DNUL.js";import"./chunk-2PB34FTK.js";import"./chunk-HO245J34.js";import"./chunk-73HYPGOI.js";var R=Symbol.for("corsair:internal");function P(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 b(n){return n[R]?.database}async function I(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=b(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 d=P(g.api,e.endpoint.split("."));if(!d)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,a=await d(i);return await n.permissions.set_completed(e.id),{plugin:e.plugin,endpoint:e.endpoint,result:a}}catch(i){let a=i instanceof Error?i.message:String(i),c=b(n);return c&&await c.db.updateTable("corsair_permissions").set({status:"failed",error:a,updated_at:new Date}).where("id","=",e.id).execute(),{plugin:e.plugin,endpoint:e.endpoint,result:null,error:a}}}function B(n){return n!==null&&typeof n=="object"&&"match"in n&&"handler"in n&&typeof n.match=="function"&&typeof n.handler=="function"}function m(n,r,o=[]){for(let[e,t]of Object.entries(n))if(B(t)){if(t.match(r))return{webhook:t,path:[...o,e]}}else if(t&&typeof t=="object"){let s=m(t,r,[...o,e]);if(s)return s}return null}function C(n){let r={};for(let[o,e]of Object.entries(n))r[o.toLowerCase()]=Array.isArray(e)?e[0]:e;return r}function S(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 T(n,r,o,e){let t=C(r),s=typeof o=="string"?JSON.parse(o):o;(!s||typeof s=="object"&&Object.keys(s).length===0)&&t["x-goog-resource-uri"]&&(s=S(t)||s);let d={headers:t,body:s},i=e?.tenantId||"default",a=n.withTenant?n.withTenant(i):n,c=k;for(let l of c){let p=a[l];if(!p||!p.webhooks||p.pluginWebhookMatcher&&!p.pluginWebhookMatcher(d))continue;let f=m(p.webhooks,d);if(!f)continue;let h=f.path.join("."),w={payload:s,headers:t,rawBody:typeof o=="string"?o:JSON.stringify(o)};try{let u=await f.webhook.handler(w),y=!!Object.keys(u.returnToSender||{})?.length;return{plugin:l,action:h,body:s,response:y?{...u?.returnToSender,success:!0}:{success:!0},...u.responseHeaders&&{responseHeaders:u.responseHeaders}}}catch(u){return console.error(`Error executing webhook handler for ${l}.${h}:`,u),{plugin:l,action:h,body:s,response:{success:!1,error:u instanceof Error?u.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}export{x as createCorsair,I as executePermission,T as processWebhook,W as setupCorsair};
package/dist/setup.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CorsairPlugin, c as CorsairSingleTenantClient } from './index-CNwyqNCs.js';
1
+ import { C as CorsairPlugin, c as CorsairSingleTenantClient } from './index-D_Ah5Tz6.js';
2
2
  import 'zod';
3
3
  import './orm.js';
4
4
  import './db.js';
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{a as o}from"./chunk-34QKYT53.js";import"./chunk-5XRKMGCV.js";import"./chunk-7IH5DNUL.js";import"./chunk-2PB34FTK.js";import"./chunk-HO245J34.js";import"./chunk-73HYPGOI.js";export{o as setupCorsair};
1
+ import{a as o}from"./chunk-CZV54LHV.js";import"./chunk-642IYEGX.js";import"./chunk-7IH5DNUL.js";import"./chunk-2PB34FTK.js";import"./chunk-HO245J34.js";import"./chunk-73HYPGOI.js";export{o as setupCorsair};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsair",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -72,7 +72,6 @@
72
72
  "build": "NODE_OPTIONS=--max-old-space-size=8192 tsup",
73
73
  "build:watch": "tsup --watch",
74
74
  "typecheck": "tsc --noEmit",
75
- "ind": "tsx index.ts",
76
- "generate:plugin": "tsx templates/plugin/generate.ts"
75
+ "ind": "tsx index.ts"
77
76
  }
78
77
  }
@@ -1,15 +0,0 @@
1
- import{a as le,b as Y}from"./chunk-2PB34FTK.js";import{a as ue}from"./chunk-73HYPGOI.js";import{createCipheriv as ge,createDecipheriv as pe,randomBytes as j,scrypt as ve}from"crypto";import{promisify as De}from"util";var fe=De(ve),H="aes-256-gcm",ye=12,U=16,Ke=16,N=32;function K(){return j(N).toString("base64")}async function O(e,t){let n=j(Ke),o=await fe(t,n,N),r=j(ye),i=ge(H,o,r,{authTagLength:U}),s=Buffer.concat([i.update(e,"utf8"),i.final()]),a=i.getAuthTag();return[n.toString("base64"),r.toString("base64"),a.toString("base64"),s.toString("base64")].join(":")}async function D(e,t){let[n,o,r,i]=e.split(":");if(!n||!o||!r||!i)throw new Error("Invalid encrypted DEK format");let s=Buffer.from(n,"base64"),a=Buffer.from(o,"base64"),d=Buffer.from(r,"base64"),g=Buffer.from(i,"base64"),y=await fe(t,s,N),c=pe(H,y,a,{authTagLength:U});return c.setAuthTag(d),Buffer.concat([c.update(g),c.final()]).toString("utf8")}function Q(e,t){let n=Buffer.from(t,"base64"),o=j(ye),r=ge(H,n,o,{authTagLength:U}),i=Buffer.concat([r.update(e,"utf8"),r.final()]),s=r.getAuthTag();return[o.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function X(e,t){let[n,o,r]=e.split(":");if(!n||!o||!r)throw new Error("Invalid encrypted data format");let i=Buffer.from(t,"base64"),s=Buffer.from(n,"base64"),a=Buffer.from(o,"base64"),d=Buffer.from(r,"base64"),g=pe(H,i,s,{authTagLength:U});return g.setAuthTag(a),Buffer.concat([g.update(d),g.final()]).toString("utf8")}function S(e,t){let n={};for(let[o,r]of Object.entries(e))n[o]=Q(r,t);return n}function M(e,t){let n={};for(let[o,r]of Object.entries(e))n[o]=X(r,t);return n}function $(e,t,n){let o=M(e,t);return S(o,n)}function q(e,t){let n=[];e||n.push("database"),t||n.push("kek");let o={};return new Proxy(o,{get(r,i){let s=n.length>1;throw new Error(`corsair.keys.${String(i)}: Cannot access keys because ${n.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 ${N}`)}})}var W={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 he(e,t,n){let o={};for(let r of n)o[`get_${r}`]=async()=>(await e())[r]??null,o[`set_${r}`]=async i=>{let s=[null,void 0,""].includes(i)?null:i;await t({[r]:s})};return o}var ee=e=>{if(!e)return{};if(typeof e=="string")try{return JSON.parse(e)}catch{return{}}return e};function z(e){let{authType:t,integrationName:n,kek:o,database:r,extraIntegrationFields:i=[]}=e,s=[...W[t].integration,...i],a=null,d={kek:o,integrationName:n,getIntegration:async()=>{if(a)return a;let u=await r.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!u)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);return a={id:u.id,config:ee(u.config),dek:u.dek??null},a},updateIntegration:async u=>{let f=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","=",f.id).execute(),a=null}},g=null,y=async()=>{if(g)return g;let u=await d.getIntegration();if(!u.dek)throw new Error(`No DEK found for integration "${n}". Initialize the integration first.`);return g=await D(u.dek,o),g},c=async()=>{let u=await d.getIntegration(),f=await y(),h=u.config;return!h||Object.keys(h).length===0?{}:M(h,f)};return{get_dek:y,issue_new_dek:async()=>{let u=await d.getIntegration(),f=K(),h={};if(u.dek){let E=await D(u.dek,o),T=u.config;T&&Object.keys(T).length>0&&(h=$(T,E,f))}let w=await O(f,o);return await d.updateIntegration({config:h,dek:w}),g=f,f},...he(c,async u=>{let f=await y(),h;try{h=await c()}catch(T){console.error(`[corsair] Failed to decrypt config for integration "${n}", starting fresh:`,T),h={}}let w={...h};for(let[T,l]of Object.entries(u))l===null?delete w[T]:w[T]=l;let E=S(w,f);await d.updateIntegration({config:E})},s)}}function G(e){let{authType:t,integrationName:n,tenantId:o,kek:r,database:i,extraAccountFields:s=[]}=e,a=[...W[t].account,...s],d=null,g=null,y=async()=>{if(g)return g;let l=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!l)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);return g={id:l.id,config:ee(l.config),dek:l.dek??null},g},c={kek:r,integrationName:n,tenantId:o,getIntegration:y,getAccount:async()=>{if(d)return d;let l=await y(),k=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",o).where("integration_id","=",l.id).executeTakeFirst();if(!k)throw new Error(`Account not found for tenant "${o}" and integration "${n}". Make sure to create the account first.`);return d={id:k.id,config:ee(k.config),dek:k.dek??null},d},updateAccount:async l=>{let k=await c.getAccount();await i.db.updateTable("corsair_accounts").set({...l.config!==void 0?{config:l.config}:{},...l.dek!==void 0?{dek:l.dek}:{},updated_at:new Date}).where("id","=",k.id).execute(),d=null}},m=null,p=null,u=async()=>{if(m)return m;let l=await c.getAccount();if(!l.dek)throw new Error(`No DEK found for account (tenant: "${o}", integration: "${n}"). Initialize the account first.`);return m=await D(l.dek,r),m},f=async()=>{if(p)return p;let l=await c.getIntegration();if(!l.dek)throw new Error(`No DEK found for integration "${n}". Initialize the integration first.`);return p=await D(l.dek,r),p},h=async()=>{let l=await c.getAccount(),k=await u(),b=l.config;return!b||Object.keys(b).length===0?{}:M(b,k)},w=async()=>{let l=await c.getIntegration(),k=await f(),b=l.config;return!b||Object.keys(b).length===0?{}:M(b,k)},T={get_dek:u,issue_new_dek:async()=>{let l=await c.getAccount(),k=K(),b={};if(l.dek){let A=await D(l.dek,r),P=l.config;P&&Object.keys(P).length>0&&(b=$(P,A,k))}let I=await O(k,r);return await c.updateAccount({config:b,dek:I}),m=k,k},...he(h,async l=>{let k=await u(),b;try{b=await h()}catch(P){console.error(`[corsair] Failed to decrypt config for account (tenant: "${o}", integration: "${n}"), starting fresh:`,P),b={}}let I={...b};for(let[P,C]of Object.entries(l))C===null?delete I[P]:I[P]=C;let A=S(I,k);await c.updateAccount({config:A})},a)};return t==="oauth_2"&&(T.get_integration_credentials=async()=>{let l=await w();return{client_id:l.client_id||null,client_secret:l.client_secret||null,redirect_url:l.redirect_url??null}}),T}async function me(e,t,n){let o=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!o)throw new Error(`Integration "${t}" not found.`);let r=K(),i=await O(r,n);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",o.id).execute(),r}async function ke(e,t,n,o){let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!r)throw new Error(`Integration "${t}" not found.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",n).where("integration_id","=",r.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${n}" and integration "${t}".`);let s=K(),a=await O(s,o);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var Oe=async(e,t)=>(console.error(`[corsair:${t.pluginId}:${t.operation}]`,{error:e.message,input:t.input}),{maxRetries:0});async function be(e,t,n,o,r){let i={pluginId:t,operation:n,input:o,originalError:e},s=Object.keys(r).find(g=>r[g]?.match(e,i));return await(r[s||"DEFAULT"]?.handler||Oe)(e,i)}import{randomBytes as Me}from"crypto";import{v4 as Fe}from"uuid";var Se={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 Be(e,t,n){return n!==void 0?n:Se[t][e]}function we(e){let t=/(\d+)(d|h|m|s)/g,n=0,o;for(;(o=t.exec(e))!==null;){let r=parseInt(o[1],10);switch(o[2]){case"d":n+=r*864e5;break;case"h":n+=r*36e5;break;case"m":n+=r*6e4;break;case"s":n+=r*1e3;break}}return n>0?n:600*1e3}function Ce(e){return{async find_by_permission_id(t){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("id","=",t).executeTakeFirst()},async find_by_token(t){if(e)return e.db.selectFrom("corsair_permissions").selectAll().where("token","=",t).executeTakeFirst()},async set_executing(t){e&&await e.db.updateTable("corsair_permissions").set({status:"executing",updated_at:new Date}).where("id","=",t).execute()},async set_completed(t){e&&await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",t).execute()}}}async function Te(e){let t=Be(e.riskLevel,e.mode,e.override);if(t==="allow")return{result:"allow"};let n=e.meta?.irreversible?" (irreversible)":"",o=e.meta?.description?`${e.meta.description}${n}`:`${e.pluginId}.${e.endpointPath}${n}`;if(t==="deny"||!e.db)return console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 denied by permission mode '${e.mode}'.`,`
4
- Action: ${o}`,`
5
- To allow this, update the permission mode or add an override in your corsair config.`),{result:"blocked"};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 m=e.db,p=a.id;return{result:"allow",onComplete:async()=>{await m.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",p).execute()}}}return a.status==="executing"?{result:"allow"}:(console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval already pending.`,`
6
- Action: ${o}`,`
7
- Permission ID: ${a.id}`,`
8
- Use the token to approve or deny this request.`),{result:"blocked"})}let d=Fe(),g=Me(32).toString("hex"),y=e.timeoutMs??600*1e3,c=new Date(Date.now()+y).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:d,created_at:new Date,updated_at:new Date,token:g,plugin:e.pluginId,endpoint:e.endpointPath,args:r,tenant_id:s,status:"pending",expires_at:c}).execute(),console.log(`[corsair/${e.pluginId}] '${e.endpointPath}' blocked \u2014 approval required.`,`
9
- Action: ${o}`,`
10
- Permission ID: ${d}`,`
11
- Permission token: ${g}`,`
12
- Expires at: ${c}`,`
13
- Use the token to approve or deny this request.`),{result:"blocked"}}function Ne(e){return typeof e=="function"}function ne({endpoints:e,hooks:t,ctx:n,tree:o,pluginId:r,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:d,endpointMeta:g,database:y,approvalConfig:c,tenantId:m}){for(let[p,u]of Object.entries(e)){let f=t?.[p];if(Ne(u)){let h=f,w=[...s,p].join("."),E=async(T={})=>{let l;if(d){let C=g?.[w],{result:v,onComplete:R}=await Te({pluginId:r,endpointPath:w,args:T,mode:d.mode,override:d.overrides?.[w],riskLevel:C?.riskLevel??"write",meta:C,db:y,timeoutMs:c?we(c.timeout):void 0,tenantId:m});if(v==="blocked")return null;l=R}let k=async(C,v,R)=>{try{return await u(v,R)}catch(B){if(B instanceof Error){let F=await be(B,r,w,typeof R=="object"&&R!==null?R:{args:R},i);if(C<(F.maxRetries||0)){let L=C+1;console.log(`Retrying (${L} / ${F.maxRetries})...`);let _;if(F.headersRetryAfterMs)_=F.headersRetryAfterMs;else switch(F.retryStrategy){case"exponential_backoff":_=Math.pow(2,L-1)*1e3;break;case"exponential_backoff_jitter":let V=Math.pow(2,L-1)*1e3,_e=(Math.random()-.5)*1e3;_=Math.max(0,V+_e);break;case"linear_1s":_=1e3;break;case"linear_2s":_=2e3;break;case"linear_3s":_=3e3;break;case"linear_4s":_=4e3;break;default:_=1e3;break}await new Promise(V=>setTimeout(V,_)),await k(L,v,R),console.log(`[corsair:${r}:${w}] Retry strategy:`,F)}}throw B}},b=a?await a(n,"endpoint"):void 0;if(!h?.before&&!h?.after){let C=await k(0,{...n,key:b},T);return await l?.(),C}let I={...n,key:b},A=h.before?await h.before(I,T):{ctx:I,args:T,continue:!0,passToAfter:void 0};if(A.continue===!1)return;let P=await k(0,A.ctx,A.args);return await h.after?.(A.ctx,P,A.passToAfter),await l?.(),P};o[p]=E}else if(u&&typeof u=="object"){let h={};ne({endpoints:u,hooks:f,ctx:n,tree:h,pluginId:r,errorHandlers:i,currentPath:[...s,p],keyBuilder:a,permissionsConfig:d,endpointMeta:g,database:y,approvalConfig:c,tenantId:m}),o[p]=h}}}var Pe=["airtable","amplitude","asana","box","cal","calendly","discord","dropbox","exa","figma","fireflies","github","gmail","googlecalendar","googledrive","googlesheets","hackernews","hubspot","intercom","jira","linear","monday","notion","oura","pagerduty","posthog","resend","sentry","slack","spotify","stripe","tavily","teams","telegram","todoist","trello","twitter","twitterapiio","typeform","zoom"];function x(e){let t=e._def,n=t.typeName;switch(n){case"ZodString":return{type:"string"};case"ZodNumber":return{type:"number"};case"ZodBoolean":return{type:"boolean"};case"ZodNull":return{type:"null"};case"ZodUnknown":case"ZodAny":return{};case"ZodLiteral":return{const:t.value};case"ZodEnum":return{enum:t.values};case"ZodOptional":return x(t.innerType);case"ZodNullable":return{anyOf:[x(t.innerType),{type:"null"}]};case"ZodArray":return{type:"array",items:x(t.type)};case"ZodRecord":return{type:"object",additionalProperties:x(t.valueType)};case"ZodObject":{let o=t.shape(),r={},i=[];for(let[a,d]of Object.entries(o)){r[a]=x(d);let g=d._def.typeName;g!=="ZodOptional"&&g!=="ZodNullable"&&i.push(a)}let s={type:"object",properties:r};return i.length>0&&(s.required=i),s}case"ZodUnion":return{anyOf:t.options.map(x)};case"ZodIntersection":return{allOf:[x(t.left),x(t.right)]};case"ZodEffects":return x(t.schema);default:return{type:(n??"unknown").replace("Zod","").toLowerCase()}}}var xe=["equals","contains","startsWith","endsWith","in"],$e=["equals","gt","gte","lt","lte","in"],We=["equals"],Ze=["equals","before","after","between"];function re(e){let t=e._def;switch(t.typeName){case"ZodOptional":case"ZodNullable":case"ZodDefault":return re(t.innerType);case"ZodEffects":return re(t.schema);case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function oe(e){let t=e._def,n=t.typeName;if(n==="ZodOptional"||n==="ZodNullable"||n==="ZodDefault")return oe(t.innerType);if(n==="ZodEffects")return oe(t.schema);if(n!=="ZodObject")return{};let o=t.shape(),r={};for(let[i,s]of Object.entries(o)){let a=re(s);a==="string"?r[i]={type:"string",operators:xe}:a==="number"?r[i]={type:"number",operators:$e}:a==="boolean"?r[i]={type:"boolean",operators:We}:a==="date"&&(r[i]={type:"date",operators:Ze})}return r}function Le(e,t){for(let[n,o]of Object.entries(e))if(n.toLowerCase()===t)return[n,o]}function ie(e,t,n){for(let[o,r]of Object.entries(e)){let i=[...t,o];typeof r=="function"?n.push(i.join(".")):r!==null&&typeof r=="object"&&ie(r,i,n)}}function se(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function ae(e,t,n){for(let[o,r]of Object.entries(e)){let i=[...t,o];se(r)?n.push(i.join(".")):r!==null&&typeof r=="object"&&ae(r,i,n)}}function Ae(e,t){if(t.length===0)return null;let[n,...o]=t,r=Object.entries(e).find(([a])=>a.toLowerCase()===n);if(!r)return null;let[i,s]=r;if(o.length===0)return se(s)?[i]:null;if(s!==null&&typeof s=="object"&&!se(s)){let a=Ae(s,o);if(a!==null)return[i,...a]}return null}function je(e,t,n){let o=[];o.push(`${e}({`),o.push(" webhookHooks: {");for(let s=0;s<t.length;s++){let a=" ".repeat(s+2);o.push(`${a}${t[s]}: {`)}let r=" ".repeat(t.length+2),i=r+" ";if(o.push(`${r}before(ctx, args) {`),o.push(`${i}return { ctx, args };`),o.push(`${r}},`),o.push(`${r}after(ctx, response) {`),n!==null){let a=JSON.stringify(n,null,2).split(`
14
- `).map((d,g)=>g===0?`${i}// response.data: ${d}`:`${i}// ${d}`);o.push(...a)}else o.push(`${i}// response.data: unknown (register webhookSchemas to see the type)`);o.push(`${r}},`);for(let s=t.length-1;s>=0;s--){let a=" ".repeat(s+2);o.push(`${a}},`)}return o.push(" },"),o.push("})"),o.join(`
15
- `)}var He=new Set(Pe);function Z(e,t){let n=t?.type??"api",o=t?.plugin;if(o!==void 0){let i=e.find(a=>a.id===o);if(!i)return He.has(o)?`This plugin (${o}) is not configured. Please add it to the Corsair instance to see its associated methods.`:Z(e);if(n==="webhooks"){if(!i.webhooks)return[];let a=[];return ae(i.webhooks,[],a),a.map(d=>`${i.id}.webhooks.${d}`)}if(n==="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 ie(i.endpoints,[],s),s.map(a=>`${i.id}.api.${a.toLowerCase()}`)}let r={};if(n==="webhooks")for(let i of e){if(!i.webhooks)continue;let s=[];ae(i.webhooks,[],s),r[i.id]=s.map(a=>`${i.id}.webhooks.${a}`)}else if(n==="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=[];ie(i.endpoints,[],s),r[i.id]=s.map(a=>`${i.id}.api.${a.toLowerCase()}`)}return r}function te(e,t){if(e){for(let[n,o]of Object.entries(e))if(n.toLowerCase()===t)return o}}function Ue(e,t){let n=t.toLowerCase(),o=n.indexOf(".");if(o!==-1){let r=n.slice(0,o),i=n.slice(o+1),s=e.find(a=>a.id===r);if(s){if(i.startsWith("db.")){let y=i.slice(3),c=y.lastIndexOf(".");if(c!==-1){let m=y.slice(0,c),p=y.slice(c+1),u=s.schema?.entities;if(p==="search"&&u){let f=Le(u,m);if(f){let[h,w]=f;return{description:`Search ${r} ${h} stored in the local database. Returns an array of matching records. Pass limit and offset (numbers) for pagination.`,filters:{entity_id:{type:"string",operators:xe},data:oe(w)}}}}}return{availableMethods:Z(e,{type:"db"})}}if(i.startsWith("webhooks.")){let y=i.slice(9);if(s.webhooks){let c=Ae(s.webhooks,y.split("."));if(c!==null){let m=c.join("."),p=te(s.webhookSchemas,m.toLowerCase()),u=p?.response?x(p.response):null;return{description:p?.description,payload:p?.payload?x(p.payload):void 0,response:u??void 0,usage:je(r,c,u)}}}return{availableWebhooks:Z(e,{type:"webhooks"})}}let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=te(s.endpointMeta,a),g=te(s.endpointSchemas,a);if(d||g)return{description:d?.description,riskLevel:d?.riskLevel,irreversible:d?.irreversible,input:g?.input?x(g.input):void 0,output:g?.output?x(g.output):void 0}}}return{availableMethods:Z(e)}}function J(e){return{list_operations(t){return Z(e,t)},get_schema(t){return Ue(e,t)}}}function qe(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function ce({webhooks:e,hooks:t,ctx:n,webhooksTree:o,keyBuilder:r}){for(let[i,s]of Object.entries(e)){let a=t?.[i];if(qe(s)){let d=a,g=async y=>{let c=(p,u)=>s.handler(p,u),m=r?await r(n,"webhook"):void 0;return!d?.before&&!d?.after?c({...n,key:m},y):(async()=>{let p={...n,key:m},u=d.before?await d.before(p,y):{ctx:p,args:y,continue:!0,passToAfter:void 0};if(u.continue===!1)return;let f=await c(u.ctx,u.args);return f?.success===!0&&await d.after?.(u.ctx,f,u.passToAfter),f})()};o[i]={match:s.match,handler:g}}else if(s&&typeof s=="object"){let d={};ce({webhooks:s,hooks:a,ctx:n,webhooksTree:d,keyBuilder:r}),o[i]=d}}}function ze(e,t,n){let o=null;return async()=>{if(o)return o;if(!e)throw new Error("Database not configured");let r=await e.db.selectFrom("corsair_integrations").selectAll().where("name","=",t).executeTakeFirst();if(!r)throw new Error(`Integration "${t}" not found. Make sure to create the integration first.`);let i=await e.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",n).where("integration_id","=",r.id).executeTakeFirst();if(!i)throw new Error(`Account not found for tenant "${n}" and integration "${t}". Make sure to create the account first.`);return o=i.id,o}}function Ge(e,t,n,o,r){return e?Y(e.db,t,n,o,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 de(e,t){let{database:n,tenantId:o,kek:r,rootErrorHandlers:i,approvalConfig:s}=t,a={},d={};for(let c of e)a[c.id]={},d[c.id]={};for(let c of e){let m=c.schema,p=o??"default",u=ze(n,c.id,p);if(m?.entities){let C={};for(let[v,R]of Object.entries(m.entities)){let B=n?Y(n.db,u,v,m.version,R):Ge(void 0,u,v,m.version,R);C[v]=B}d[c.id].db=C,a[c.id].db=C}let f=c.options,h=c.authConfig,w;if(n&&r&&f?.authType){let C=h?.[f.authType]?.account??[];w=G({authType:f.authType,integrationName:c.id,tenantId:p,kek:r,database:n,extraAccountFields:C}),a[c.id].keys=w}let E={database:n,db:d[c.id]?.db??{},$getAccountId:u,...c.options?{options:c.options}:{},...w?{keys:w,authType:f?.authType}:{},...o?{tenantId:o}:{}},T=c.endpoints??{},l=c.hooks,k={...i,...c.errorHandlers},b={},I=c.options?.permissions;ne({endpoints:T,hooks:l,ctx:E,tree:b,pluginId:c.id,errorHandlers:k,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:I,endpointMeta:c.endpointMeta,database:n,approvalConfig:s,tenantId:o}),Object.keys(b).length>0&&(a[c.id].api=b),E.endpoints=b;let A=c.webhooks??{},P=c.webhookHooks;if(Object.keys(A).length>0){let C={};ce({webhooks:A,hooks:P,ctx:E,webhooksTree:C,keyBuilder:c.keyBuilder}),a[c.id].webhooks=C,c.pluginWebhookMatcher&&(a[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher)}}let g=a,y=J(e);return{...g,...y}}function Re(e,t,n){let o={};for(let r of e){let i=r.options,s=r.authConfig;if(i?.authType){let a=s?.[i.authType]?.integration??[],d=z({authType:i.authType,integrationName:r.id,kek:n,database:t,extraIntegrationFields:a});o[r.id]=d}}return o}async function Ee(e,t,n,o,r="pending"){if(!e)return null;try{let i=le(),s=new Date;return await e.db.insertInto("corsair_events").values({id:i,created_at:s,updated_at:s,account_id:t,event_type:n,payload:o,status:r}).execute(),i}catch(i){return console.warn("Failed to log event:",i),null}}async function Je(e,t,n,o="pending"){try{let r=await e.$getAccountId();return Ee(e.database,r,t,n,o)}catch(r){return console.warn("Failed to log event:",r),null}}var Ie=Symbol.for("corsair:internal");function Bn(e){let t=e.database?ue(e.database):void 0,n=t&&e.kek?Re(e.plugins,t,e.kek):q(!!t,!!e.kek),o={plugins:e.plugins,database:t,kek:e.kek,multiTenancy:!!e.multiTenancy,approval:e.approval},r=Ce(t);if(e.multiTenancy)return Object.assign({withTenant:s=>{if(!s)throw new Error("corsair.withTenant(tenantId): tenantId must be a non-empty string");return de(e.plugins,{database:t,tenantId:s,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval})},keys:n,permissions:r,...J(e.plugins)},{[Ie]:o});let i=de(e.plugins,{database:t,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval});return Object.assign({},i,{keys:n,permissions:r,[Ie]:o})}export{K as a,O as b,D as c,Q as d,X as e,S as f,M as g,$ as h,W as i,z as j,G as k,me as l,ke as m,Pe as n,Ee as o,Je as p,Ie as q,Bn as r};