corsair 0.1.59 → 0.1.61
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.
- package/dist/chunk-34FMIFYP.js +26 -0
- package/dist/{chunk-3XKGQYPT.js → chunk-4UXFAV2B.js} +1 -1
- package/dist/core.d.ts +3 -3
- package/dist/core.js +1 -1
- package/dist/index-DWGwcIFp.d.ts +135 -0
- package/dist/{index-DVL--3eB.d.ts → index-DhJiJ1ZE.d.ts} +22 -86
- package/dist/index.d.ts +44 -3
- package/dist/index.js +3 -1
- package/dist/setup.d.ts +1 -1
- package/dist/setup.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-7QIX3IRP.js +0 -26
- package/dist/index-BRo0KrXQ.d.ts +0 -35
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import{a as he,b as X}from"./chunk-2PB34FTK.js";import{a as ye}from"./chunk-ZGVIF3UY.js";import{createCipheriv as me,createDecipheriv as ke,randomBytes as H,scrypt as Me}from"crypto";import{promisify as Ne}from"util";var be=Ne(Me),U="aes-256-gcm",we=12,z=16,Be=16,B=32;function v(){return H(B).toString("base64")}async function F(e,t){let n=H(Be),r=await be(t,n,B),o=H(we),i=me(U,r,o,{authTagLength:z}),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"),c=Buffer.from(i,"base64"),l=await be(t,s,B),p=ke(U,l,a,{authTagLength:z});return p.setAuthTag(d),Buffer.concat([p.update(c),p.final()]).toString("utf8")}function ee(e,t){let n=Buffer.from(t,"base64"),r=H(we),o=me(U,n,r,{authTagLength:z}),i=Buffer.concat([o.update(e,"utf8"),o.final()]),s=o.getAuthTag();return[r.toString("base64"),s.toString("base64"),i.toString("base64")].join(":")}function ne(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"),c=ke(U,i,s,{authTagLength:z});return c.setAuthTag(a),Buffer.concat([c.update(d),c.final()]).toString("utf8")}function M(e,t){let n={};for(let[r,o]of Object.entries(e))n[r]=ee(o,t);return n}function O(e,t){let n={};for(let[r,o]of Object.entries(e))n[r]=ne(o,t);return n}function Z(e,t,n){let r=O(e,t);return M(r,n)}function q(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 j={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 Te(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 te=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=[...j[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:te(u.config),dek:u.dek??null},a},updateIntegration:async u=>{let y=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","=",y.id).execute(),a=null}},c=null,l=async()=>{if(c)return c;let u=await d.getIntegration();if(!u.dek)throw new Error(`No DEK found for integration "${n}". Initialize the integration first.`);return c=await D(u.dek,r),c},p=async()=>{let u=await d.getIntegration(),y=await l(),m=u.config;return!m||Object.keys(m).length===0?{}:O(m,y)};return{get_dek:l,issue_new_dek:async()=>{let u=await d.getIntegration(),y=v(),m={};if(u.dek){let P=await D(u.dek,r),b=u.config;b&&Object.keys(b).length>0&&(m=Z(b,P,y))}let w=await F(y,r);return await d.updateIntegration({config:m,dek:w}),c=y,y},...Te(p,async u=>{let y=await l(),m;try{m=await p()}catch(b){console.error(`[corsair] Failed to decrypt config for integration "${n}", starting fresh:`,b),m={}}let w={...m};for(let[b,g]of Object.entries(u))g===null?delete w[b]:w[b]=g;let P=M(w,y);await d.updateIntegration({config:P})},s)}}function V(e){let{authType:t,integrationName:n,tenantId:r,kek:o,database:i,extraAccountFields:s=[]}=e,a=[...j[t].account,...s],d=null,c=null,l=async()=>{if(c)return c;let g=await i.db.selectFrom("corsair_integrations").selectAll().where("name","=",n).executeTakeFirst();if(!g)throw new Error(`Integration "${n}" not found. Make sure to create the integration first.`);return c={id:g.id,config:te(g.config),dek:g.dek??null},c},p={kek:o,integrationName:n,tenantId:r,getIntegration:l,getAccount:async()=>{if(d)return d;let g=await l(),k=await i.db.selectFrom("corsair_accounts").selectAll().where("tenant_id","=",r).where("integration_id","=",g.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:te(k.config),dek:k.dek??null},d},updateAccount:async g=>{let k=await p.getAccount();await i.db.updateTable("corsair_accounts").set({...g.config!==void 0?{config:g.config}:{},...g.dek!==void 0?{dek:g.dek}:{},updated_at:new Date}).where("id","=",k.id).execute(),d=null}},h=null,f=null,u=async()=>{if(h)return h;let g=await p.getAccount();if(!g.dek)throw new Error(`No DEK found for account (tenant: "${r}", integration: "${n}"). Initialize the account first.`);return h=await D(g.dek,o),h},y=async()=>{if(f)return f;let g=await p.getIntegration();if(!g.dek)throw new Error(`No DEK found for integration "${n}". Initialize the integration first.`);return f=await D(g.dek,o),f},m=async()=>{let g=await p.getAccount(),k=await u(),T=g.config;return!T||Object.keys(T).length===0?{}:O(T,k)},w=async()=>{let g=await p.getIntegration(),k=await y(),T=g.config;return!T||Object.keys(T).length===0?{}:O(T,k)},b={get_dek:u,issue_new_dek:async()=>{let g=await p.getAccount(),k=v(),T={};if(g.dek){let C=await D(g.dek,o),x=g.config;x&&Object.keys(x).length>0&&(T=Z(x,C,k))}let R=await F(k,o);return await p.updateAccount({config:T,dek:R}),h=k,k},...Te(m,async g=>{let k=await u(),T;try{T=await m()}catch(x){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${n}"), starting fresh:`,x),T={}}let R={...T};for(let[x,E]of Object.entries(g))E===null?delete R[x]:R[x]=E;let C=M(R,k);await p.updateAccount({config:C})},a)};return t==="oauth_2"&&(b.get_integration_credentials=async()=>{let g=await w();return{client_id:g.client_id||null,client_secret:g.client_secret||null,redirect_url:g.redirect_url??null}}),b}async function Ce(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=v(),i=await F(o,n);return await e.db.updateTable("corsair_integrations").set({dek:i,updated_at:new Date}).where("id","=",r.id).execute(),o}async function Pe(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=v(),a=await F(s,r);return await e.db.updateTable("corsair_accounts").set({dek:a,updated_at:new Date}).where("id","=",i.id).execute(),s}var Ze=async(e,t)=>(console.error(`[corsair:${t.pluginId}:${t.operation}]`,{error:e.message,input:t.input}),{maxRetries:0});async function xe(e,t,n,r,o){let i={pluginId:t,operation:n,input:r,originalError:e},s=Object.keys(o).find(c=>o[c]?.match(e,i));return await(o[s||"DEFAULT"]?.handler||Ze)(e,i)}import{randomBytes as je}from"crypto";import{v4 as We}from"uuid";var Le={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 He(e,t,n){return n!==void 0?n:Le[t][e]}function Ee(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 Re(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 Ae(e,t,n){let r=Date.now()+n;for(;Date.now()<r;){let o=await e.db.selectFrom("corsair_permissions").select(["id","status"]).where("id","=",t).executeTakeFirst();if(!o)return{result:"blocked"};if(o.status==="approved")return{result:"allow",onComplete:async()=>{await e.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",t).execute()}};if(o.status==="denied"||o.status==="expired"||o.status==="failed")return{result:"blocked"};await new Promise(i=>setTimeout(i,500))}return{result:"blocked"}}async function Ie(e){let t=He(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 h=e.db,f=a.id;return{result:"allow",onComplete:async()=>{await h.db.updateTable("corsair_permissions").set({status:"completed",updated_at:new Date}).where("id","=",f).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.`),e.approvalMode==="synchronous"?Ae(e.db,a.id,e.timeoutMs??600*1e3):{result:"blocked"})}let d=We(),c=je(32).toString("hex"),l=e.timeoutMs??600*1e3,p=new Date(Date.now()+l).toISOString();return await e.db.db.insertInto("corsair_permissions").values({id:d,created_at:new Date,updated_at:new Date,token:c,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: ${c}`,`
|
|
12
|
+
Expires at: ${p}`,`
|
|
13
|
+
Use the token to approve or deny this request.`),e.approvalMode==="synchronous"?Ae(e.db,d,l):{result:"blocked"}}function Ue(e){return typeof e=="function"}function re({endpoints:e,hooks:t,ctx:n,tree:r,pluginId:o,errorHandlers:i,currentPath:s=[],keyBuilder:a,permissionsConfig:d,endpointMeta:c,database:l,approvalConfig:p,tenantId:h}){for(let[f,u]of Object.entries(e)){let y=t?.[f];if(Ue(u)){let m=y,w=[...s,f].join("."),P=async(b={})=>{let g;if(d){let E=c?.[w],{result:$,onComplete:_}=await Ie({pluginId:o,endpointPath:w,args:b,mode:d.mode,override:d.overrides?.[w],riskLevel:E?.riskLevel??"write",meta:E,db:l,timeoutMs:p?Ee(p.timeout):void 0,tenantId:h,approvalMode:p?.mode});if($==="blocked")return null;g=_}let k=async(E,$,_)=>{try{return await u($,_)}catch(Y){if(Y instanceof Error){let S=await xe(Y,o,w,typeof _=="object"&&_!==null?_:{args:_},i);if(E<(S.maxRetries||0)){let L=E+1;console.log(`Retrying (${L} / ${S.maxRetries})...`);let I;if(S.headersRetryAfterMs)I=S.headersRetryAfterMs;else switch(S.retryStrategy){case"exponential_backoff":I=Math.pow(2,L-1)*1e3;break;case"exponential_backoff_jitter":let Q=Math.pow(2,L-1)*1e3,Se=(Math.random()-.5)*1e3;I=Math.max(0,Q+Se);break;case"linear_1s":I=1e3;break;case"linear_2s":I=2e3;break;case"linear_3s":I=3e3;break;case"linear_4s":I=4e3;break;default:I=1e3;break}await new Promise(Q=>setTimeout(Q,I)),await k(L,$,_),console.log(`[corsair:${o}:${w}] Retry strategy:`,S)}}throw Y}},T=a?await a(n,"endpoint"):void 0;if(!m?.before&&!m?.after){let E=await k(0,{...n,key:T},b);return await g?.(),E}let R={...n,key:T},C=m.before?await m.before(R,b):{ctx:R,args:b,continue:!0,passToAfter:void 0};if(C.continue===!1)return;let x=await k(0,C.ctx,C.args);return await m.after?.(C.ctx,x,C.passToAfter),await g?.(),x};r[f]=P}else if(u&&typeof u=="object"){let m={};re({endpoints:u,hooks:y,ctx:n,tree:m,pluginId:o,errorHandlers:i,currentPath:[...s,f],keyBuilder:a,permissionsConfig:d,endpointMeta:c,database:l,approvalConfig:p,tenantId:h}),r[f]=m}}}function ze(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function oe({webhooks:e,hooks:t,ctx:n,webhooksTree:r,keyBuilder:o}){for(let[i,s]of Object.entries(e)){let a=t?.[i];if(ze(s)){let d=a,c=async l=>{let p=(f,u)=>s.handler(f,u),h=o?await o(n,"webhook"):void 0;return!d?.before&&!d?.after?p({...n,key:h},l):(async()=>{let f={...n,key:h},u=d.before?await d.before(f,l):{ctx:f,args:l,continue:!0,passToAfter:void 0};if(u.continue===!1)return;let y=await p(u.ctx,u.args);return y?.success===!0&&await d.after?.(u.ctx,y,u.passToAfter),y})()};r[i]={match:s.match,handler:c}}else if(s&&typeof s=="object"){let d={};oe({webhooks:s,hooks:a,ctx:n,webhooksTree:d,keyBuilder:o}),r[i]=d}}}function qe(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 Ge(e,t,n,r,o){return e?X(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 ie(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 l=c.schema,p=r??"default",h=qe(n,c.id,p);if(l?.entities){let C={};for(let[x,E]of Object.entries(l.entities)){let $=n?X(n.db,h,x,l.version,E):Ge(void 0,h,x,l.version,E);C[x]=$}d[c.id].db=C,a[c.id].db=C}let f=c.options,u=c.authConfig,y;if(n&&o&&f?.authType){let C=u?.[f.authType]?.account??[];y=V({authType:f.authType,integrationName:c.id,tenantId:p,kek:o,database:n,extraAccountFields:C}),a[c.id].keys=y}let m={database:n,db:d[c.id]?.db??{},$getAccountId:h,...c.options?{options:c.options}:{},...y?{keys:y,authType:f?.authType}:{},...r?{tenantId:r}:{}},w=c.endpoints??{},P=c.hooks,b={...i,...c.errorHandlers},g={},k=c.options?.permissions;re({endpoints:w,hooks:P,ctx:m,tree:g,pluginId:c.id,errorHandlers:b,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:k,endpointMeta:c.endpointMeta,database:n,approvalConfig:s,tenantId:r}),Object.keys(g).length>0&&(a[c.id].api=g),m.endpoints=g;let T=c.webhooks??{},R=c.webhookHooks;if(Object.keys(T).length>0){let C={};oe({webhooks:T,hooks:R,ctx:m,webhooksTree:C,keyBuilder:c.keyBuilder}),a[c.id].webhooks=C,c.pluginWebhookMatcher&&(a[c.id].pluginWebhookMatcher=c.pluginWebhookMatcher)}}return a}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 De(e,t,n,r,o="pending"){if(!e)return null;try{let i=he(),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 Ve(e,t,n,r="pending"){try{let o=await e.$getAccountId();return De(e.database,o,t,n,r)}catch(o){return console.warn("Failed to log event:",o),null}}var ve=["ably","airtable","amplitude","asana","box","cal","calendly","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gmail","googlecalendar","googledrive","googlesheets","hackernews","hubspot","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","tavily","teams","telegram","todoist","trello","twitter","twitterapiio","typeform","youtube","zoom"];var Fe=" ";function A(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 A(t.innerType);case"ZodNullable":return`${A(t.innerType)} | null`;case"ZodArray":{let r=t.type,i=r._def.typeName==="ZodUnion",s=A(r);return`${i?`(${s})`:s}[]`}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}: ${A(a)}`}).join(", ")} }`}case"ZodUnion":return t.options.map(A).join(" | ");case"ZodIntersection":return`${A(t.left)} & ${A(t.right)}`;case"ZodEffects":return A(t.schema);default:return(n??"unknown").replace("Zod","").toLowerCase()}}function W(e,t){let n=e._def,r=n.typeName;if(r==="ZodOptional"||r==="ZodEffects")return W(r==="ZodOptional"?n.innerType:n.schema,t);if(r!=="ZodObject")return A(e);let o=n.shape(),i=Object.entries(o);if(i.length===0)return"{}";let s=Fe.repeat(t+1),a=Fe.repeat(t),d=[];for(let[c,l]of i){let p=l._def,h=p.typeName,u=h==="ZodOptional"||h==="ZodNullable"?`${c}?`:c,y=h==="ZodOptional"||h==="ZodNullable"?p.innerType:l,m=y?._def,w=m?.typeName,P=m?.description,b=P?` // ${P}`:"";w==="ZodObject"?d.push(`${s}${u}: ${W(y,t+1)}${b}`):d.push(`${s}${u}: ${A(l)}${b}`)}return`{
|
|
14
|
+
${d.join(`
|
|
15
|
+
`)}
|
|
16
|
+
${a}}`}var pe=["equals","contains","startsWith","endsWith","in"],Je=["equals","gt","gte","lt","lte","in"],Ye=["equals"],Qe=["equals","before","after","between"];function ce(e){let t=e._def;switch(t.typeName){case"ZodOptional":case"ZodNullable":case"ZodDefault":return ce(t.innerType);case"ZodEffects":return ce(t.schema);case"ZodString":return"string";case"ZodNumber":return"number";case"ZodBoolean":return"boolean";case"ZodDate":return"date";default:return null}}function J(e){let t=e._def,n=t.typeName;if(n==="ZodOptional"||n==="ZodNullable"||n==="ZodDefault")return J(t.innerType);if(n==="ZodEffects")return J(t.schema);if(n!=="ZodObject")return{};let r=t.shape(),o={};for(let[i,s]of Object.entries(r)){let a=ce(s);a==="string"?o[i]={type:"string",operators:pe}:a==="number"?o[i]={type:"number",operators:Je}:a==="boolean"?o[i]={type:"boolean",operators:Ye}:a==="date"&&(o[i]={type:"date",operators:Qe})}return o}function Ke(e,t){for(let[n,r]of Object.entries(e))if(n.toLowerCase()===t)return[n,r]}function de(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"&&de(o,i,n)}}function ue(e){return e!==null&&typeof e=="object"&&"match"in e&&"handler"in e&&typeof e.match=="function"&&typeof e.handler=="function"}function le(e,t,n){for(let[r,o]of Object.entries(e)){let i=[...t,r];ue(o)?n.push(i.join(".")):o!==null&&typeof o=="object"&&le(o,i,n)}}function ge(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 ue(s)?[i]:null;if(s!==null&&typeof s=="object"&&!ue(s)){let a=ge(s,r);if(a!==null)return[i,...a]}return null}function $e(e,t){let n=[];n.push(`${e}({`),n.push(" webhookHooks: {");for(let i=0;i<t.length;i++){let s=" ".repeat(i+2);n.push(`${s}${t[i]}: {`)}let r=" ".repeat(t.length+2),o=r+" ";n.push(`${r}before(ctx, args) {`),n.push(`${o}return { ctx, args };`),n.push(`${r}},`),n.push(`${r}after(ctx, response) {`),n.push(`${r}},`);for(let i=t.length-1;i>=0;i--){let s=" ".repeat(i+2);n.push(`${s}},`)}return n.push(" },"),n.push("})"),n.join(`
|
|
17
|
+
`)}var Xe=new Set(ve);function K(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 Xe.has(r)?`This plugin (${r}) is not configured. Please add it to the Corsair instance to see its associated methods.`:K(e);if(n==="webhooks"){if(!i.webhooks)return[];let a=[];return le(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 de(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=[];le(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=[];de(i.endpoints,[],s),o[i.id]=s.map(a=>`${i.id}.api.${a}`)}return o}function N(e,t){if(e){for(let[n,r]of Object.entries(e))if(n.toLowerCase()===t)return r}}function en(e,t){let n=e.toLowerCase(),r=t.toLowerCase();if(!n.startsWith(`${r}.`)){let i=n.slice(t.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(t.length+1);return o.toLowerCase().startsWith("api.")&&(o=o.slice(4)),{shortPath:o,lookupKey:o.toLowerCase()}}function se(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 Sn(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 l=i.slice(3),p=l.lastIndexOf(".");if(p!==-1){let h=l.slice(0,p),f=l.slice(p+1),u=s.schema?.entities;if(f==="search"&&u){let y=Ke(u,h);if(y){let[m,w]=y,P=J(w),b=[`Search ${o} ${m} stored in the local database.`,"Pass limit and offset as numbers for pagination.","","filters {",` entity_id: string [${pe.join(", ")}]`];for(let[g,k]of Object.entries(P))b.push(` ${g}?: ${k.type} [${k.operators.join(", ")}]`);return b.push("}"),b.join(`
|
|
21
|
+
`)}}}return se(K(e,{type:"db"}),"Path not found. Available db operations")}if(i.startsWith("webhooks.")){let l=i.slice(9);if(s.webhooks){let p=ge(s.webhooks,l.split("."));if(p!==null){let h=p.join("."),f=N(s.webhookSchemas,h.toLowerCase()),u=f?.response?A(f.response):null,y=[];return f?.description&&y.push(f.description),f?.payload&&y.push(`payload ${W(f.payload,0)}`),u&&y.push(`response: ${u}`),y.push(`usage:
|
|
22
|
+
${$e(o,p)}`),y.join(`
|
|
23
|
+
|
|
24
|
+
`)}}return se(K(e,{type:"webhooks"}),"Path not found. Available webhooks")}let a=i;a.startsWith("api.")&&(a=a.slice(4));let d=N(s.endpointMeta,a),c=N(s.endpointSchemas,a);if(d||c){let l=[],p=[d?.riskLevel?`[${d.riskLevel}]`:"",d?.irreversible?"[irreversible]":""].filter(Boolean).join(" "),h=[d?.description,p].filter(Boolean).join(" ");return h&&l.push(h),c?.input&&l.push(`input ${W(c.input,0)}`),c?.output&&l.push(`output ${W(c.output,0)}`),l.join(`
|
|
25
|
+
|
|
26
|
+
`)}}}return se(K(e),"Path not found. Available operations")}function Oe(e){let t=e;for(;;){let n=t._def,r=n.typeName;if(r==="ZodOptional"||r==="ZodNullable"||r==="ZodDefault"){t=n.innerType;continue}if(r==="ZodEffects"){t=n.schema;continue}return t}}function ae(e){if(e===void 0)return{kind:"inline",type:"unknown"};let t=Oe(e),n=t._def;if(n.typeName==="ZodObject"){let o=n.shape(),i=[];for(let[s,a]of Object.entries(o)){let c=a._def.typeName,l=c==="ZodOptional"||c==="ZodNullable",p=Oe(a),f=p._def?.description;i.push({key:s,optional:l,type:A(p),description:f})}return{kind:"object",fields:i}}return{kind:"inline",type:A(t)}}function nn(e,t){let n=K(e,{plugin:t,type:"api"});if(typeof n=="string")return{ok:!1,error:n};if(!Array.isArray(n))return{ok:!1,error:"list_operations did not return a path array \u2014 pass a configured plugin id."};let r=e.find(l=>l.id===t);if(!r)return{ok:!1,error:`Plugin "${t}" is not configured on this instance.`};let o=[];for(let l of n){let{shortPath:p,lookupKey:h}=en(l,t),f=N(r.endpointMeta,h),u=N(r.endpointSchemas,h);!f&&!u||o.push({path:l,shortPath:p,description:f?.description,riskLevel:f?.riskLevel,irreversible:f?.irreversible,input:ae(u?.input),output:ae(u?.output)})}o.sort((l,p)=>l.path.localeCompare(p.path));let i=[],s=K(e,{plugin:t,type:"webhooks"});if(Array.isArray(s)&&r.webhooks)for(let l of s){let h=l.toLowerCase().slice(t.length+1),f=h.startsWith(".")?h.slice(1):h;if(!f.startsWith("webhooks."))continue;let u=f.slice(9),y=ge(r.webhooks,u.split("."));if(y===null)continue;let m=y.join("."),w=N(r.webhookSchemas,m.toLowerCase()),P=w?.response?A(w.response):void 0;i.push({path:l,description:w?.description,payload:ae(w?.payload),responseType:P,usageExample:$e(t,y)})}i.sort((l,p)=>l.path.localeCompare(p.path));let a=[],d=K(e,{plugin:t,type:"db"}),c=r.schema?.entities;if(Array.isArray(d)&&c)for(let l of d){let h=l.toLowerCase().slice(t.length+1),f=h.startsWith(".")?h.slice(1):h;if(!f.startsWith("db."))continue;let u=f.slice(3),y=u.lastIndexOf(".");if(y===-1)continue;let m=u.slice(0,y);if(u.slice(y+1)!=="search")continue;let P=Ke(c,m);if(!P)continue;let[b,g]=P,k=J(g),T=Object.entries(k).map(([R,C])=>({field:R,type:C.type,operators:C.operators}));a.push({path:l,entityName:b,filters:[{field:"entity_id",type:"string",operators:pe},...T]})}return a.sort((l,p)=>l.path.localeCompare(p.path)),{ok:!0,data:{pluginId:t,api:o,webhooks:i,db:a}}}var fe=Symbol.for("corsair:internal");function Wn(e){let t=e.database?ye(e.database):void 0,n=t&&e.kek?_e(e.plugins,t,e.kek):q(!!t,!!e.kek),r={plugins:e.plugins,database:t,kek:e.kek,multiTenancy:!!e.multiTenancy,approval:e.approval},o=Re(t);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=ie(e.plugins,{database:t,tenantId:s,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval});return Object.assign(a,{[fe]:r})},keys:n,permissions:o},{[fe]:r});let i=ie(e.plugins,{database:t,tenantId:void 0,kek:e.kek,rootErrorHandlers:e.errorHandlers,approvalConfig:e.approval});return Object.assign({},i,{keys:n,permissions:o,[fe]:r})}export{v as a,F as b,D as c,ee as d,ne as e,M as f,O as g,Z as h,j as i,G as j,V as k,Ce as l,Pe as m,De as n,Ve as o,ve as p,K as q,Sn as r,nn as s,fe as t,Wn as u};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{t as k,u as w}from"./chunk-34FMIFYP.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,7 +1,7 @@
|
|
|
1
|
-
export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, c as createCorsair } from './index-
|
|
1
|
+
export { C as CORSAIR_INTERNAL, a as CorsairInternalConfig, D as DocSchemaFieldRow, b as DocSchemaShape, d as DocsApiEndpoint, e as DocsDbEntity, f as DocsDbFilterField, g as DocsWebhook, E as EndpointSchemaResult, I as IntrospectPluginForDocsResult, L as ListOperationsOptions, P as PluginDocsIntrospection, c as createCorsair, i as introspectPluginForDocs } from './index-DWGwcIFp.js';
|
|
2
2
|
import { CorsairDatabase } from './db.js';
|
|
3
|
-
import { A as AuthTypes,
|
|
4
|
-
export {
|
|
3
|
+
import { A as AuthTypes, d as AccountKeyManagerFor, I as IntegrationKeyManagerFor } from './index-DhJiJ1ZE.js';
|
|
4
|
+
export { e as AccountFieldNames, j as AllProviders, h as BASE_AUTH_FIELDS, B as BaseAuthFieldConfig, f as BaseKeyManager, k as BaseProviders, G as BeforeHookResult, m as BindEndpoints, a0 as BindWebhooks, _ as Bivariant, n as BoundEndpointFn, o as BoundEndpointTree, a1 as BoundWebhook, a2 as BoundWebhookTree, i as CorsairClient, p as CorsairContext, q as CorsairEndpoint, t as CorsairErrorHandler, a as CorsairIntegration, H as CorsairKeyBuilder, J as CorsairKeyBuilderBase, z as CorsairPermissionsNamespace, C as CorsairPlugin, K as CorsairPluginContext, c as CorsairSingleTenantClient, b as CorsairTenantWrapper, a3 as CorsairWebhook, a4 as CorsairWebhookHandler, a5 as CorsairWebhookMatcher, L as EndpointHooks, M as EndpointMetaEntry, r as EndpointPathsOf, E as EndpointRiskLevel, s as EndpointTree, D as EnforcePermissionOptions, F as EnforcePermissionResult, u as ErrorContext, v as ErrorHandler, w as ErrorHandlerAndMatchFunction, x as ErrorMatcher, g as IntegrationFieldNames, N as KeyBuilderContext, O as OAuth2IntegrationCredentials, Q as OAuthConfig, S as PermissionMode, T as PermissionPolicy, l as PickAuth, P as PluginAuthConfig, U as PluginEndpointMeta, V as PluginPermissionsConfig, a6 as RawWebhookRequest, W as RequiredPluginEndpointMeta, X as RequiredPluginEndpointSchemas, Y as RequiredPluginWebhookSchemas, R as RetryStrategies, y as RetryStrategy, $ as UnionToIntersection, Z as WebhookHooks, a7 as WebhookPathsOf, a8 as WebhookRequest, a9 as WebhookResponse, aa as WebhookTree } from './index-DhJiJ1ZE.js';
|
|
5
5
|
import 'kysely';
|
|
6
6
|
import 'zod';
|
|
7
7
|
import 'pg';
|
package/dist/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b,c,d,e,f,g,h,i,j,k,l,m,o as
|
|
1
|
+
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,s as p,t as q,u as r}from"./chunk-34FMIFYP.js";import"./chunk-2PB34FTK.js";import"./chunk-ZGVIF3UY.js";import"./chunk-QAIKSQAD.js";export{i as BASE_AUTH_FIELDS,q as CORSAIR_INTERNAL,k as createAccountKeyManager,r 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,p as introspectPluginForDocs,n as logEvent,o as logEventFromContext,h as reEncryptConfig};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { E as EndpointRiskLevel, C as CorsairPlugin, a as CorsairIntegration, b as CorsairTenantWrapper, c as CorsairSingleTenantClient } from './index-DhJiJ1ZE.js';
|
|
2
|
+
import { CorsairDatabase } from './db.js';
|
|
3
|
+
|
|
4
|
+
/** @deprecated get_schema now returns a plain string. This type is kept for backwards compatibility. */
|
|
5
|
+
type EndpointSchemaResult = {
|
|
6
|
+
description?: string;
|
|
7
|
+
riskLevel?: 'read' | 'write' | 'destructive';
|
|
8
|
+
irreversible?: boolean;
|
|
9
|
+
input?: unknown;
|
|
10
|
+
output?: unknown;
|
|
11
|
+
availableMethods?: Record<string, string[]>;
|
|
12
|
+
};
|
|
13
|
+
type ListOperationsOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* Filter to a specific plugin by its ID (e.g. 'slack', 'github').
|
|
16
|
+
* - If the plugin is known but not added to the Corsair instance, a plain string message is returned.
|
|
17
|
+
* - If the string is completely unrecognised, returns all API endpoints as a fallback.
|
|
18
|
+
*/
|
|
19
|
+
plugin?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to list API endpoints, webhooks, or database entities.
|
|
22
|
+
* - 'api' (default) — lists callable API endpoint paths
|
|
23
|
+
* - 'webhooks' — lists receivable webhook event paths
|
|
24
|
+
* - 'db' — lists searchable database entity paths (one .search per entity type)
|
|
25
|
+
*/
|
|
26
|
+
type?: 'api' | 'webhooks' | 'db';
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* One row in an input/output table — typically a top-level Zod object property.
|
|
30
|
+
* Nested shapes are collapsed into {@link DocSchemaFieldRow.type} via `zodToInlineType`
|
|
31
|
+
* so tables stay scannable.
|
|
32
|
+
*/
|
|
33
|
+
type DocSchemaFieldRow = {
|
|
34
|
+
key: string;
|
|
35
|
+
optional: boolean;
|
|
36
|
+
/** TypeScript-like type string (nested objects stay on one line) */
|
|
37
|
+
type: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Either an object broken out as field rows, or a single inline type (arrays, unions, etc.).
|
|
42
|
+
*/
|
|
43
|
+
type DocSchemaShape = {
|
|
44
|
+
kind: 'object';
|
|
45
|
+
fields: DocSchemaFieldRow[];
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'inline';
|
|
48
|
+
type: string;
|
|
49
|
+
};
|
|
50
|
+
type DocsApiEndpoint = {
|
|
51
|
+
path: string;
|
|
52
|
+
/** Dot path after `plugin.api.` (e.g. `messages.post`) */
|
|
53
|
+
shortPath: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
riskLevel?: EndpointRiskLevel;
|
|
56
|
+
irreversible?: boolean;
|
|
57
|
+
input: DocSchemaShape;
|
|
58
|
+
output: DocSchemaShape;
|
|
59
|
+
};
|
|
60
|
+
type DocsWebhook = {
|
|
61
|
+
path: string;
|
|
62
|
+
description?: string;
|
|
63
|
+
payload: DocSchemaShape;
|
|
64
|
+
responseType?: string;
|
|
65
|
+
/** Ready-to-paste `webhookHooks` snippet (same idea as `get_schema` text output) */
|
|
66
|
+
usageExample: string;
|
|
67
|
+
};
|
|
68
|
+
type DocsDbFilterField = {
|
|
69
|
+
field: string;
|
|
70
|
+
type: 'string' | 'number' | 'boolean' | 'date';
|
|
71
|
+
operators: readonly string[];
|
|
72
|
+
};
|
|
73
|
+
type DocsDbEntity = {
|
|
74
|
+
path: string;
|
|
75
|
+
entityName: string;
|
|
76
|
+
/** Always includes the synthetic `entity_id` row first, then entity filter fields */
|
|
77
|
+
filters: DocsDbFilterField[];
|
|
78
|
+
};
|
|
79
|
+
type PluginDocsIntrospection = {
|
|
80
|
+
pluginId: string;
|
|
81
|
+
api: DocsApiEndpoint[];
|
|
82
|
+
webhooks: DocsWebhook[];
|
|
83
|
+
db: DocsDbEntity[];
|
|
84
|
+
};
|
|
85
|
+
type IntrospectPluginForDocsResult = {
|
|
86
|
+
ok: true;
|
|
87
|
+
data: PluginDocsIntrospection;
|
|
88
|
+
} | {
|
|
89
|
+
ok: false;
|
|
90
|
+
error: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Returns structured API, webhook, and DB operation metadata for a single plugin.
|
|
94
|
+
* Intended for **documentation generators** inside the Corsair repo (or tooling that depends
|
|
95
|
+
* on `corsair` as a library). It does not shell out to the CLI and does not require a
|
|
96
|
+
* `corsair.ts` file — pass the same `plugins` array you pass to `createCorsair`.
|
|
97
|
+
*
|
|
98
|
+
* Input/output shapes favour **small tables**: top-level object keys become rows; nested
|
|
99
|
+
* objects are rendered as compact inline types so pages do not overwhelm readers.
|
|
100
|
+
*/
|
|
101
|
+
declare function introspectPluginForDocs(plugins: readonly CorsairPlugin[], pluginId: string): IntrospectPluginForDocsResult;
|
|
102
|
+
|
|
103
|
+
declare const CORSAIR_INTERNAL: unique symbol;
|
|
104
|
+
type CorsairInternalConfig = {
|
|
105
|
+
plugins: readonly CorsairPlugin[];
|
|
106
|
+
database: CorsairDatabase | undefined;
|
|
107
|
+
kek: string;
|
|
108
|
+
multiTenancy: boolean;
|
|
109
|
+
approval?: {
|
|
110
|
+
timeout: string;
|
|
111
|
+
onTimeout: 'deny' | 'approve';
|
|
112
|
+
mode?: 'synchronous' | 'asynchronous';
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Creates a Corsair integration with multi-tenancy enabled.
|
|
117
|
+
* Returns a wrapper with a `withTenant()` method to scope operations to specific tenants,
|
|
118
|
+
* and a `keys` property for integration-level key management.
|
|
119
|
+
* @param config - Configuration with plugins, database, and multiTenancy: true
|
|
120
|
+
* @returns A tenant wrapper with `withTenant(tenantId)` method and integration-level `keys`
|
|
121
|
+
*/
|
|
122
|
+
declare function createCorsair<const Plugins extends readonly CorsairPlugin[]>(config: CorsairIntegration<Plugins> & {
|
|
123
|
+
multiTenancy: true;
|
|
124
|
+
}): CorsairTenantWrapper<Plugins>;
|
|
125
|
+
/**
|
|
126
|
+
* Creates a Corsair integration without multi-tenancy.
|
|
127
|
+
* Returns a direct client instance with both plugin APIs and integration-level keys.
|
|
128
|
+
* @param config - Configuration with plugins and optional database
|
|
129
|
+
* @returns A Corsair client instance with plugin APIs and integration-level `keys`
|
|
130
|
+
*/
|
|
131
|
+
declare function createCorsair<const Plugins extends readonly CorsairPlugin[]>(config: CorsairIntegration<Plugins> & {
|
|
132
|
+
multiTenancy?: false | undefined;
|
|
133
|
+
}): CorsairSingleTenantClient<Plugins>;
|
|
134
|
+
|
|
135
|
+
export { CORSAIR_INTERNAL as C, type DocSchemaFieldRow as D, type EndpointSchemaResult as E, type IntrospectPluginForDocsResult as I, type ListOperationsOptions as L, type PluginDocsIntrospection as P, type CorsairInternalConfig as a, type DocSchemaShape as b, createCorsair as c, type DocsApiEndpoint as d, type DocsDbEntity as e, type DocsDbFilterField as f, type DocsWebhook as g, introspectPluginForDocs as i };
|
|
@@ -3,8 +3,8 @@ import { CorsairPluginSchema, PluginEntityClients } from './orm.js';
|
|
|
3
3
|
import { CorsairDatabase, CorsairDatabaseInput, CorsairPermission } from './db.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", "box", "cal", "calendly", "cursor", "discord", "dodopayments", "dropbox", "exa", "figma", "firecrawl", "fireflies", "github", "gmail", "googlecalendar", "googledrive", "googlesheets", "hackernews", "hubspot", "intercom", "jira", "linear", "monday", "notion", "onedrive", "openweathermap", "oura", "outlook", "pagerduty", "posthog", "razorpay", "reddit", "resend", "sentry", "sharepoint", "slack", "spotify", "strava", "stripe", "tavily", "teams", "telegram", "todoist", "trello", "twitter", "twitterapiio", "typeform", "youtube", "zoom"];
|
|
7
|
-
type AllProviders = 'airtable' | 'amplitude' | 'asana' | 'box' | 'cal' | 'calendly' | 'cursor' | 'discord' | 'dodopayments' | 'dropbox' | 'exa' | 'figma' | 'firecrawl' | 'fireflies' | 'github' | 'gmail' | 'googlecalendar' | 'googledrive' | 'googlesheets' | 'hackernews' | 'hubspot' | 'intercom' | 'jira' | 'linear' | 'monday' | 'notion' | 'onedrive' | 'openweathermap' | 'oura' | 'outlook' | 'pagerduty' | 'posthog' | 'razorpay' | 'reddit' | 'resend' | 'sentry' | 'sharepoint' | 'slack' | 'spotify' | 'strava' | 'stripe' | 'tavily' | 'teams' | 'telegram' | 'todoist' | 'trello' | 'twitter' | 'twitterapiio' | 'typeform' | 'youtube' | 'zoom' | (string & {});
|
|
6
|
+
declare const BaseProviders: readonly ["ably", "airtable", "amplitude", "asana", "box", "cal", "calendly", "cursor", "discord", "dodopayments", "dropbox", "exa", "figma", "firecrawl", "fireflies", "github", "gmail", "googlecalendar", "googledrive", "googlesheets", "hackernews", "hubspot", "intercom", "jira", "linear", "monday", "notion", "onedrive", "openweathermap", "oura", "outlook", "pagerduty", "posthog", "razorpay", "reddit", "resend", "sentry", "sharepoint", "slack", "spotify", "strava", "stripe", "tavily", "teams", "telegram", "todoist", "trello", "twitter", "twitterapiio", "typeform", "youtube", "zoom"];
|
|
7
|
+
type AllProviders = 'ably' | 'airtable' | 'amplitude' | 'asana' | 'box' | 'cal' | 'calendly' | 'cursor' | 'discord' | 'dodopayments' | 'dropbox' | 'exa' | 'figma' | 'firecrawl' | 'fireflies' | 'github' | 'gmail' | 'googlecalendar' | 'googledrive' | 'googlesheets' | 'hackernews' | 'hubspot' | 'intercom' | 'jira' | 'linear' | 'monday' | 'notion' | 'onedrive' | 'openweathermap' | 'oura' | 'outlook' | 'pagerduty' | 'posthog' | 'razorpay' | 'reddit' | 'resend' | 'sentry' | 'sharepoint' | 'slack' | 'spotify' | 'strava' | 'stripe' | 'tavily' | 'teams' | 'telegram' | 'todoist' | 'trello' | 'twitter' | 'twitterapiio' | 'typeform' | 'youtube' | 'zoom' | (string & {});
|
|
8
8
|
type AuthTypes = 'oauth_2' | 'api_key' | 'bot_token';
|
|
9
9
|
type PickAuth<T extends AuthTypes> = T;
|
|
10
10
|
|
|
@@ -914,88 +914,19 @@ type CorsairIntegration<Plugins extends readonly CorsairPlugin[]> = {
|
|
|
914
914
|
* - `'approve'` → the action is automatically approved (use only in low-risk setups)
|
|
915
915
|
*/
|
|
916
916
|
onTimeout: 'deny' | 'approve';
|
|
917
|
+
/**
|
|
918
|
+
* How approval requests are handled when execution is blocked.
|
|
919
|
+
* - `'synchronous'` → the tool call blocks (polls the DB) until the user approves or denies.
|
|
920
|
+
* The model is unaware anything happened — it just sees a slow tool call.
|
|
921
|
+
* On denial, the tool returns an error and the model stops.
|
|
922
|
+
* - `'asynchronous'` → the tool call returns immediately with a blocked result.
|
|
923
|
+
* The model must handle the denial and stop on its own.
|
|
924
|
+
* Defaults to `'asynchronous'` if not specified.
|
|
925
|
+
*/
|
|
926
|
+
mode?: 'synchronous' | 'asynchronous';
|
|
917
927
|
};
|
|
918
928
|
};
|
|
919
929
|
|
|
920
|
-
/** @deprecated get_schema now returns a plain string. This type is kept for backwards compatibility. */
|
|
921
|
-
type EndpointSchemaResult = {
|
|
922
|
-
description?: string;
|
|
923
|
-
riskLevel?: 'read' | 'write' | 'destructive';
|
|
924
|
-
irreversible?: boolean;
|
|
925
|
-
input?: unknown;
|
|
926
|
-
output?: unknown;
|
|
927
|
-
availableMethods?: Record<string, string[]>;
|
|
928
|
-
};
|
|
929
|
-
type ListOperationsOptions = {
|
|
930
|
-
/**
|
|
931
|
-
* Filter to a specific plugin by its ID (e.g. 'slack', 'github').
|
|
932
|
-
* - If the plugin is known but not added to the Corsair instance, a plain string message is returned.
|
|
933
|
-
* - If the string is completely unrecognised, returns all API endpoints as a fallback.
|
|
934
|
-
*/
|
|
935
|
-
plugin?: string;
|
|
936
|
-
/**
|
|
937
|
-
* Whether to list API endpoints, webhooks, or database entities.
|
|
938
|
-
* - 'api' (default) — lists callable API endpoint paths
|
|
939
|
-
* - 'webhooks' — lists receivable webhook event paths
|
|
940
|
-
* - 'db' — lists searchable database entity paths (one .search per entity type)
|
|
941
|
-
*/
|
|
942
|
-
type?: 'api' | 'webhooks' | 'db';
|
|
943
|
-
};
|
|
944
|
-
type CorsairInspectMethods = {
|
|
945
|
-
/**
|
|
946
|
-
* Lists available operations (API endpoints, webhooks, or database entities) for the configured plugins.
|
|
947
|
-
*
|
|
948
|
-
* - No options → all API endpoint paths across every plugin, keyed by plugin ID
|
|
949
|
-
* - `{ type: 'webhooks' }` → all webhook paths across every plugin, keyed by plugin ID
|
|
950
|
-
* - `{ type: 'db' }` → all searchable DB entity paths across every plugin, keyed by plugin ID
|
|
951
|
-
* - `{ plugin: 'slack' }` → Slack API endpoint paths as a flat array
|
|
952
|
-
* - `{ plugin: 'slack', type: 'webhooks' }` → Slack webhook paths as a flat array
|
|
953
|
-
* - `{ plugin: 'slack', type: 'db' }` → Slack DB entity search paths as a flat array
|
|
954
|
-
* - If the plugin is known but not configured, returns a plain string message.
|
|
955
|
-
* - If the plugin string is completely unrecognised, returns all API endpoints (same as no options).
|
|
956
|
-
*
|
|
957
|
-
* API paths use the format `plugin.api.group.method` (e.g. `slack.api.messages.post`).
|
|
958
|
-
* Webhook paths use the format `plugin.webhooks.group.event` (e.g. `slack.webhooks.messages.message`).
|
|
959
|
-
* DB paths use the format `plugin.db.entityType.search` (e.g. `slack.db.messages.search`).
|
|
960
|
-
* All paths can be passed directly to `get_schema()`.
|
|
961
|
-
*
|
|
962
|
-
* @example
|
|
963
|
-
* corsair.list_operations()
|
|
964
|
-
* // { slack: ['slack.api.channels.list', 'slack.api.messages.post', ...], ... }
|
|
965
|
-
*
|
|
966
|
-
* corsair.list_operations({ plugin: 'slack' })
|
|
967
|
-
* // ['slack.api.channels.list', 'slack.api.messages.post', ...]
|
|
968
|
-
*
|
|
969
|
-
* corsair.list_operations({ plugin: 'slack', type: 'webhooks' })
|
|
970
|
-
* // ['slack.webhooks.messages.message', 'slack.webhooks.channels.created', ...]
|
|
971
|
-
*
|
|
972
|
-
* corsair.list_operations({ plugin: 'slack', type: 'db' })
|
|
973
|
-
* // ['slack.db.messages.search', 'slack.db.channels.search', 'slack.db.users.search', ...]
|
|
974
|
-
*
|
|
975
|
-
* corsair.list_operations({ plugin: 'unknown' })
|
|
976
|
-
* // "unknown isn't configured in the Corsair instance."
|
|
977
|
-
*/
|
|
978
|
-
list_operations(options?: ListOperationsOptions): Record<string, string[]> | string[] | string;
|
|
979
|
-
/**
|
|
980
|
-
* Returns a plain-text TypeScript-style type declaration for a specific operation path.
|
|
981
|
-
* The path format determines which kind of schema is returned:
|
|
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
|
|
985
|
-
*
|
|
986
|
-
* Casing is ignored — the path is lowercased before lookup.
|
|
987
|
-
* If the path is not found, returns a list of available paths for self-correction.
|
|
988
|
-
*
|
|
989
|
-
* @example
|
|
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 ..."
|
|
992
|
-
*
|
|
993
|
-
* corsair.get_schema('slack.api.invalid')
|
|
994
|
-
* // "Path not found. Available operations:\n slack: slack.api.channels.list, ..."
|
|
995
|
-
*/
|
|
996
|
-
get_schema(path: string): string;
|
|
997
|
-
};
|
|
998
|
-
|
|
999
930
|
/**
|
|
1000
931
|
* The `corsair.permissions` namespace available at the root of every corsair instance.
|
|
1001
932
|
* Provides methods for querying and transitioning permission records.
|
|
@@ -1041,6 +972,13 @@ type EnforcePermissionOptions = {
|
|
|
1041
972
|
timeoutMs?: number;
|
|
1042
973
|
/** Tenant ID for multi-tenant instances. Stored on the record so executePermission can scope correctly. Defaults to 'default'. */
|
|
1043
974
|
tenantId?: string;
|
|
975
|
+
/**
|
|
976
|
+
* Controls whether the call blocks until the user approves or denies.
|
|
977
|
+
* - `'synchronous'` → polls the DB every 500 ms; returns 'allow' on approval, 'blocked' on denial/timeout.
|
|
978
|
+
* - `'asynchronous'` → returns 'blocked' immediately after creating the pending record (legacy behaviour).
|
|
979
|
+
* Defaults to `'asynchronous'`.
|
|
980
|
+
*/
|
|
981
|
+
approvalMode?: 'synchronous' | 'asynchronous';
|
|
1044
982
|
};
|
|
1045
983
|
type EnforcePermissionResult = {
|
|
1046
984
|
result: 'allow' | 'blocked';
|
|
@@ -1131,13 +1069,11 @@ type InferAllIntegrationKeys<Plugins extends readonly CorsairPlugin[]> = UnionTo
|
|
|
1131
1069
|
type InferPluginNamespaces<Plugins extends readonly CorsairPlugin[]> = UnionToIntersection<InferPluginNamespace<Plugins[number]>>;
|
|
1132
1070
|
/**
|
|
1133
1071
|
* The main Corsair client type that provides access to all plugin APIs, entities, webhooks, and keys.
|
|
1134
|
-
* Also includes list_operations() and get_schema() for agent-facing endpoint discovery.
|
|
1135
1072
|
*/
|
|
1136
|
-
type CorsairClient<Plugins extends readonly CorsairPlugin[]> = InferPluginNamespaces<Plugins
|
|
1073
|
+
type CorsairClient<Plugins extends readonly CorsairPlugin[]> = InferPluginNamespaces<Plugins>;
|
|
1137
1074
|
/**
|
|
1138
1075
|
* Multi-tenant wrapper that provides a `withTenant` method to scope operations to a specific tenant.
|
|
1139
1076
|
* Also includes integration-level `keys` for managing shared secrets (OAuth2 client credentials, etc.)
|
|
1140
|
-
* Inspect methods (list_operations / get_schema) are available at the root — no need to call withTenant().
|
|
1141
1077
|
*/
|
|
1142
1078
|
type CorsairTenantWrapper<Plugins extends readonly CorsairPlugin[]> = {
|
|
1143
1079
|
withTenant: (tenantId: string) => CorsairClient<Plugins>;
|
|
@@ -1151,7 +1087,7 @@ type CorsairTenantWrapper<Plugins extends readonly CorsairPlugin[]> = {
|
|
|
1151
1087
|
* Available at the root regardless of multi-tenancy setting.
|
|
1152
1088
|
*/
|
|
1153
1089
|
permissions: CorsairPermissionsNamespace;
|
|
1154
|
-
}
|
|
1090
|
+
};
|
|
1155
1091
|
/**
|
|
1156
1092
|
* Single-tenant client that includes both plugin APIs and integration-level keys.
|
|
1157
1093
|
*/
|
|
@@ -1168,4 +1104,4 @@ type CorsairSingleTenantClient<Plugins extends readonly CorsairPlugin[]> = Corsa
|
|
|
1168
1104
|
permissions: CorsairPermissionsNamespace;
|
|
1169
1105
|
};
|
|
1170
1106
|
|
|
1171
|
-
export { type
|
|
1107
|
+
export { type UnionToIntersection$1 as $, type AuthTypes as A, type BaseAuthFieldConfig as B, type CorsairPlugin as C, type EnforcePermissionOptions as D, type EndpointRiskLevel as E, type EnforcePermissionResult as F, type BeforeHookResult as G, type CorsairKeyBuilder as H, type IntegrationKeyManagerFor as I, type CorsairKeyBuilderBase as J, type CorsairPluginContext as K, type EndpointHooks as L, type EndpointMetaEntry as M, type KeyBuilderContext as N, type OAuth2IntegrationCredentials as O, type PluginAuthConfig as P, type OAuthConfig as Q, type RetryStrategies as R, type PermissionMode as S, type PermissionPolicy as T, type PluginEndpointMeta as U, type PluginPermissionsConfig as V, type RequiredPluginEndpointMeta as W, type RequiredPluginEndpointSchemas as X, type RequiredPluginWebhookSchemas as Y, type WebhookHooks as Z, type Bivariant$2 as _, type CorsairIntegration as a, type BindWebhooks as a0, type BoundWebhook as a1, type BoundWebhookTree as a2, type CorsairWebhook as a3, type CorsairWebhookHandler as a4, type CorsairWebhookMatcher as a5, type RawWebhookRequest as a6, type WebhookPathsOf as a7, type WebhookRequest as a8, type WebhookResponse as a9, type WebhookTree as aa, type CorsairTenantWrapper as b, type CorsairSingleTenantClient as c, type AccountKeyManagerFor as d, type AccountFieldNames as e, type BaseKeyManager as f, type IntegrationFieldNames as g, BASE_AUTH_FIELDS as h, type CorsairClient as i, type AllProviders as j, BaseProviders as k, type PickAuth as l, type BindEndpoints as m, type BoundEndpointFn as n, type BoundEndpointTree as o, type CorsairContext as p, type CorsairEndpoint as q, type EndpointPathsOf as r, type EndpointTree as s, type CorsairErrorHandler as t, type ErrorContext as u, type ErrorHandler as v, type ErrorHandlerAndMatchFunction as w, type ErrorMatcher as x, type RetryStrategy as y, type CorsairPermissionsNamespace as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { L as ListOperationsOptions } from './index-DWGwcIFp.js';
|
|
2
|
+
export { c as createCorsair } from './index-DWGwcIFp.js';
|
|
3
|
+
import { c as CorsairSingleTenantClient, C as CorsairPlugin, b as CorsairTenantWrapper, i as CorsairClient, z as CorsairPermissionsNamespace, a2 as BoundWebhookTree, a6 as RawWebhookRequest, k as BaseProviders, a9 as WebhookResponse } from './index-DhJiJ1ZE.js';
|
|
3
4
|
export { SetupCorsairOptions, setupCorsair } from './setup.js';
|
|
4
5
|
import './db.js';
|
|
5
6
|
import 'kysely';
|
|
@@ -8,6 +9,46 @@ import 'pg';
|
|
|
8
9
|
import 'postgres';
|
|
9
10
|
import './orm.js';
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Any form of Corsair instance:
|
|
14
|
+
* - single-tenant client (`createCorsair({ ... })`)
|
|
15
|
+
* - multi-tenant wrapper (`createCorsair({ multiTenancy: true, ... })`)
|
|
16
|
+
* - tenant-scoped client (`corsair.withTenant("tenant-id")`)
|
|
17
|
+
*/
|
|
18
|
+
type AnyCorsairInstance = CorsairSingleTenantClient<readonly CorsairPlugin[]> | CorsairTenantWrapper<readonly CorsairPlugin[]> | CorsairClient<readonly CorsairPlugin[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Lists available operations (API endpoints, webhooks, or database entities) for the configured plugins.
|
|
21
|
+
* Returns a newline-separated string with one operation path per line.
|
|
22
|
+
*
|
|
23
|
+
* Accepts single-tenant instances, multi-tenant wrappers, and tenant-scoped clients.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* listOperations(corsair)
|
|
27
|
+
* // "slack.api.channels.list\nslack.api.messages.post\n..."
|
|
28
|
+
*
|
|
29
|
+
* listOperations(corsair, { plugin: 'slack' })
|
|
30
|
+
* // "slack.api.channels.list\nslack.api.messages.post\n..."
|
|
31
|
+
*
|
|
32
|
+
* listOperations(corsair, { plugin: 'slack', type: 'webhooks' })
|
|
33
|
+
* // "slack.webhooks.messages.message\nslack.webhooks.channels.created\n..."
|
|
34
|
+
*/
|
|
35
|
+
declare function listOperations(corsair: AnyCorsairInstance, options?: ListOperationsOptions): string;
|
|
36
|
+
/**
|
|
37
|
+
* Returns a plain-text TypeScript-style type declaration for a specific operation path.
|
|
38
|
+
*
|
|
39
|
+
* Accepts single-tenant instances, multi-tenant wrappers, and tenant-scoped clients.
|
|
40
|
+
* Casing is ignored — the path is lowercased before lookup.
|
|
41
|
+
* If the path is not found, returns a list of available paths for self-correction.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* getSchema(corsair, 'slack.api.messages.post')
|
|
45
|
+
* // "Post a message to a channel [write]\n\ninput {\n channel: string\n text?: string\n ..."
|
|
46
|
+
*
|
|
47
|
+
* getSchema(corsair, 'slack.api.invalid')
|
|
48
|
+
* // "Path not found. Available operations:\n slack: slack.api.channels.list, ..."
|
|
49
|
+
*/
|
|
50
|
+
declare function getSchema(corsair: AnyCorsairInstance, path: string): string;
|
|
51
|
+
|
|
11
52
|
/**
|
|
12
53
|
* The corsair instance type for permission execution.
|
|
13
54
|
* Must expose the `permissions` namespace and optionally a `withTenant` method.
|
|
@@ -113,4 +154,4 @@ declare function processWebhook(corsair: CorsairInstance, headers: WebhookHeader
|
|
|
113
154
|
[x: string]: string | string[] | undefined;
|
|
114
155
|
}): Promise<WebhookFilterResult>;
|
|
115
156
|
|
|
116
|
-
export { type PermissionExecuteResult, executePermission, processWebhook };
|
|
157
|
+
export { type AnyCorsairInstance, ListOperationsOptions, type PermissionExecuteResult, executePermission, getSchema, listOperations, processWebhook };
|
package/dist/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as I}from"./chunk-4UXFAV2B.js";import{p as m,q as k,r as b,t as y,u as P}from"./chunk-34FMIFYP.js";import"./chunk-7IH5DNUL.js";import"./chunk-2PB34FTK.js";import"./chunk-HO245J34.js";import"./chunk-ZGVIF3UY.js";import"./chunk-QAIKSQAD.js";function w(n){let r=n[y];if(!r)throw new Error("listOperations / getSchema: invalid corsair instance. Pass the value returned by createCorsair() or corsair.withTenant().");return r.plugins}function O(n,r){let o=k(w(n),r);return typeof o=="string"?o:Array.isArray(o)?o.join(`
|
|
2
|
+
`):Object.values(o).flat().join(`
|
|
3
|
+
`)}function S(n,r){return b(w(n),r)}var T=Symbol.for("corsair:internal");function B(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 x(n){return n[T]?.database}async function A(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=x(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 p=B(g.api,e.endpoint.split("."));if(!p)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 p(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=x(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 E(n){return n!==null&&typeof n=="object"&&"match"in n&&"handler"in n&&typeof n.match=="function"&&typeof n.handler=="function"}function C(n,r,o=[]){for(let[e,t]of Object.entries(n))if(E(t)){if(t.match(r))return{webhook:t,path:[...o,e]}}else if(t&&typeof t=="object"){let s=C(t,r,[...o,e]);if(s)return s}return null}function $(n){let r={};for(let[o,e]of Object.entries(n))r[o.toLowerCase()]=Array.isArray(e)?e[0]:e;return r}function j(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 _(n,r,o,e){let t=$(r),s=typeof o=="string"?JSON.parse(o):o;(!s||typeof s=="object"&&Object.keys(s).length===0)&&t["x-goog-resource-uri"]&&(s=j(t)||s);let p={headers:t,body:s},i=e?.tenantId||"default",u=n.withTenant?n.withTenant(i):n,d=m;for(let l of d){let c=u[l];if(!c||!c.webhooks||c.pluginWebhookMatcher&&!c.pluginWebhookMatcher(p))continue;let f=C(c.webhooks,p);if(!f)continue;let h=f.path.join("."),R={payload:s,headers:t,rawBody:typeof o=="string"?o:JSON.stringify(o)};try{let a=await f.webhook.handler(R),W=!!Object.keys(a.returnToSender||{})?.length;return{plugin:l,action:h,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}.${h}:`,a),{plugin:l,action:h,body:s,response:{success:!1,error:a instanceof Error?a.message:"Unknown error"}}}}return{plugin:null,action:null,body:null}}export{P as createCorsair,A as executePermission,S as getSchema,O as listOperations,_ as processWebhook,I as setupCorsair};
|
package/dist/setup.d.ts
CHANGED
package/dist/setup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as o}from"./chunk-
|
|
1
|
+
import{a as o}from"./chunk-4UXFAV2B.js";import"./chunk-34FMIFYP.js";import"./chunk-7IH5DNUL.js";import"./chunk-2PB34FTK.js";import"./chunk-HO245J34.js";import"./chunk-ZGVIF3UY.js";import"./chunk-QAIKSQAD.js";export{o as setupCorsair};
|
package/package.json
CHANGED
package/dist/chunk-7QIX3IRP.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import{a as pe,b as Q}from"./chunk-2PB34FTK.js";import{a as ge}from"./chunk-ZGVIF3UY.js";import{createCipheriv as fe,createDecipheriv as ye,randomBytes as H,scrypt as Ke}from"crypto";import{promisify as $e}from"util";var he=$e(Ke),U="aes-256-gcm",me=12,z=16,Me=16,B=32;function O(){return H(B).toString("base64")}async function K(e,t){let n=H(Me),r=await he(t,n,B),o=H(me),i=fe(U,r,o,{authTagLength:z}),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:z});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:z}),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:z});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 $(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=$(e,t);return F(r,n)}function q(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,p)};return{get_dek:f,issue_new_dek:async()=>{let u=await d.getIntegration(),p=O(),m={};if(u.dek){let P=await D(u.dek,r),b=u.config;b&&Object.keys(b).length>0&&(m=S(b,P,p))}let w=await K(p,r);return await d.updateIntegration({config:m,dek:w}),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 w={...m};for(let[b,l]of Object.entries(u))l===null?delete w[b]:w[b]=l;let P=F(w,p);await d.updateIntegration({config:P})},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(),C=l.config;return!C||Object.keys(C).length===0?{}:$(C,k)},w=async()=>{let l=await c.getIntegration(),k=await p(),C=l.config;return!C||Object.keys(C).length===0?{}:$(C,k)},b={get_dek:u,issue_new_dek:async()=>{let l=await c.getAccount(),k=O(),C={};if(l.dek){let A=await D(l.dek,o),x=l.config;x&&Object.keys(x).length>0&&(C=S(x,A,k))}let I=await K(k,o);return await c.updateAccount({config:C,dek:I}),y=k,k},...ke(m,async l=>{let k=await u(),C;try{C=await m()}catch(x){console.error(`[corsair] Failed to decrypt config for account (tenant: "${r}", integration: "${n}"), starting fresh:`,x),C={}}let I={...C};for(let[x,T]of Object.entries(l))T===null?delete I[x]:I[x]=T;let A=F(I,k);await c.updateAccount({config:A})},a)};return t==="oauth_2"&&(b.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}}),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,w=[...s,h].join("."),P=async(b={})=>{let l;if(d){let T=g?.[w],{result:v,onComplete:E}=await xe({pluginId:o,endpointPath:w,args:b,mode:d.mode,override:d.overrides?.[w],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 M=await Ce(N,o,w,typeof E=="object"&&E!==null?E:{args:E},i);if(T<(M.maxRetries||0)){let L=T+1;console.log(`Retrying (${L} / ${M.maxRetries})...`);let _;if(M.headersRetryAfterMs)_=M.headersRetryAfterMs;else switch(M.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}:${w}] Retry strategy:`,M)}}throw N}},C=a?await a(n,"endpoint"):void 0;if(!m?.before&&!m?.after){let T=await k(0,{...n,key:C},b);return await l?.(),T}let I={...n,key:C},A=m.before?await m.before(I,b):{ctx:I,args:b,continue:!0,passToAfter:void 0};if(A.continue===!1)return;let x=await k(0,A.ctx,A.args);return await m.after?.(A.ctx,x,A.passToAfter),await l?.(),x};r[h]=P}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","cursor","discord","dodopayments","dropbox","exa","figma","firecrawl","fireflies","github","gmail","googlecalendar","googledrive","googlesheets","hackernews","hubspot","intercom","jira","linear","monday","notion","onedrive","openweathermap","oura","outlook","pagerduty","posthog","razorpay","reddit","resend","sentry","sharepoint","slack","spotify","strava","stripe","tavily","teams","telegram","todoist","trello","twitter","twitterapiio","typeform","youtube","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":{let r=t.type,i=r._def.typeName==="ZodUnion",s=R(r);return`${i?`(${s})`:s}[]`}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,m=p?._def,w=m?.typeName,P=m?.description,b=P?` // ${P}`:"";w==="ZodObject"?d.push(`${s}${u}: ${j(p,t+1)}${b}`):d.push(`${s}${u}: ${R(f)}${b}`)}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 ze(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 qe=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 qe.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,w]=p,P=se(w),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(P))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
|
-
${ze(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,w;if(n&&o&&p?.authType){let T=m?.[p.authType]?.account??[];w=V({authType:p.authType,integrationName:c.id,tenantId:h,kek:o,database:n,extraAccountFields:T}),a[c.id].keys=w}let P={database:n,db:d[c.id]?.db??{},$getAccountId:u,...c.options?{options:c.options}:{},...w?{keys:w,authType:p?.authType}:{},...r?{tenantId:r}:{}},b=c.endpoints??{},l=c.hooks,k={...i,...c.errorHandlers},C={},I=c.options?.permissions;te({endpoints:b,hooks:l,ctx:P,tree:C,pluginId:c.id,errorHandlers:k,currentPath:[],keyBuilder:c.keyBuilder,permissionsConfig:I,endpointMeta:c.endpointMeta,database:n,approvalConfig:s,tenantId:r}),Object.keys(C).length>0&&(a[c.id].api=C),P.endpoints=C;let A=c.webhooks??{},x=c.webhookHooks;if(Object.keys(A).length>0){let T={};ue({webhooks:A,hooks:x,ctx:P,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):q(!!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,$ 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};
|
package/dist/index-BRo0KrXQ.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { CorsairDatabase } from './db.js';
|
|
2
|
-
import { C as CorsairPlugin, a as CorsairIntegration, b as CorsairTenantWrapper, c as CorsairSingleTenantClient } from './index-DVL--3eB.js';
|
|
3
|
-
|
|
4
|
-
declare const CORSAIR_INTERNAL: unique symbol;
|
|
5
|
-
type CorsairInternalConfig = {
|
|
6
|
-
plugins: readonly CorsairPlugin[];
|
|
7
|
-
database: CorsairDatabase | undefined;
|
|
8
|
-
kek: string;
|
|
9
|
-
multiTenancy: boolean;
|
|
10
|
-
approval?: {
|
|
11
|
-
timeout: string;
|
|
12
|
-
onTimeout: 'deny' | 'approve';
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Creates a Corsair integration with multi-tenancy enabled.
|
|
17
|
-
* Returns a wrapper with a `withTenant()` method to scope operations to specific tenants,
|
|
18
|
-
* and a `keys` property for integration-level key management.
|
|
19
|
-
* @param config - Configuration with plugins, database, and multiTenancy: true
|
|
20
|
-
* @returns A tenant wrapper with `withTenant(tenantId)` method and integration-level `keys`
|
|
21
|
-
*/
|
|
22
|
-
declare function createCorsair<const Plugins extends readonly CorsairPlugin[]>(config: CorsairIntegration<Plugins> & {
|
|
23
|
-
multiTenancy: true;
|
|
24
|
-
}): CorsairTenantWrapper<Plugins>;
|
|
25
|
-
/**
|
|
26
|
-
* Creates a Corsair integration without multi-tenancy.
|
|
27
|
-
* Returns a direct client instance with both plugin APIs and integration-level keys.
|
|
28
|
-
* @param config - Configuration with plugins and optional database
|
|
29
|
-
* @returns A Corsair client instance with plugin APIs and integration-level `keys`
|
|
30
|
-
*/
|
|
31
|
-
declare function createCorsair<const Plugins extends readonly CorsairPlugin[]>(config: CorsairIntegration<Plugins> & {
|
|
32
|
-
multiTenancy?: false | undefined;
|
|
33
|
-
}): CorsairSingleTenantClient<Plugins>;
|
|
34
|
-
|
|
35
|
-
export { CORSAIR_INTERNAL as C, type CorsairInternalConfig as a, createCorsair as c };
|