@authhero/multi-tenancy 13.12.1 → 13.13.2
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/multi-tenancy.cjs +1 -1
- package/dist/multi-tenancy.d.ts +27 -56
- package/dist/multi-tenancy.mjs +156 -156
- package/package.json +3 -3
package/dist/multi-tenancy.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var Z=Object.defineProperty;var H=(e,t,s)=>t in e?Z(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var F=(e,t,s)=>H(e,typeof t!="symbol"?t+"":t,s);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("hono"),T=require("authhero"),C=require("@hono/zod-openapi"),I=require("@authhero/adapter-interfaces");var v=class extends Error{constructor(t=500,s){super(s==null?void 0:s.message,{cause:s==null?void 0:s.cause});F(this,"res");F(this,"status");this.res=s==null?void 0:s.res,this.status=t}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function U(e){const{controlPlaneTenantId:t,requireOrganizationMatch:s=!0}=e;return{async onTenantAccessValidation(a,i){if(i===t)return!0;if(s){const n=a.var.org_name,u=a.var.organization_id,l=n||u;return l?l===i:!1}return!0}}}function E(e,t,s,a){if(t===s)return!0;const i=a||e;return i?i===t:!1}function K(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(s){console.error(`Failed to resolve data adapters for tenant ${t}:`,s);return}}}}function G(e){return{async beforeCreate(t,s){return!s.audience&&s.id?{...s,audience:T.getTenantAudience(s.id)}:s},async afterCreate(t,s){const{accessControl:a,databaseIsolation:i,settingsInheritance:n}=e;a&&t.ctx&&await x(t,s,a),i!=null&&i.onProvision&&await i.onProvision(s.id),(n==null?void 0:n.inheritFromControlPlane)!==!1&&t.ctx&&await ae(t,s,e)},async beforeDelete(t,s){const{accessControl:a,databaseIsolation:i}=e;if(a)try{const u=(await t.adapters.organizations.list(a.controlPlaneTenantId)).organizations.find(l=>l.name===s);u&&await t.adapters.organizations.remove(a.controlPlaneTenantId,u.id)}catch(n){console.warn(`Failed to remove organization for tenant ${s}:`,n)}if(i!=null&&i.onDeprovision)try{await i.onDeprovision(s)}catch(n){console.warn(`Failed to deprovision database for tenant ${s}:`,n)}}}}async function x(e,t,s){const{controlPlaneTenantId:a,defaultPermissions:i,defaultRoles:n,issuer:u,adminRoleName:l="Tenant Admin",adminRoleDescription:c="Full access to all tenant management operations",addCreatorToOrganization:r=!0}=s,f=await e.adapters.organizations.create(a,{name:t.id,display_name:t.friendly_name||t.id});let d;if(u&&(d=await te(e,a,l,c)),r&&e.ctx){const o=e.ctx.var.user;if(o!=null&&o.sub&&!await ee(e,a,o.sub))try{await e.adapters.userOrganizations.create(a,{user_id:o.sub,organization_id:f.id}),d&&await e.adapters.userRoles.create(a,o.sub,d,f.id)}catch(g){console.warn(`Failed to add creator ${o.sub} to organization ${f.id}:`,g)}}n&&n.length>0&&console.log(`Would assign roles ${n.join(", ")} to organization ${f.id}`),i&&i.length>0&&console.log(`Would grant permissions ${i.join(", ")} to organization ${f.id}`)}async function ee(e,t,s){const a=await e.adapters.userRoles.list(t,s,void 0,"");for(const i of a)if((await e.adapters.rolePermissions.list(t,i.id,{per_page:1e3})).some(l=>l.permission_name==="admin:organizations"))return!0;return!1}async function te(e,t,s,a){const n=(await e.adapters.roles.list(t,{})).roles.find(r=>r.name===s);if(n)return n.id;const u=await e.adapters.roles.create(t,{name:s,description:a}),l=T.MANAGEMENT_API_AUDIENCE,c=T.MANAGEMENT_API_SCOPES.map(r=>({role_id:u.id,resource_server_identifier:l,permission_name:r.value}));return await e.adapters.rolePermissions.assign(t,u.id,c),u.id}async function ae(e,t,s){const{accessControl:a,settingsInheritance:i}=s;if(!a)return;const n=await e.adapters.tenants.get(a.controlPlaneTenantId);if(!n)return;let u={...n};const l=["id","created_at","updated_at","friendly_name","audience","sender_email","sender_name"];for(const c of l)delete u[c];if(i!=null&&i.inheritedKeys){const c={};for(const r of i.inheritedKeys)r in n&&!l.includes(r)&&(c[r]=n[r]);u=c}if(i!=null&&i.excludedKeys)for(const c of i.excludedKeys)delete u[c];i!=null&&i.transformSettings&&(u=i.transformSettings(u,t.id)),Object.keys(u).length>0&&await e.adapters.tenants.update(t.id,u)}function B(e){const{controlPlaneTenantId:t,getChildTenantIds:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n}=e;async function u(r,f,d){return(await r.resourceServers.list(f,{q:`identifier:${d}`,per_page:1})).resource_servers[0]??null}async function l(r,f){const d=await s();await Promise.all(d.map(async o=>{try{const p=await a(o),h={...n?n(r,o):{name:r.name,identifier:r.identifier,scopes:r.scopes,signing_alg:r.signing_alg,signing_secret:r.signing_secret,token_lifetime:r.token_lifetime,token_lifetime_for_web:r.token_lifetime_for_web,skip_consent_for_verifiable_first_party_clients:r.skip_consent_for_verifiable_first_party_clients,allow_offline_access:r.allow_offline_access,verificationKey:r.verificationKey,options:r.options},is_system:!0};if(f==="create"){const A=await u(p,o,r.identifier);A&&A.id?await p.resourceServers.update(o,A.id,h):await p.resourceServers.create(o,h)}else{const A=await u(p,o,r.identifier);A&&A.id?await p.resourceServers.update(o,A.id,h):await p.resourceServers.create(o,h)}}catch(p){console.error(`Failed to sync resource server "${r.identifier}" to tenant "${o}":`,p)}}))}async function c(r){const f=await s();await Promise.all(f.map(async d=>{try{const o=await a(d),p=await u(o,d,r);p&&p.id&&await o.resourceServers.remove(d,p.id)}catch(o){console.error(`Failed to delete resource server "${r}" from tenant "${d}":`,o)}}))}return{afterCreate:async(r,f)=>{r.tenantId===t&&i(f)&&await l(f,"create")},afterUpdate:async(r,f,d)=>{r.tenantId===t&&i(d)&&await l(d,"update")},afterDelete:async(r,f)=>{r.tenantId===t&&await c(f)}}}function W(e){const{controlPlaneTenantId:t,getControlPlaneAdapters:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n}=e;return{async afterCreate(u,l){if(l.id!==t)try{const c=await s(),r=await a(l.id),f=await T.fetchAll(d=>c.resourceServers.list(t,d),"resource_servers",{cursorField:"id",pageSize:100});await Promise.all(f.filter(d=>i(d)).map(async d=>{const o=d;try{const p=n?n(o,l.id):{name:o.name,identifier:o.identifier,scopes:o.scopes,signing_alg:o.signing_alg,signing_secret:o.signing_secret,token_lifetime:o.token_lifetime,token_lifetime_for_web:o.token_lifetime_for_web,skip_consent_for_verifiable_first_party_clients:o.skip_consent_for_verifiable_first_party_clients,allow_offline_access:o.allow_offline_access,verificationKey:o.verificationKey,options:o.options};await r.resourceServers.create(l.id,{...p,is_system:!0})}catch(p){console.error(`Failed to sync resource server "${o.identifier}" to new tenant "${l.id}":`,p)}}))}catch(c){console.error(`Failed to sync resource servers to new tenant "${l.id}":`,c)}}}}function L(e){const{controlPlaneTenantId:t,getChildTenantIds:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n}=e;async function u(c,r,f){return(await c.roles.list(r,{q:`name:${f}`,per_page:1})).roles[0]??null}async function l(c,r){const f=await s();await Promise.all(f.map(async d=>{try{const o=await a(d),g={...n?n(c,d):{name:c.name,description:c.description},is_system:!0};if(r==="create"){const h=await u(o,d,c.name);h&&h.id?await o.roles.update(d,h.id,g):await o.roles.create(d,g)}else{const h=await u(o,d,c.name);h&&h.id?await o.roles.update(d,h.id,g):await o.roles.create(d,g)}}catch(o){console.error(`Failed to sync role "${c.name}" to tenant "${d}":`,o)}}))}return{afterCreate:async(c,r)=>{c.tenantId===t&&i(r)&&await l(r,"create")},afterUpdate:async(c,r,f)=>{c.tenantId===t&&i(f)&&await l(f,"update")},afterDelete:async(c,r)=>{c.tenantId===t&&console.warn(`Role ${r} was deleted from control plane. Child tenant roles with matching names should be deleted manually or implement role name tracking.`)}}}function Q(e){const{controlPlaneTenantId:t,getControlPlaneAdapters:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n,syncPermissions:u=!0}=e;return{async afterCreate(l,c){if(c.id!==t)try{const r=await s(),f=await a(c.id),d=await T.fetchAll(p=>r.roles.list(t,p),"roles",{cursorField:"id",pageSize:100}),o=new Map;if(await Promise.all(d.filter(p=>i(p)).map(async p=>{const g=p;try{const h=n?n(g,c.id):{name:g.name,description:g.description},A=await f.roles.create(c.id,{...h,is_system:!0});o.set(g.id,A.id)}catch(h){console.error(`Failed to sync role "${g.name}" to new tenant "${c.id}":`,h)}})),u)for(const[p,g]of o)try{const h=await r.rolePermissions.list(t,p,{});h.length>0&&await f.rolePermissions.assign(c.id,g,h.map(A=>({role_id:g,resource_server_identifier:A.resource_server_identifier,permission_name:A.permission_name})))}catch(h){console.error(`Failed to sync permissions for role to new tenant "${c.id}":`,h)}}catch(r){console.error(`Failed to sync roles to new tenant "${c.id}":`,r)}}}}function O(e,t){const s=new C.OpenAPIHono;return s.openapi(C.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:I.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:C.z.object({tenants:C.z.array(I.tenantSchema),start:C.z.number().optional(),limit:C.z.number().optional(),length:C.z.number().optional()})}},description:"List of tenants"}}}),async a=>{var p,g,h,A;const i=a.req.valid("query"),{page:n,per_page:u,include_totals:l,q:c}=i,r=a.var.user,f=((r==null?void 0:r.scope)||"").split(" "),d=f.includes("auth:read");if(console.log("User scopes:",f,"hasAuthRead:",d),d){const S=await a.env.data.tenants.list({page:n,per_page:u,include_totals:l,q:c});return l?a.json({tenants:S.tenants,start:((p=S.totals)==null?void 0:p.start)??0,limit:((g=S.totals)==null?void 0:g.limit)??u,length:S.tenants.length}):a.json({tenants:S.tenants})}if(e.accessControl&&(r!=null&&r.sub)){const S=e.accessControl.controlPlaneTenantId,R=(await T.fetchAll(M=>a.env.data.userOrganizations.listUserOrganizations(S,r.sub,M),"organizations")).map(M=>M.name);if(R.length===0)return l?a.json({tenants:[],start:0,limit:u??50,length:0}):a.json({tenants:[]});const $=R.length,D=n??0,P=u??50,w=D*P,m=R.slice(w,w+P);if(m.length===0)return l?a.json({tenants:[],start:w,limit:P,length:$}):a.json({tenants:[]});const y=m.map(M=>`id:${M}`).join(" OR "),_=c?`(${y}) AND (${c})`:y,b=await a.env.data.tenants.list({q:_,per_page:P,include_totals:!1});return l?a.json({tenants:b.tenants,start:w,limit:P,length:$}):a.json({tenants:b.tenants})}const o=await a.env.data.tenants.list({page:n,per_page:u,include_totals:l,q:c});return l?a.json({tenants:o.tenants,start:((h=o.totals)==null?void 0:h.start)??0,limit:((A=o.totals)==null?void 0:A.limit)??u,length:o.tenants.length}):a.json({tenants:o.tenants})}),s.openapi(C.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:I.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:I.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async a=>{var c,r;const i=a.var.user;if(!(i!=null&&i.sub))throw new v(401,{message:"Authentication required to create tenants"});let n=a.req.valid("json");const u={adapters:a.env.data,ctx:a};(c=t.tenants)!=null&&c.beforeCreate&&(n=await t.tenants.beforeCreate(u,n));const l=await a.env.data.tenants.create(n);return(r=t.tenants)!=null&&r.afterCreate&&await t.tenants.afterCreate(u,l),a.json(l,201)}),s.openapi(C.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:C.z.object({id:C.z.string()})},security:[{Bearer:["delete:tenants"]}],responses:{204:{description:"Tenant deleted"},403:{description:"Access denied or cannot delete the control plane"},404:{description:"Tenant not found"}}}),async a=>{var l,c;const{id:i}=a.req.valid("param");if(e.accessControl){const r=a.var.user,f=e.accessControl.controlPlaneTenantId;if(!(r!=null&&r.sub))throw new v(401,{message:"Authentication required"});if(i===f)throw new v(403,{message:"Cannot delete the control plane"});if(!(await T.fetchAll(p=>a.env.data.userOrganizations.listUserOrganizations(f,r.sub,p),"organizations")).some(p=>p.name===i))throw new v(403,{message:"Access denied to this tenant"})}if(!await a.env.data.tenants.get(i))throw new v(404,{message:"Tenant not found"});const u={adapters:a.env.data,ctx:a};return(l=t.tenants)!=null&&l.beforeDelete&&await t.tenants.beforeDelete(u,i),await a.env.data.tenants.remove(i),(c=t.tenants)!=null&&c.afterDelete&&await t.tenants.afterDelete(u,i),a.body(null,204)}),s}function ne(e){const t=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:s,type:a}of t){const i=e.match(s);if(i&&i[1])return{type:a,id:i[1]}}return null}async function re(e,t,s){try{switch(s.type){case"resource_server":{const a=await e.resourceServers.get(t,s.id);return(a==null?void 0:a.is_system)===!0}case"role":{const a=await e.roles.get(t,s.id);return(a==null?void 0:a.is_system)===!0}case"connection":{const a=await e.connections.get(t,s.id);return(a==null?void 0:a.is_system)===!0}default:return!1}}catch{return!1}}function se(e){return{resource_server:"resource server",role:"role",connection:"connection"}[e]}function V(){return async(e,t)=>{if(!["PATCH","PUT","DELETE"].includes(e.req.method))return t();const s=ne(e.req.path);if(!s)return t();const a=e.var.tenant_id||e.req.header("x-tenant-id")||e.req.header("tenant-id");if(!a)return t();if(await re(e.env.data,a,s))throw new v(403,{message:`This ${se(s.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function k(e){return async(t,s)=>{if(!e.accessControl)return s();const a=t.var.tenant_id,i=t.var.organization_id;if(!a)throw new v(400,{message:"Tenant ID not found in request"});if(!E(i,a,e.accessControl.controlPlaneTenantId))throw new v(403,{message:`Access denied to tenant ${a}`});return s()}}function J(e){return async(t,s)=>{if(!e.subdomainRouting)return s();const{baseDomain:a,reservedSubdomains:i=[],resolveSubdomain:n}=e.subdomainRouting,u=t.req.header("host")||"";let l=null;if(u.endsWith(a)){const r=u.slice(0,-(a.length+1));r&&!r.includes(".")&&(l=r)}if(l&&i.includes(l)&&(l=null),!l)return e.accessControl&&t.set("tenant_id",e.accessControl.controlPlaneTenantId),s();let c=null;if(n)c=await n(l);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{const r=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,l);r&&(c=r.id)}catch{}if(!c)throw new v(404,{message:`Tenant not found for subdomain: ${l}`});return t.set("tenant_id",c),s()}}function X(e){return async(t,s)=>{if(!e.databaseIsolation)return s();const a=t.var.tenant_id;if(!a)throw new v(400,{message:"Tenant ID not found in request"});try{const i=await e.databaseIsolation.getAdapters(a);t.env.data=i}catch(i){throw console.error(`Failed to resolve database for tenant ${a}:`,i),new v(500,{message:"Failed to resolve tenant database"})}return s()}}function j(e){const t=J(e),s=k(e),a=X(e);return async(i,n)=>(await t(i,async()=>{}),await s(i,async()=>{}),await a(i,async()=>{}),n())}function ie(e){const t=z(e);return{name:"multi-tenancy",middleware:j(e),hooks:t,routes:[{path:"/management",handler:O(e,t)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),e.accessControl&&console.log(` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`),e.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`),e.databaseIsolation&&console.log(" - Database isolation enabled")}}}function z(e){const t=e.accessControl?U(e.accessControl):{},s=e.databaseIsolation?K(e.databaseIsolation):{},a=G(e);return{...t,...s,tenants:a}}function Y(e){const t=new N.Hono,s=z(e);return t.route("/tenants",O(e,s)),t}function oe(e){return{hooks:z(e),middleware:j(e),app:Y(e),config:e}}function ce(e){const{controlPlaneTenantId:t="control_plane",syncResourceServers:s=!0,syncRoles:a=!0,multiTenancy:i,entityHooks:n,...u}=e,l={...i,accessControl:{controlPlaneTenantId:t,requireOrganizationMatch:!1,defaultPermissions:["tenant:admin"],...i==null?void 0:i.accessControl}},c=z(l);let r,f;s&&(r=B({controlPlaneTenantId:t,getChildTenantIds:async()=>(await T.fetchAll(m=>e.dataAdapter.tenants.list(m),"tenants",{cursorField:"id",pageSize:100})).filter(m=>m.id!==t).map(m=>m.id),getAdapters:async w=>e.dataAdapter}),f=W({controlPlaneTenantId:t,getControlPlaneAdapters:async()=>e.dataAdapter,getAdapters:async w=>e.dataAdapter}));let d,o;a&&(d=L({controlPlaneTenantId:t,getChildTenantIds:async()=>(await T.fetchAll(m=>e.dataAdapter.tenants.list(m),"tenants",{cursorField:"id",pageSize:100})).filter(m=>m.id!==t).map(m=>m.id),getAdapters:async w=>e.dataAdapter}),o=Q({controlPlaneTenantId:t,getControlPlaneAdapters:async()=>e.dataAdapter,getAdapters:async w=>e.dataAdapter,syncPermissions:!0}));const p=async(w,m,...y)=>{const _=[];if(w)try{await w(...y)}catch(b){_.push(b instanceof Error?b:new Error(String(b)))}if(m)try{await m(...y)}catch(b){_.push(b instanceof Error?b:new Error(String(b)))}if(_.length===1)throw _[0];if(_.length>1)throw new AggregateError(_,`Multiple hook errors: ${_.map(b=>b.message).join("; ")}`)},g=async(w,...m)=>{const y=[];for(const _ of w)if(_)try{await _(...m)}catch(b){y.push(b instanceof Error?b:new Error(String(b)))}if(y.length===1)throw y[0];if(y.length>1)throw new AggregateError(y,`Multiple hook errors: ${y.map(_=>_.message).join("; ")}`)},h={...n,resourceServers:r?{...n==null?void 0:n.resourceServers,afterCreate:async(w,m)=>{var y;await p((y=n==null?void 0:n.resourceServers)==null?void 0:y.afterCreate,r==null?void 0:r.afterCreate,w,m)},afterUpdate:async(w,m,y)=>{var _;await p((_=n==null?void 0:n.resourceServers)==null?void 0:_.afterUpdate,r==null?void 0:r.afterUpdate,w,m,y)},afterDelete:async(w,m)=>{var y;await p((y=n==null?void 0:n.resourceServers)==null?void 0:y.afterDelete,r==null?void 0:r.afterDelete,w,m)}}:n==null?void 0:n.resourceServers,roles:d?{...n==null?void 0:n.roles,afterCreate:async(w,m)=>{var y;await p((y=n==null?void 0:n.roles)==null?void 0:y.afterCreate,d==null?void 0:d.afterCreate,w,m)},afterUpdate:async(w,m,y)=>{var _;await p((_=n==null?void 0:n.roles)==null?void 0:_.afterUpdate,d==null?void 0:d.afterUpdate,w,m,y)},afterDelete:async(w,m)=>{var y;await p((y=n==null?void 0:n.roles)==null?void 0:y.afterDelete,d==null?void 0:d.afterDelete,w,m)}}:n==null?void 0:n.roles,tenants:f||o?{...n==null?void 0:n.tenants,afterCreate:async(w,m)=>{var y;await g([(y=n==null?void 0:n.tenants)==null?void 0:y.afterCreate,f==null?void 0:f.afterCreate,o==null?void 0:o.afterCreate],w,m)}}:n==null?void 0:n.tenants},A={...c,tenants:f||o?{...c.tenants,afterCreate:async(w,m)=>{var y;(y=c.tenants)!=null&&y.afterCreate&&await c.tenants.afterCreate(w,m),await g([f==null?void 0:f.afterCreate,o==null?void 0:o.afterCreate],w,m)}}:c.tenants},S=O(l,A),q=T.init({...u,entityHooks:h,managementApiExtensions:[...u.managementApiExtensions||[],{path:"/tenants",router:S}]}),{app:R,managementApp:$,...D}=q,P=new N.Hono;return P.onError((w,m)=>w instanceof v?w.getResponse():(console.error(w),m.json({message:"Internal Server Error"},500))),P.use("/api/v2/*",V()),P.route("/",R),{app:P,managementApp:$,...D,multiTenancyConfig:l,multiTenancyHooks:c}}Object.defineProperty(exports,"MANAGEMENT_API_SCOPES",{enumerable:!0,get:()=>T.MANAGEMENT_API_SCOPES});Object.defineProperty(exports,"fetchAll",{enumerable:!0,get:()=>T.fetchAll});Object.defineProperty(exports,"seed",{enumerable:!0,get:()=>T.seed});exports.createAccessControlHooks=U;exports.createAccessControlMiddleware=k;exports.createDatabaseHooks=K;exports.createDatabaseMiddleware=X;exports.createMultiTenancy=Y;exports.createMultiTenancyHooks=z;exports.createMultiTenancyMiddleware=j;exports.createMultiTenancyPlugin=ie;exports.createProtectSyncedMiddleware=V;exports.createProvisioningHooks=G;exports.createResourceServerSyncHooks=B;exports.createRoleSyncHooks=L;exports.createSubdomainMiddleware=J;exports.createTenantResourceServerSyncHooks=W;exports.createTenantRoleSyncHooks=Q;exports.createTenantsOpenAPIRouter=O;exports.init=ce;exports.setupMultiTenancy=oe;exports.validateTenantAccess=E;
|
|
1
|
+
"use strict";var Z=Object.defineProperty;var H=(e,t,s)=>t in e?Z(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var D=(e,t,s)=>H(e,typeof t!="symbol"?t+"":t,s);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("hono"),T=require("authhero"),C=require("@hono/zod-openapi"),I=require("@authhero/adapter-interfaces");var v=class extends Error{constructor(t=500,s){super(s==null?void 0:s.message,{cause:s==null?void 0:s.cause});D(this,"res");D(this,"status");this.res=s==null?void 0:s.res,this.status=t}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function U(e){const{controlPlaneTenantId:t,requireOrganizationMatch:s=!0}=e;return{async onTenantAccessValidation(a,i){if(i===t)return!0;if(s){const n=a.var.org_name,d=a.var.organization_id,l=n||d;return l?l===i:!1}return!0}}}function E(e,t,s,a){if(t===s)return!0;const i=a||e;return i?i===t:!1}function K(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(s){console.error(`Failed to resolve data adapters for tenant ${t}:`,s);return}}}}function G(e){return{async beforeCreate(t,s){return!s.audience&&s.id?{...s,audience:T.getTenantAudience(s.id)}:s},async afterCreate(t,s){const{accessControl:a,databaseIsolation:i,settingsInheritance:n}=e;a&&t.ctx&&await x(t,s,a),i!=null&&i.onProvision&&await i.onProvision(s.id),(n==null?void 0:n.inheritFromControlPlane)!==!1&&t.ctx&&await ae(t,s,e)},async beforeDelete(t,s){const{accessControl:a,databaseIsolation:i}=e;if(a)try{const d=(await t.adapters.organizations.list(a.controlPlaneTenantId)).organizations.find(l=>l.name===s);d&&await t.adapters.organizations.remove(a.controlPlaneTenantId,d.id)}catch(n){console.warn(`Failed to remove organization for tenant ${s}:`,n)}if(i!=null&&i.onDeprovision)try{await i.onDeprovision(s)}catch(n){console.warn(`Failed to deprovision database for tenant ${s}:`,n)}}}}async function x(e,t,s){const{controlPlaneTenantId:a,defaultPermissions:i,defaultRoles:n,issuer:d,adminRoleName:l="Tenant Admin",adminRoleDescription:c="Full access to all tenant management operations",addCreatorToOrganization:r=!0}=s,f=await e.adapters.organizations.create(a,{name:t.id,display_name:t.friendly_name||t.id});let u;if(d&&(u=await te(e,a,l,c)),r&&e.ctx){const o=e.ctx.var.user;if(o!=null&&o.sub&&!await ee(e,a,o.sub))try{await e.adapters.userOrganizations.create(a,{user_id:o.sub,organization_id:f.id}),u&&await e.adapters.userRoles.create(a,o.sub,u,f.id)}catch(g){console.warn(`Failed to add creator ${o.sub} to organization ${f.id}:`,g)}}n&&n.length>0&&console.log(`Would assign roles ${n.join(", ")} to organization ${f.id}`),i&&i.length>0&&console.log(`Would grant permissions ${i.join(", ")} to organization ${f.id}`)}async function ee(e,t,s){const a=await e.adapters.userRoles.list(t,s,void 0,"");for(const i of a)if((await e.adapters.rolePermissions.list(t,i.id,{per_page:1e3})).some(l=>l.permission_name==="admin:organizations"))return!0;return!1}async function te(e,t,s,a){const n=(await e.adapters.roles.list(t,{})).roles.find(r=>r.name===s);if(n)return n.id;const d=await e.adapters.roles.create(t,{name:s,description:a}),l=T.MANAGEMENT_API_AUDIENCE,c=T.MANAGEMENT_API_SCOPES.map(r=>({role_id:d.id,resource_server_identifier:l,permission_name:r.value}));return await e.adapters.rolePermissions.assign(t,d.id,c),d.id}async function ae(e,t,s){const{accessControl:a,settingsInheritance:i}=s;if(!a)return;const n=await e.adapters.tenants.get(a.controlPlaneTenantId);if(!n)return;let d={...n};const l=["id","created_at","updated_at","friendly_name","audience","sender_email","sender_name"];for(const c of l)delete d[c];if(i!=null&&i.inheritedKeys){const c={};for(const r of i.inheritedKeys)r in n&&!l.includes(r)&&(c[r]=n[r]);d=c}if(i!=null&&i.excludedKeys)for(const c of i.excludedKeys)delete d[c];i!=null&&i.transformSettings&&(d=i.transformSettings(d,t.id)),Object.keys(d).length>0&&await e.adapters.tenants.update(t.id,d)}function B(e){const{controlPlaneTenantId:t,getChildTenantIds:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n}=e;async function d(r,f,u){return(await r.resourceServers.list(f,{q:`identifier:${u}`,per_page:1})).resource_servers[0]??null}async function l(r,f){const u=await s();await Promise.all(u.map(async o=>{try{const p=await a(o),h={...n?n(r,o):{name:r.name,identifier:r.identifier,scopes:r.scopes,signing_alg:r.signing_alg,signing_secret:r.signing_secret,token_lifetime:r.token_lifetime,token_lifetime_for_web:r.token_lifetime_for_web,skip_consent_for_verifiable_first_party_clients:r.skip_consent_for_verifiable_first_party_clients,allow_offline_access:r.allow_offline_access,verificationKey:r.verificationKey,options:r.options},is_system:!0};if(f==="create"){const A=await d(p,o,r.identifier);A&&A.id?await p.resourceServers.update(o,A.id,h):await p.resourceServers.create(o,h)}else{const A=await d(p,o,r.identifier);A&&A.id?await p.resourceServers.update(o,A.id,h):await p.resourceServers.create(o,h)}}catch(p){console.error(`Failed to sync resource server "${r.identifier}" to tenant "${o}":`,p)}}))}async function c(r){const f=await s();await Promise.all(f.map(async u=>{try{const o=await a(u),p=await d(o,u,r);p&&p.id&&await o.resourceServers.remove(u,p.id)}catch(o){console.error(`Failed to delete resource server "${r}" from tenant "${u}":`,o)}}))}return{afterCreate:async(r,f)=>{r.tenantId===t&&i(f)&&await l(f,"create")},afterUpdate:async(r,f,u)=>{r.tenantId===t&&i(u)&&await l(u,"update")},afterDelete:async(r,f)=>{r.tenantId===t&&await c(f)}}}function W(e){const{controlPlaneTenantId:t,getControlPlaneAdapters:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n}=e;return{async afterCreate(d,l){if(l.id!==t)try{const c=await s(),r=await a(l.id),f=await T.fetchAll(u=>c.resourceServers.list(t,u),"resource_servers",{cursorField:"id",pageSize:100});await Promise.all(f.filter(u=>i(u)).map(async u=>{const o=u;try{const p=n?n(o,l.id):{name:o.name,identifier:o.identifier,scopes:o.scopes,signing_alg:o.signing_alg,signing_secret:o.signing_secret,token_lifetime:o.token_lifetime,token_lifetime_for_web:o.token_lifetime_for_web,skip_consent_for_verifiable_first_party_clients:o.skip_consent_for_verifiable_first_party_clients,allow_offline_access:o.allow_offline_access,verificationKey:o.verificationKey,options:o.options};await r.resourceServers.create(l.id,{...p,is_system:!0})}catch(p){console.error(`Failed to sync resource server "${o.identifier}" to new tenant "${l.id}":`,p)}}))}catch(c){console.error(`Failed to sync resource servers to new tenant "${l.id}":`,c)}}}}function L(e){const{controlPlaneTenantId:t,getChildTenantIds:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n}=e;async function d(c,r,f){return(await c.roles.list(r,{q:`name:${f}`,per_page:1})).roles[0]??null}async function l(c,r){const f=await s();await Promise.all(f.map(async u=>{try{const o=await a(u),g={...n?n(c,u):{name:c.name,description:c.description},is_system:!0};if(r==="create"){const h=await d(o,u,c.name);h&&h.id?await o.roles.update(u,h.id,g):await o.roles.create(u,g)}else{const h=await d(o,u,c.name);h&&h.id?await o.roles.update(u,h.id,g):await o.roles.create(u,g)}}catch(o){console.error(`Failed to sync role "${c.name}" to tenant "${u}":`,o)}}))}return{afterCreate:async(c,r)=>{c.tenantId===t&&i(r)&&await l(r,"create")},afterUpdate:async(c,r,f)=>{c.tenantId===t&&i(f)&&await l(f,"update")},afterDelete:async(c,r)=>{c.tenantId===t&&console.warn(`Role ${r} was deleted from control plane. Child tenant roles with matching names should be deleted manually or implement role name tracking.`)}}}function Q(e){const{controlPlaneTenantId:t,getControlPlaneAdapters:s,getAdapters:a,shouldSync:i=()=>!0,transformForSync:n,syncPermissions:d=!0}=e;return{async afterCreate(l,c){if(c.id!==t)try{const r=await s(),f=await a(c.id),u=await T.fetchAll(p=>r.roles.list(t,p),"roles",{cursorField:"id",pageSize:100}),o=new Map;if(await Promise.all(u.filter(p=>i(p)).map(async p=>{const g=p;try{const h=n?n(g,c.id):{name:g.name,description:g.description},A=await f.roles.create(c.id,{...h,is_system:!0});o.set(g.id,A.id)}catch(h){console.error(`Failed to sync role "${g.name}" to new tenant "${c.id}":`,h)}})),d)for(const[p,g]of o)try{const h=await r.rolePermissions.list(t,p,{});h.length>0&&await f.rolePermissions.assign(c.id,g,h.map(A=>({role_id:g,resource_server_identifier:A.resource_server_identifier,permission_name:A.permission_name})))}catch(h){console.error(`Failed to sync permissions for role to new tenant "${c.id}":`,h)}}catch(r){console.error(`Failed to sync roles to new tenant "${c.id}":`,r)}}}}function O(e,t){const s=new C.OpenAPIHono;return s.openapi(C.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:I.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:C.z.object({tenants:C.z.array(I.tenantSchema),start:C.z.number().optional(),limit:C.z.number().optional(),length:C.z.number().optional()})}},description:"List of tenants"}}}),async a=>{var p,g,h,A;const i=a.req.valid("query"),{page:n,per_page:d,include_totals:l,q:c}=i,r=a.var.user,f=(r==null?void 0:r.permissions)||[];if(f.includes("auth:read")||f.includes("admin:organizations")){const S=await a.env.data.tenants.list({page:n,per_page:d,include_totals:l,q:c});return l?a.json({tenants:S.tenants,start:((p=S.totals)==null?void 0:p.start)??0,limit:((g=S.totals)==null?void 0:g.limit)??d,length:S.tenants.length}):a.json({tenants:S.tenants})}if(e.accessControl&&(r!=null&&r.sub)){const S=e.accessControl.controlPlaneTenantId,z=(await T.fetchAll(M=>a.env.data.userOrganizations.listUserOrganizations(S,r.sub,M),"organizations")).map(M=>M.name);if(z.length===0)return l?a.json({tenants:[],start:0,limit:d??50,length:0}):a.json({tenants:[]});const $=z.length,F=n??0,P=d??50,w=F*P,m=z.slice(w,w+P);if(m.length===0)return l?a.json({tenants:[],start:w,limit:P,length:$}):a.json({tenants:[]});const y=m.map(M=>`id:${M}`).join(" OR "),_=c?`(${y}) AND (${c})`:y,b=await a.env.data.tenants.list({q:_,per_page:P,include_totals:!1});return l?a.json({tenants:b.tenants,start:w,limit:P,length:$}):a.json({tenants:b.tenants})}const o=await a.env.data.tenants.list({page:n,per_page:d,include_totals:l,q:c});return l?a.json({tenants:o.tenants,start:((h=o.totals)==null?void 0:h.start)??0,limit:((A=o.totals)==null?void 0:A.limit)??d,length:o.tenants.length}):a.json({tenants:o.tenants})}),s.openapi(C.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:I.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:I.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async a=>{var c,r;const i=a.var.user;if(!(i!=null&&i.sub))throw new v(401,{message:"Authentication required to create tenants"});let n=a.req.valid("json");const d={adapters:a.env.data,ctx:a};(c=t.tenants)!=null&&c.beforeCreate&&(n=await t.tenants.beforeCreate(d,n));const l=await a.env.data.tenants.create(n);return(r=t.tenants)!=null&&r.afterCreate&&await t.tenants.afterCreate(d,l),a.json(l,201)}),s.openapi(C.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:C.z.object({id:C.z.string()})},security:[{Bearer:["delete:tenants"]}],responses:{204:{description:"Tenant deleted"},403:{description:"Access denied or cannot delete the control plane"},404:{description:"Tenant not found"}}}),async a=>{var l,c;const{id:i}=a.req.valid("param");if(e.accessControl){const r=a.var.user,f=e.accessControl.controlPlaneTenantId;if(!(r!=null&&r.sub))throw new v(401,{message:"Authentication required"});if(i===f)throw new v(403,{message:"Cannot delete the control plane"});if(!(await T.fetchAll(p=>a.env.data.userOrganizations.listUserOrganizations(f,r.sub,p),"organizations")).some(p=>p.name===i))throw new v(403,{message:"Access denied to this tenant"})}if(!await a.env.data.tenants.get(i))throw new v(404,{message:"Tenant not found"});const d={adapters:a.env.data,ctx:a};return(l=t.tenants)!=null&&l.beforeDelete&&await t.tenants.beforeDelete(d,i),await a.env.data.tenants.remove(i),(c=t.tenants)!=null&&c.afterDelete&&await t.tenants.afterDelete(d,i),a.body(null,204)}),s}function ne(e){const t=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:s,type:a}of t){const i=e.match(s);if(i&&i[1])return{type:a,id:i[1]}}return null}async function re(e,t,s){try{switch(s.type){case"resource_server":{const a=await e.resourceServers.get(t,s.id);return(a==null?void 0:a.is_system)===!0}case"role":{const a=await e.roles.get(t,s.id);return(a==null?void 0:a.is_system)===!0}case"connection":{const a=await e.connections.get(t,s.id);return(a==null?void 0:a.is_system)===!0}default:return!1}}catch{return!1}}function se(e){return{resource_server:"resource server",role:"role",connection:"connection"}[e]}function V(){return async(e,t)=>{if(!["PATCH","PUT","DELETE"].includes(e.req.method))return t();const s=ne(e.req.path);if(!s)return t();const a=e.var.tenant_id||e.req.header("x-tenant-id")||e.req.header("tenant-id");if(!a)return t();if(await re(e.env.data,a,s))throw new v(403,{message:`This ${se(s.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function k(e){return async(t,s)=>{if(!e.accessControl)return s();const a=t.var.tenant_id,i=t.var.organization_id;if(!a)throw new v(400,{message:"Tenant ID not found in request"});if(!E(i,a,e.accessControl.controlPlaneTenantId))throw new v(403,{message:`Access denied to tenant ${a}`});return s()}}function J(e){return async(t,s)=>{if(!e.subdomainRouting)return s();const{baseDomain:a,reservedSubdomains:i=[],resolveSubdomain:n}=e.subdomainRouting,d=t.req.header("host")||"";let l=null;if(d.endsWith(a)){const r=d.slice(0,-(a.length+1));r&&!r.includes(".")&&(l=r)}if(l&&i.includes(l)&&(l=null),!l)return e.accessControl&&t.set("tenant_id",e.accessControl.controlPlaneTenantId),s();let c=null;if(n)c=await n(l);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{const r=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,l);r&&(c=r.id)}catch{}if(!c)throw new v(404,{message:`Tenant not found for subdomain: ${l}`});return t.set("tenant_id",c),s()}}function X(e){return async(t,s)=>{if(!e.databaseIsolation)return s();const a=t.var.tenant_id;if(!a)throw new v(400,{message:"Tenant ID not found in request"});try{const i=await e.databaseIsolation.getAdapters(a);t.env.data=i}catch(i){throw console.error(`Failed to resolve database for tenant ${a}:`,i),new v(500,{message:"Failed to resolve tenant database"})}return s()}}function j(e){const t=J(e),s=k(e),a=X(e);return async(i,n)=>(await t(i,async()=>{}),await s(i,async()=>{}),await a(i,async()=>{}),n())}function ie(e){const t=R(e);return{name:"multi-tenancy",middleware:j(e),hooks:t,routes:[{path:"/management",handler:O(e,t)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),e.accessControl&&console.log(` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`),e.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`),e.databaseIsolation&&console.log(" - Database isolation enabled")}}}function R(e){const t=e.accessControl?U(e.accessControl):{},s=e.databaseIsolation?K(e.databaseIsolation):{},a=G(e);return{...t,...s,tenants:a}}function Y(e){const t=new N.Hono,s=R(e);return t.route("/tenants",O(e,s)),t}function oe(e){return{hooks:R(e),middleware:j(e),app:Y(e),config:e}}function ce(e){const{controlPlaneTenantId:t="control_plane",syncResourceServers:s=!0,syncRoles:a=!0,multiTenancy:i,entityHooks:n,...d}=e,l={...i,accessControl:{controlPlaneTenantId:t,requireOrganizationMatch:!1,defaultPermissions:["tenant:admin"],...i==null?void 0:i.accessControl}},c=R(l);let r,f;s&&(r=B({controlPlaneTenantId:t,getChildTenantIds:async()=>(await T.fetchAll(m=>e.dataAdapter.tenants.list(m),"tenants",{cursorField:"id",pageSize:100})).filter(m=>m.id!==t).map(m=>m.id),getAdapters:async w=>e.dataAdapter}),f=W({controlPlaneTenantId:t,getControlPlaneAdapters:async()=>e.dataAdapter,getAdapters:async w=>e.dataAdapter}));let u,o;a&&(u=L({controlPlaneTenantId:t,getChildTenantIds:async()=>(await T.fetchAll(m=>e.dataAdapter.tenants.list(m),"tenants",{cursorField:"id",pageSize:100})).filter(m=>m.id!==t).map(m=>m.id),getAdapters:async w=>e.dataAdapter}),o=Q({controlPlaneTenantId:t,getControlPlaneAdapters:async()=>e.dataAdapter,getAdapters:async w=>e.dataAdapter,syncPermissions:!0}));const p=async(w,m,...y)=>{const _=[];if(w)try{await w(...y)}catch(b){_.push(b instanceof Error?b:new Error(String(b)))}if(m)try{await m(...y)}catch(b){_.push(b instanceof Error?b:new Error(String(b)))}if(_.length===1)throw _[0];if(_.length>1)throw new AggregateError(_,`Multiple hook errors: ${_.map(b=>b.message).join("; ")}`)},g=async(w,...m)=>{const y=[];for(const _ of w)if(_)try{await _(...m)}catch(b){y.push(b instanceof Error?b:new Error(String(b)))}if(y.length===1)throw y[0];if(y.length>1)throw new AggregateError(y,`Multiple hook errors: ${y.map(_=>_.message).join("; ")}`)},h={...n,resourceServers:r?{...n==null?void 0:n.resourceServers,afterCreate:async(w,m)=>{var y;await p((y=n==null?void 0:n.resourceServers)==null?void 0:y.afterCreate,r==null?void 0:r.afterCreate,w,m)},afterUpdate:async(w,m,y)=>{var _;await p((_=n==null?void 0:n.resourceServers)==null?void 0:_.afterUpdate,r==null?void 0:r.afterUpdate,w,m,y)},afterDelete:async(w,m)=>{var y;await p((y=n==null?void 0:n.resourceServers)==null?void 0:y.afterDelete,r==null?void 0:r.afterDelete,w,m)}}:n==null?void 0:n.resourceServers,roles:u?{...n==null?void 0:n.roles,afterCreate:async(w,m)=>{var y;await p((y=n==null?void 0:n.roles)==null?void 0:y.afterCreate,u==null?void 0:u.afterCreate,w,m)},afterUpdate:async(w,m,y)=>{var _;await p((_=n==null?void 0:n.roles)==null?void 0:_.afterUpdate,u==null?void 0:u.afterUpdate,w,m,y)},afterDelete:async(w,m)=>{var y;await p((y=n==null?void 0:n.roles)==null?void 0:y.afterDelete,u==null?void 0:u.afterDelete,w,m)}}:n==null?void 0:n.roles,tenants:f||o?{...n==null?void 0:n.tenants,afterCreate:async(w,m)=>{var y;await g([(y=n==null?void 0:n.tenants)==null?void 0:y.afterCreate,f==null?void 0:f.afterCreate,o==null?void 0:o.afterCreate],w,m)}}:n==null?void 0:n.tenants},A={...c,tenants:f||o?{...c.tenants,afterCreate:async(w,m)=>{var y;(y=c.tenants)!=null&&y.afterCreate&&await c.tenants.afterCreate(w,m),await g([f==null?void 0:f.afterCreate,o==null?void 0:o.afterCreate],w,m)}}:c.tenants},S=O(l,A),q=T.init({...d,entityHooks:h,managementApiExtensions:[...d.managementApiExtensions||[],{path:"/tenants",router:S}]}),{app:z,managementApp:$,...F}=q,P=new N.Hono;return P.onError((w,m)=>w instanceof v?w.getResponse():(console.error(w),m.json({message:"Internal Server Error"},500))),P.use("/api/v2/*",V()),P.route("/",z),{app:P,managementApp:$,...F,multiTenancyConfig:l,multiTenancyHooks:c}}Object.defineProperty(exports,"MANAGEMENT_API_SCOPES",{enumerable:!0,get:()=>T.MANAGEMENT_API_SCOPES});Object.defineProperty(exports,"fetchAll",{enumerable:!0,get:()=>T.fetchAll});Object.defineProperty(exports,"seed",{enumerable:!0,get:()=>T.seed});exports.createAccessControlHooks=U;exports.createAccessControlMiddleware=k;exports.createDatabaseHooks=K;exports.createDatabaseMiddleware=X;exports.createMultiTenancy=Y;exports.createMultiTenancyHooks=R;exports.createMultiTenancyMiddleware=j;exports.createMultiTenancyPlugin=ie;exports.createProtectSyncedMiddleware=V;exports.createProvisioningHooks=G;exports.createResourceServerSyncHooks=B;exports.createRoleSyncHooks=L;exports.createSubdomainMiddleware=J;exports.createTenantResourceServerSyncHooks=W;exports.createTenantRoleSyncHooks=Q;exports.createTenantsOpenAPIRouter=O;exports.init=ce;exports.setupMultiTenancy=oe;exports.validateTenantAccess=E;
|
package/dist/multi-tenancy.d.ts
CHANGED
|
@@ -14702,73 +14702,25 @@ export interface SamlSigner {
|
|
|
14702
14702
|
*/
|
|
14703
14703
|
signSAML(xmlContent: string, privateKey: string, publicCert: string): Promise<string>;
|
|
14704
14704
|
}
|
|
14705
|
-
/**
|
|
14706
|
-
* Context passed to all entity hooks
|
|
14707
|
-
*/
|
|
14705
|
+
/** Context passed to entity hooks */
|
|
14708
14706
|
export interface EntityHookContext {
|
|
14709
|
-
/** The tenant where the operation occurred */
|
|
14710
14707
|
tenantId: string;
|
|
14711
|
-
/** Data adapters for the current tenant */
|
|
14712
14708
|
adapters: DataAdapters;
|
|
14713
14709
|
}
|
|
14714
|
-
/**
|
|
14715
|
-
* CRUD hooks for any entity type.
|
|
14716
|
-
*
|
|
14717
|
-
* Use these hooks to implement cross-tenant synchronization,
|
|
14718
|
-
* audit logging, webhooks, or any other side effects.
|
|
14719
|
-
*
|
|
14720
|
-
* @example
|
|
14721
|
-
* ```typescript
|
|
14722
|
-
* const roleHooks: EntityHooks<Role, RoleInsert> = {
|
|
14723
|
-
* afterCreate: async (ctx, role) => {
|
|
14724
|
-
* // Propagate to other tenants
|
|
14725
|
-
* await syncToChildTenants(ctx, role);
|
|
14726
|
-
* },
|
|
14727
|
-
* afterUpdate: async (ctx, id, role) => {
|
|
14728
|
-
* // Log the update
|
|
14729
|
-
* await auditLog('role_updated', { id, tenantId: ctx.tenantId });
|
|
14730
|
-
* },
|
|
14731
|
-
* };
|
|
14732
|
-
* ```
|
|
14733
|
-
*/
|
|
14710
|
+
/** CRUD hooks for entity operations */
|
|
14734
14711
|
export interface EntityHooks<TEntity, TInsert, TUpdate = Partial<TInsert>> {
|
|
14735
|
-
/** Called before an entity is created */
|
|
14736
14712
|
beforeCreate?: (ctx: EntityHookContext, data: TInsert) => Promise<TInsert>;
|
|
14737
|
-
/** Called after an entity is created */
|
|
14738
14713
|
afterCreate?: (ctx: EntityHookContext, entity: TEntity) => Promise<void>;
|
|
14739
|
-
/** Called before an entity is updated */
|
|
14740
14714
|
beforeUpdate?: (ctx: EntityHookContext, id: string, data: TUpdate) => Promise<TUpdate>;
|
|
14741
|
-
/** Called after an entity is updated */
|
|
14742
14715
|
afterUpdate?: (ctx: EntityHookContext, id: string, entity: TEntity) => Promise<void>;
|
|
14743
|
-
/** Called before an entity is deleted */
|
|
14744
14716
|
beforeDelete?: (ctx: EntityHookContext, id: string) => Promise<void>;
|
|
14745
|
-
/** Called after an entity is deleted */
|
|
14746
14717
|
afterDelete?: (ctx: EntityHookContext, id: string) => Promise<void>;
|
|
14747
14718
|
}
|
|
14748
|
-
/**
|
|
14749
|
-
* Hooks for role permission assignment operations.
|
|
14750
|
-
*
|
|
14751
|
-
* Role permissions use assign/remove operations rather than typical CRUD,
|
|
14752
|
-
* so they have a specialized hook interface.
|
|
14753
|
-
*
|
|
14754
|
-
* @example
|
|
14755
|
-
* ```typescript
|
|
14756
|
-
* const rolePermissionHooks: RolePermissionHooks = {
|
|
14757
|
-
* afterAssign: async (ctx, roleId, permissions) => {
|
|
14758
|
-
* // Sync permissions to child tenants
|
|
14759
|
-
* await syncPermissionsToChildTenants(ctx, roleId, permissions);
|
|
14760
|
-
* },
|
|
14761
|
-
* };
|
|
14762
|
-
* ```
|
|
14763
|
-
*/
|
|
14719
|
+
/** Hooks for role permission assign/remove operations */
|
|
14764
14720
|
export interface RolePermissionHooks {
|
|
14765
|
-
/** Called before permissions are assigned to a role */
|
|
14766
14721
|
beforeAssign?: (ctx: EntityHookContext, roleId: string, permissions: RolePermissionInsert[]) => Promise<RolePermissionInsert[]>;
|
|
14767
|
-
/** Called after permissions are assigned to a role */
|
|
14768
14722
|
afterAssign?: (ctx: EntityHookContext, roleId: string, permissions: RolePermissionInsert[]) => Promise<void>;
|
|
14769
|
-
/** Called before permissions are removed from a role */
|
|
14770
14723
|
beforeRemove?: (ctx: EntityHookContext, roleId: string, permissions: Pick<RolePermissionInsert, "resource_server_identifier" | "permission_name">[]) => Promise<Pick<RolePermissionInsert, "resource_server_identifier" | "permission_name">[]>;
|
|
14771
|
-
/** Called after permissions are removed from a role */
|
|
14772
14724
|
afterRemove?: (ctx: EntityHookContext, roleId: string, permissions: Pick<RolePermissionInsert, "resource_server_identifier" | "permission_name">[]) => Promise<void>;
|
|
14773
14725
|
}
|
|
14774
14726
|
export type Transaction = {
|
|
@@ -14785,7 +14737,7 @@ export type Transaction = {
|
|
|
14785
14737
|
};
|
|
14786
14738
|
export type HookRequest = {
|
|
14787
14739
|
asn?: string;
|
|
14788
|
-
body?: Record<string,
|
|
14740
|
+
body?: Record<string, unknown>;
|
|
14789
14741
|
geoip?: {
|
|
14790
14742
|
cityName?: string;
|
|
14791
14743
|
continentCode?: string;
|
|
@@ -14828,13 +14780,13 @@ export type HookEvent = {
|
|
|
14828
14780
|
id: string;
|
|
14829
14781
|
name: string;
|
|
14830
14782
|
strategy: string;
|
|
14831
|
-
metadata?: Record<string,
|
|
14783
|
+
metadata?: Record<string, unknown>;
|
|
14832
14784
|
};
|
|
14833
14785
|
organization?: {
|
|
14834
14786
|
id: string;
|
|
14835
14787
|
name: string;
|
|
14836
14788
|
display_name: string;
|
|
14837
|
-
metadata?: Record<string,
|
|
14789
|
+
metadata?: Record<string, unknown>;
|
|
14838
14790
|
};
|
|
14839
14791
|
resource_server?: {
|
|
14840
14792
|
identifier: string;
|
|
@@ -14950,7 +14902,20 @@ export type OnExecuteValidateRegistrationUsername = (event: Omit<HookEvent, "use
|
|
|
14950
14902
|
connection: string;
|
|
14951
14903
|
};
|
|
14952
14904
|
}, api: OnExecuteValidateRegistrationUsernameAPI) => Promise<void>;
|
|
14953
|
-
export type
|
|
14905
|
+
export type UserInfoEvent = {
|
|
14906
|
+
ctx: Context<{
|
|
14907
|
+
Bindings: Bindings;
|
|
14908
|
+
Variables: Variables;
|
|
14909
|
+
}>;
|
|
14910
|
+
user: User;
|
|
14911
|
+
tenant_id: string;
|
|
14912
|
+
scopes: string[];
|
|
14913
|
+
};
|
|
14914
|
+
export type OnFetchUserInfoAPI = {
|
|
14915
|
+
setCustomClaim: (claim: string, value: unknown) => void;
|
|
14916
|
+
};
|
|
14917
|
+
/** Called when /userinfo endpoint is accessed */
|
|
14918
|
+
export type OnFetchUserInfo = (event: UserInfoEvent, api: OnFetchUserInfoAPI) => Promise<void>;
|
|
14954
14919
|
/**
|
|
14955
14920
|
* Entity hooks configuration for CRUD operations.
|
|
14956
14921
|
*
|
|
@@ -14993,6 +14958,11 @@ export interface AuthHeroConfig {
|
|
|
14993
14958
|
onExecutePostUserRegistration?: OnExecutePostUserRegistration;
|
|
14994
14959
|
onExecutePreUserUpdate?: OnExecutePreUserUpdate;
|
|
14995
14960
|
onExecutePostLogin?: OnExecutePostLogin;
|
|
14961
|
+
/**
|
|
14962
|
+
* Called when the /userinfo endpoint is accessed.
|
|
14963
|
+
* Use this to add custom claims to the userinfo response.
|
|
14964
|
+
*/
|
|
14965
|
+
onFetchUserInfo?: OnFetchUserInfo;
|
|
14996
14966
|
};
|
|
14997
14967
|
/**
|
|
14998
14968
|
* Entity CRUD hooks for when resources are created/updated/deleted.
|
|
@@ -15094,8 +15064,9 @@ export type Bindings = {
|
|
|
15094
15064
|
onExecutePostLogin?: OnExecutePostLogin;
|
|
15095
15065
|
onExecutePreUserDeletion?: OnExecutePreUserDeletion;
|
|
15096
15066
|
onExecutePostUserDeletion?: OnExecutePostUserDeletion;
|
|
15097
|
-
onExecuteValidateSignupEmail?: OnExecuteValidateSignupEmail;
|
|
15098
15067
|
onExecuteValidateRegistrationUsername?: OnExecuteValidateRegistrationUsername;
|
|
15068
|
+
/** Called when /userinfo endpoint is accessed to add custom claims */
|
|
15069
|
+
onFetchUserInfo?: OnFetchUserInfo;
|
|
15099
15070
|
};
|
|
15100
15071
|
/**
|
|
15101
15072
|
* Entity CRUD hooks for when resources are created/updated/deleted.
|
package/dist/multi-tenancy.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var K = Object.defineProperty;
|
|
2
2
|
var E = (e, t, s) => t in e ? K(e, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : e[t] = s;
|
|
3
3
|
var D = (e, t, s) => E(e, typeof t != "symbol" ? t + "" : t, s);
|
|
4
|
-
import { Hono as
|
|
4
|
+
import { Hono as N } from "hono";
|
|
5
5
|
import { getTenantAudience as G, MANAGEMENT_API_SCOPES as B, MANAGEMENT_API_AUDIENCE as W, fetchAll as S, init as L } from "authhero";
|
|
6
6
|
import { MANAGEMENT_API_SCOPES as Ce, fetchAll as Pe, seed as Se } from "authhero";
|
|
7
7
|
import { OpenAPIHono as Q, createRoute as M, z as P } from "@hono/zod-openapi";
|
|
@@ -39,7 +39,7 @@ function X(e) {
|
|
|
39
39
|
if (i === t)
|
|
40
40
|
return !0;
|
|
41
41
|
if (s) {
|
|
42
|
-
const n = a.var.org_name,
|
|
42
|
+
const n = a.var.org_name, d = a.var.organization_id, l = n || d;
|
|
43
43
|
return l ? l === i : !1;
|
|
44
44
|
}
|
|
45
45
|
return !0;
|
|
@@ -83,12 +83,12 @@ function k(e) {
|
|
|
83
83
|
const { accessControl: a, databaseIsolation: i } = e;
|
|
84
84
|
if (a)
|
|
85
85
|
try {
|
|
86
|
-
const
|
|
86
|
+
const d = (await t.adapters.organizations.list(
|
|
87
87
|
a.controlPlaneTenantId
|
|
88
88
|
)).organizations.find((l) => l.name === s);
|
|
89
|
-
|
|
89
|
+
d && await t.adapters.organizations.remove(
|
|
90
90
|
a.controlPlaneTenantId,
|
|
91
|
-
|
|
91
|
+
d.id
|
|
92
92
|
);
|
|
93
93
|
} catch (n) {
|
|
94
94
|
console.warn(
|
|
@@ -113,7 +113,7 @@ async function H(e, t, s) {
|
|
|
113
113
|
controlPlaneTenantId: a,
|
|
114
114
|
defaultPermissions: i,
|
|
115
115
|
defaultRoles: n,
|
|
116
|
-
issuer:
|
|
116
|
+
issuer: d,
|
|
117
117
|
adminRoleName: l = "Tenant Admin",
|
|
118
118
|
adminRoleDescription: c = "Full access to all tenant management operations",
|
|
119
119
|
addCreatorToOrganization: r = !0
|
|
@@ -124,8 +124,8 @@ async function H(e, t, s) {
|
|
|
124
124
|
display_name: t.friendly_name || t.id
|
|
125
125
|
}
|
|
126
126
|
);
|
|
127
|
-
let
|
|
128
|
-
if (
|
|
127
|
+
let u;
|
|
128
|
+
if (d && (u = await ee(
|
|
129
129
|
e,
|
|
130
130
|
a,
|
|
131
131
|
l,
|
|
@@ -141,10 +141,10 @@ async function H(e, t, s) {
|
|
|
141
141
|
await e.adapters.userOrganizations.create(a, {
|
|
142
142
|
user_id: o.sub,
|
|
143
143
|
organization_id: f.id
|
|
144
|
-
}),
|
|
144
|
+
}), u && await e.adapters.userRoles.create(
|
|
145
145
|
a,
|
|
146
146
|
o.sub,
|
|
147
|
-
|
|
147
|
+
u,
|
|
148
148
|
f.id
|
|
149
149
|
// organizationId
|
|
150
150
|
);
|
|
@@ -184,19 +184,19 @@ async function ee(e, t, s, a) {
|
|
|
184
184
|
const n = (await e.adapters.roles.list(t, {})).roles.find((r) => r.name === s);
|
|
185
185
|
if (n)
|
|
186
186
|
return n.id;
|
|
187
|
-
const
|
|
187
|
+
const d = await e.adapters.roles.create(t, {
|
|
188
188
|
name: s,
|
|
189
189
|
description: a
|
|
190
190
|
}), l = W, c = B.map((r) => ({
|
|
191
|
-
role_id:
|
|
191
|
+
role_id: d.id,
|
|
192
192
|
resource_server_identifier: l,
|
|
193
193
|
permission_name: r.value
|
|
194
194
|
}));
|
|
195
195
|
return await e.adapters.rolePermissions.assign(
|
|
196
196
|
t,
|
|
197
|
-
|
|
197
|
+
d.id,
|
|
198
198
|
c
|
|
199
|
-
),
|
|
199
|
+
), d.id;
|
|
200
200
|
}
|
|
201
201
|
async function te(e, t, s) {
|
|
202
202
|
const { accessControl: a, settingsInheritance: i } = s;
|
|
@@ -207,7 +207,7 @@ async function te(e, t, s) {
|
|
|
207
207
|
);
|
|
208
208
|
if (!n)
|
|
209
209
|
return;
|
|
210
|
-
let
|
|
210
|
+
let d = { ...n };
|
|
211
211
|
const l = [
|
|
212
212
|
"id",
|
|
213
213
|
"created_at",
|
|
@@ -219,20 +219,20 @@ async function te(e, t, s) {
|
|
|
219
219
|
"sender_name"
|
|
220
220
|
];
|
|
221
221
|
for (const c of l)
|
|
222
|
-
delete
|
|
222
|
+
delete d[c];
|
|
223
223
|
if (i != null && i.inheritedKeys) {
|
|
224
224
|
const c = {};
|
|
225
225
|
for (const r of i.inheritedKeys)
|
|
226
226
|
r in n && !l.includes(r) && (c[r] = n[r]);
|
|
227
|
-
|
|
227
|
+
d = c;
|
|
228
228
|
}
|
|
229
229
|
if (i != null && i.excludedKeys)
|
|
230
230
|
for (const c of i.excludedKeys)
|
|
231
|
-
delete
|
|
232
|
-
i != null && i.transformSettings && (
|
|
233
|
-
|
|
231
|
+
delete d[c];
|
|
232
|
+
i != null && i.transformSettings && (d = i.transformSettings(
|
|
233
|
+
d,
|
|
234
234
|
t.id
|
|
235
|
-
)), Object.keys(
|
|
235
|
+
)), Object.keys(d).length > 0 && await e.adapters.tenants.update(t.id, d);
|
|
236
236
|
}
|
|
237
237
|
function ae(e) {
|
|
238
238
|
const {
|
|
@@ -242,18 +242,18 @@ function ae(e) {
|
|
|
242
242
|
shouldSync: i = () => !0,
|
|
243
243
|
transformForSync: n
|
|
244
244
|
} = e;
|
|
245
|
-
async function
|
|
245
|
+
async function d(r, f, u) {
|
|
246
246
|
return (await r.resourceServers.list(f, {
|
|
247
|
-
q: `identifier:${
|
|
247
|
+
q: `identifier:${u}`,
|
|
248
248
|
per_page: 1
|
|
249
249
|
})).resource_servers[0] ?? null;
|
|
250
250
|
}
|
|
251
251
|
async function l(r, f) {
|
|
252
|
-
const
|
|
252
|
+
const u = await s();
|
|
253
253
|
await Promise.all(
|
|
254
|
-
|
|
254
|
+
u.map(async (o) => {
|
|
255
255
|
try {
|
|
256
|
-
const
|
|
256
|
+
const m = await a(o), h = { ...n ? n(r, o) : {
|
|
257
257
|
name: r.name,
|
|
258
258
|
identifier: r.identifier,
|
|
259
259
|
scopes: r.scopes,
|
|
@@ -267,32 +267,32 @@ function ae(e) {
|
|
|
267
267
|
options: r.options
|
|
268
268
|
}, is_system: !0 };
|
|
269
269
|
if (f === "create") {
|
|
270
|
-
const A = await
|
|
271
|
-
|
|
270
|
+
const A = await d(
|
|
271
|
+
m,
|
|
272
272
|
o,
|
|
273
273
|
r.identifier
|
|
274
274
|
);
|
|
275
|
-
A && A.id ? await
|
|
275
|
+
A && A.id ? await m.resourceServers.update(
|
|
276
276
|
o,
|
|
277
277
|
A.id,
|
|
278
278
|
h
|
|
279
|
-
) : await
|
|
279
|
+
) : await m.resourceServers.create(o, h);
|
|
280
280
|
} else {
|
|
281
|
-
const A = await
|
|
282
|
-
|
|
281
|
+
const A = await d(
|
|
282
|
+
m,
|
|
283
283
|
o,
|
|
284
284
|
r.identifier
|
|
285
285
|
);
|
|
286
|
-
A && A.id ? await
|
|
286
|
+
A && A.id ? await m.resourceServers.update(
|
|
287
287
|
o,
|
|
288
288
|
A.id,
|
|
289
289
|
h
|
|
290
|
-
) : await
|
|
290
|
+
) : await m.resourceServers.create(o, h);
|
|
291
291
|
}
|
|
292
|
-
} catch (
|
|
292
|
+
} catch (m) {
|
|
293
293
|
console.error(
|
|
294
294
|
`Failed to sync resource server "${r.identifier}" to tenant "${o}":`,
|
|
295
|
-
|
|
295
|
+
m
|
|
296
296
|
);
|
|
297
297
|
}
|
|
298
298
|
})
|
|
@@ -301,17 +301,17 @@ function ae(e) {
|
|
|
301
301
|
async function c(r) {
|
|
302
302
|
const f = await s();
|
|
303
303
|
await Promise.all(
|
|
304
|
-
f.map(async (
|
|
304
|
+
f.map(async (u) => {
|
|
305
305
|
try {
|
|
306
|
-
const o = await a(
|
|
306
|
+
const o = await a(u), m = await d(
|
|
307
307
|
o,
|
|
308
|
-
|
|
308
|
+
u,
|
|
309
309
|
r
|
|
310
310
|
);
|
|
311
|
-
|
|
311
|
+
m && m.id && await o.resourceServers.remove(u, m.id);
|
|
312
312
|
} catch (o) {
|
|
313
313
|
console.error(
|
|
314
|
-
`Failed to delete resource server "${r}" from tenant "${
|
|
314
|
+
`Failed to delete resource server "${r}" from tenant "${u}":`,
|
|
315
315
|
o
|
|
316
316
|
);
|
|
317
317
|
}
|
|
@@ -322,8 +322,8 @@ function ae(e) {
|
|
|
322
322
|
afterCreate: async (r, f) => {
|
|
323
323
|
r.tenantId === t && i(f) && await l(f, "create");
|
|
324
324
|
},
|
|
325
|
-
afterUpdate: async (r, f,
|
|
326
|
-
r.tenantId === t && i(
|
|
325
|
+
afterUpdate: async (r, f, u) => {
|
|
326
|
+
r.tenantId === t && i(u) && await l(u, "update");
|
|
327
327
|
},
|
|
328
328
|
afterDelete: async (r, f) => {
|
|
329
329
|
r.tenantId === t && await c(f);
|
|
@@ -339,22 +339,22 @@ function ne(e) {
|
|
|
339
339
|
transformForSync: n
|
|
340
340
|
} = e;
|
|
341
341
|
return {
|
|
342
|
-
async afterCreate(
|
|
342
|
+
async afterCreate(d, l) {
|
|
343
343
|
if (l.id !== t)
|
|
344
344
|
try {
|
|
345
345
|
const c = await s(), r = await a(l.id), f = await S(
|
|
346
|
-
(
|
|
346
|
+
(u) => c.resourceServers.list(
|
|
347
347
|
t,
|
|
348
|
-
|
|
348
|
+
u
|
|
349
349
|
),
|
|
350
350
|
"resource_servers",
|
|
351
351
|
{ cursorField: "id", pageSize: 100 }
|
|
352
352
|
);
|
|
353
353
|
await Promise.all(
|
|
354
|
-
f.filter((
|
|
355
|
-
const o =
|
|
354
|
+
f.filter((u) => i(u)).map(async (u) => {
|
|
355
|
+
const o = u;
|
|
356
356
|
try {
|
|
357
|
-
const
|
|
357
|
+
const m = n ? n(o, l.id) : {
|
|
358
358
|
name: o.name,
|
|
359
359
|
identifier: o.identifier,
|
|
360
360
|
scopes: o.scopes,
|
|
@@ -368,13 +368,13 @@ function ne(e) {
|
|
|
368
368
|
options: o.options
|
|
369
369
|
};
|
|
370
370
|
await r.resourceServers.create(l.id, {
|
|
371
|
-
...
|
|
371
|
+
...m,
|
|
372
372
|
is_system: !0
|
|
373
373
|
});
|
|
374
|
-
} catch (
|
|
374
|
+
} catch (m) {
|
|
375
375
|
console.error(
|
|
376
376
|
`Failed to sync resource server "${o.identifier}" to new tenant "${l.id}":`,
|
|
377
|
-
|
|
377
|
+
m
|
|
378
378
|
);
|
|
379
379
|
}
|
|
380
380
|
})
|
|
@@ -396,7 +396,7 @@ function re(e) {
|
|
|
396
396
|
shouldSync: i = () => !0,
|
|
397
397
|
transformForSync: n
|
|
398
398
|
} = e;
|
|
399
|
-
async function
|
|
399
|
+
async function d(c, r, f) {
|
|
400
400
|
return (await c.roles.list(r, {
|
|
401
401
|
q: `name:${f}`,
|
|
402
402
|
per_page: 1
|
|
@@ -405,30 +405,30 @@ function re(e) {
|
|
|
405
405
|
async function l(c, r) {
|
|
406
406
|
const f = await s();
|
|
407
407
|
await Promise.all(
|
|
408
|
-
f.map(async (
|
|
408
|
+
f.map(async (u) => {
|
|
409
409
|
try {
|
|
410
|
-
const o = await a(
|
|
410
|
+
const o = await a(u), g = { ...n ? n(c, u) : {
|
|
411
411
|
name: c.name,
|
|
412
412
|
description: c.description
|
|
413
413
|
}, is_system: !0 };
|
|
414
414
|
if (r === "create") {
|
|
415
|
-
const h = await
|
|
415
|
+
const h = await d(o, u, c.name);
|
|
416
416
|
h && h.id ? await o.roles.update(
|
|
417
|
-
|
|
417
|
+
u,
|
|
418
418
|
h.id,
|
|
419
419
|
g
|
|
420
|
-
) : await o.roles.create(
|
|
420
|
+
) : await o.roles.create(u, g);
|
|
421
421
|
} else {
|
|
422
|
-
const h = await
|
|
422
|
+
const h = await d(o, u, c.name);
|
|
423
423
|
h && h.id ? await o.roles.update(
|
|
424
|
-
|
|
424
|
+
u,
|
|
425
425
|
h.id,
|
|
426
426
|
g
|
|
427
|
-
) : await o.roles.create(
|
|
427
|
+
) : await o.roles.create(u, g);
|
|
428
428
|
}
|
|
429
429
|
} catch (o) {
|
|
430
430
|
console.error(
|
|
431
|
-
`Failed to sync role "${c.name}" to tenant "${
|
|
431
|
+
`Failed to sync role "${c.name}" to tenant "${u}":`,
|
|
432
432
|
o
|
|
433
433
|
);
|
|
434
434
|
}
|
|
@@ -456,20 +456,20 @@ function se(e) {
|
|
|
456
456
|
getAdapters: a,
|
|
457
457
|
shouldSync: i = () => !0,
|
|
458
458
|
transformForSync: n,
|
|
459
|
-
syncPermissions:
|
|
459
|
+
syncPermissions: d = !0
|
|
460
460
|
} = e;
|
|
461
461
|
return {
|
|
462
462
|
async afterCreate(l, c) {
|
|
463
463
|
if (c.id !== t)
|
|
464
464
|
try {
|
|
465
|
-
const r = await s(), f = await a(c.id),
|
|
466
|
-
(
|
|
465
|
+
const r = await s(), f = await a(c.id), u = await S(
|
|
466
|
+
(m) => r.roles.list(t, m),
|
|
467
467
|
"roles",
|
|
468
468
|
{ cursorField: "id", pageSize: 100 }
|
|
469
469
|
), o = /* @__PURE__ */ new Map();
|
|
470
470
|
if (await Promise.all(
|
|
471
|
-
|
|
472
|
-
const g =
|
|
471
|
+
u.filter((m) => i(m)).map(async (m) => {
|
|
472
|
+
const g = m;
|
|
473
473
|
try {
|
|
474
474
|
const h = n ? n(g, c.id) : {
|
|
475
475
|
name: g.name,
|
|
@@ -486,12 +486,12 @@ function se(e) {
|
|
|
486
486
|
);
|
|
487
487
|
}
|
|
488
488
|
})
|
|
489
|
-
),
|
|
490
|
-
for (const [
|
|
489
|
+
), d)
|
|
490
|
+
for (const [m, g] of o)
|
|
491
491
|
try {
|
|
492
492
|
const h = await r.rolePermissions.list(
|
|
493
493
|
t,
|
|
494
|
-
|
|
494
|
+
m,
|
|
495
495
|
{}
|
|
496
496
|
);
|
|
497
497
|
h.length > 0 && await f.rolePermissions.assign(
|
|
@@ -550,47 +550,47 @@ function O(e, t) {
|
|
|
550
550
|
}
|
|
551
551
|
}),
|
|
552
552
|
async (a) => {
|
|
553
|
-
var
|
|
554
|
-
const i = a.req.valid("query"), { page: n, per_page:
|
|
555
|
-
if (
|
|
553
|
+
var m, g, h, A;
|
|
554
|
+
const i = a.req.valid("query"), { page: n, per_page: d, include_totals: l, q: c } = i, r = a.var.user, f = (r == null ? void 0 : r.permissions) || [];
|
|
555
|
+
if (f.includes("auth:read") || f.includes("admin:organizations")) {
|
|
556
556
|
const C = await a.env.data.tenants.list({
|
|
557
557
|
page: n,
|
|
558
|
-
per_page:
|
|
558
|
+
per_page: d,
|
|
559
559
|
include_totals: l,
|
|
560
560
|
q: c
|
|
561
561
|
});
|
|
562
562
|
return l ? a.json({
|
|
563
563
|
tenants: C.tenants,
|
|
564
|
-
start: ((
|
|
565
|
-
limit: ((g = C.totals) == null ? void 0 : g.limit) ??
|
|
564
|
+
start: ((m = C.totals) == null ? void 0 : m.start) ?? 0,
|
|
565
|
+
limit: ((g = C.totals) == null ? void 0 : g.limit) ?? d,
|
|
566
566
|
length: C.tenants.length
|
|
567
567
|
}) : a.json({ tenants: C.tenants });
|
|
568
568
|
}
|
|
569
569
|
if (e.accessControl && (r != null && r.sub)) {
|
|
570
570
|
const C = e.accessControl.controlPlaneTenantId, $ = (await S(
|
|
571
|
-
(
|
|
571
|
+
(z) => a.env.data.userOrganizations.listUserOrganizations(
|
|
572
572
|
C,
|
|
573
573
|
r.sub,
|
|
574
|
-
|
|
574
|
+
z
|
|
575
575
|
),
|
|
576
576
|
"organizations"
|
|
577
|
-
)).map((
|
|
577
|
+
)).map((z) => z.name);
|
|
578
578
|
if ($.length === 0)
|
|
579
579
|
return l ? a.json({
|
|
580
580
|
tenants: [],
|
|
581
581
|
start: 0,
|
|
582
|
-
limit:
|
|
582
|
+
limit: d ?? 50,
|
|
583
583
|
length: 0
|
|
584
584
|
}) : a.json({ tenants: [] });
|
|
585
|
-
const
|
|
586
|
-
if (
|
|
585
|
+
const R = $.length, I = n ?? 0, v = d ?? 50, w = I * v, p = $.slice(w, w + v);
|
|
586
|
+
if (p.length === 0)
|
|
587
587
|
return l ? a.json({
|
|
588
588
|
tenants: [],
|
|
589
589
|
start: w,
|
|
590
590
|
limit: v,
|
|
591
|
-
length:
|
|
591
|
+
length: R
|
|
592
592
|
}) : a.json({ tenants: [] });
|
|
593
|
-
const y =
|
|
593
|
+
const y = p.map((z) => `id:${z}`).join(" OR "), _ = c ? `(${y}) AND (${c})` : y, b = await a.env.data.tenants.list({
|
|
594
594
|
q: _,
|
|
595
595
|
per_page: v,
|
|
596
596
|
include_totals: !1
|
|
@@ -600,19 +600,19 @@ function O(e, t) {
|
|
|
600
600
|
tenants: b.tenants,
|
|
601
601
|
start: w,
|
|
602
602
|
limit: v,
|
|
603
|
-
length:
|
|
603
|
+
length: R
|
|
604
604
|
}) : a.json({ tenants: b.tenants });
|
|
605
605
|
}
|
|
606
606
|
const o = await a.env.data.tenants.list({
|
|
607
607
|
page: n,
|
|
608
|
-
per_page:
|
|
608
|
+
per_page: d,
|
|
609
609
|
include_totals: l,
|
|
610
610
|
q: c
|
|
611
611
|
});
|
|
612
612
|
return l ? a.json({
|
|
613
613
|
tenants: o.tenants,
|
|
614
614
|
start: ((h = o.totals) == null ? void 0 : h.start) ?? 0,
|
|
615
|
-
limit: ((A = o.totals) == null ? void 0 : A.limit) ??
|
|
615
|
+
limit: ((A = o.totals) == null ? void 0 : A.limit) ?? d,
|
|
616
616
|
length: o.tenants.length
|
|
617
617
|
}) : a.json({ tenants: o.tenants });
|
|
618
618
|
}
|
|
@@ -660,13 +660,13 @@ function O(e, t) {
|
|
|
660
660
|
message: "Authentication required to create tenants"
|
|
661
661
|
});
|
|
662
662
|
let n = a.req.valid("json");
|
|
663
|
-
const
|
|
663
|
+
const d = {
|
|
664
664
|
adapters: a.env.data,
|
|
665
665
|
ctx: a
|
|
666
666
|
};
|
|
667
|
-
(c = t.tenants) != null && c.beforeCreate && (n = await t.tenants.beforeCreate(
|
|
667
|
+
(c = t.tenants) != null && c.beforeCreate && (n = await t.tenants.beforeCreate(d, n));
|
|
668
668
|
const l = await a.env.data.tenants.create(n);
|
|
669
|
-
return (r = t.tenants) != null && r.afterCreate && await t.tenants.afterCreate(
|
|
669
|
+
return (r = t.tenants) != null && r.afterCreate && await t.tenants.afterCreate(d, l), a.json(l, 201);
|
|
670
670
|
}
|
|
671
671
|
), s.openapi(
|
|
672
672
|
M({
|
|
@@ -709,13 +709,13 @@ function O(e, t) {
|
|
|
709
709
|
message: "Cannot delete the control plane"
|
|
710
710
|
});
|
|
711
711
|
if (!(await S(
|
|
712
|
-
(
|
|
712
|
+
(m) => a.env.data.userOrganizations.listUserOrganizations(
|
|
713
713
|
f,
|
|
714
714
|
r.sub,
|
|
715
|
-
|
|
715
|
+
m
|
|
716
716
|
),
|
|
717
717
|
"organizations"
|
|
718
|
-
)).some((
|
|
718
|
+
)).some((m) => m.name === i))
|
|
719
719
|
throw new T(403, {
|
|
720
720
|
message: "Access denied to this tenant"
|
|
721
721
|
});
|
|
@@ -724,11 +724,11 @@ function O(e, t) {
|
|
|
724
724
|
throw new T(404, {
|
|
725
725
|
message: "Tenant not found"
|
|
726
726
|
});
|
|
727
|
-
const
|
|
727
|
+
const d = {
|
|
728
728
|
adapters: a.env.data,
|
|
729
729
|
ctx: a
|
|
730
730
|
};
|
|
731
|
-
return (l = t.tenants) != null && l.beforeDelete && await t.tenants.beforeDelete(
|
|
731
|
+
return (l = t.tenants) != null && l.beforeDelete && await t.tenants.beforeDelete(d, i), await a.env.data.tenants.remove(i), (c = t.tenants) != null && c.afterDelete && await t.tenants.afterDelete(d, i), a.body(null, 204);
|
|
732
732
|
}
|
|
733
733
|
), s;
|
|
734
734
|
}
|
|
@@ -822,10 +822,10 @@ function ue(e) {
|
|
|
822
822
|
baseDomain: a,
|
|
823
823
|
reservedSubdomains: i = [],
|
|
824
824
|
resolveSubdomain: n
|
|
825
|
-
} = e.subdomainRouting,
|
|
825
|
+
} = e.subdomainRouting, d = t.req.header("host") || "";
|
|
826
826
|
let l = null;
|
|
827
|
-
if (
|
|
828
|
-
const r =
|
|
827
|
+
if (d.endsWith(a)) {
|
|
828
|
+
const r = d.slice(0, -(a.length + 1));
|
|
829
829
|
r && !r.includes(".") && (l = r);
|
|
830
830
|
}
|
|
831
831
|
if (l && i.includes(l) && (l = null), !l)
|
|
@@ -872,7 +872,7 @@ function fe(e) {
|
|
|
872
872
|
return s();
|
|
873
873
|
};
|
|
874
874
|
}
|
|
875
|
-
function
|
|
875
|
+
function U(e) {
|
|
876
876
|
const t = ue(e), s = de(e), a = fe(e);
|
|
877
877
|
return async (i, n) => (await t(i, async () => {
|
|
878
878
|
}), await s(i, async () => {
|
|
@@ -880,11 +880,11 @@ function N(e) {
|
|
|
880
880
|
}), n());
|
|
881
881
|
}
|
|
882
882
|
function _e(e) {
|
|
883
|
-
const t =
|
|
883
|
+
const t = F(e);
|
|
884
884
|
return {
|
|
885
885
|
name: "multi-tenancy",
|
|
886
886
|
// Apply multi-tenancy middleware for subdomain routing, database resolution, etc.
|
|
887
|
-
middleware:
|
|
887
|
+
middleware: U(e),
|
|
888
888
|
// Provide lifecycle hooks
|
|
889
889
|
hooks: t,
|
|
890
890
|
// Mount tenant management routes
|
|
@@ -904,7 +904,7 @@ function _e(e) {
|
|
|
904
904
|
}
|
|
905
905
|
};
|
|
906
906
|
}
|
|
907
|
-
function
|
|
907
|
+
function F(e) {
|
|
908
908
|
const t = e.accessControl ? X(e.accessControl) : {}, s = e.databaseIsolation ? Z(e.databaseIsolation) : {}, a = k(e);
|
|
909
909
|
return {
|
|
910
910
|
...t,
|
|
@@ -912,15 +912,15 @@ function I(e) {
|
|
|
912
912
|
tenants: a
|
|
913
913
|
};
|
|
914
914
|
}
|
|
915
|
-
function
|
|
916
|
-
const t = new
|
|
915
|
+
function me(e) {
|
|
916
|
+
const t = new N(), s = F(e);
|
|
917
917
|
return t.route("/tenants", O(e, s)), t;
|
|
918
918
|
}
|
|
919
919
|
function Ae(e) {
|
|
920
920
|
return {
|
|
921
|
-
hooks:
|
|
922
|
-
middleware:
|
|
923
|
-
app:
|
|
921
|
+
hooks: F(e),
|
|
922
|
+
middleware: U(e),
|
|
923
|
+
app: me(e),
|
|
924
924
|
config: e
|
|
925
925
|
};
|
|
926
926
|
}
|
|
@@ -931,7 +931,7 @@ function be(e) {
|
|
|
931
931
|
syncRoles: a = !0,
|
|
932
932
|
multiTenancy: i,
|
|
933
933
|
entityHooks: n,
|
|
934
|
-
...
|
|
934
|
+
...d
|
|
935
935
|
} = e, l = {
|
|
936
936
|
...i,
|
|
937
937
|
accessControl: {
|
|
@@ -940,29 +940,29 @@ function be(e) {
|
|
|
940
940
|
defaultPermissions: ["tenant:admin"],
|
|
941
941
|
...i == null ? void 0 : i.accessControl
|
|
942
942
|
}
|
|
943
|
-
}, c =
|
|
943
|
+
}, c = F(l);
|
|
944
944
|
let r, f;
|
|
945
945
|
s && (r = ae({
|
|
946
946
|
controlPlaneTenantId: t,
|
|
947
947
|
getChildTenantIds: async () => (await S(
|
|
948
|
-
(
|
|
948
|
+
(p) => e.dataAdapter.tenants.list(p),
|
|
949
949
|
"tenants",
|
|
950
950
|
{ cursorField: "id", pageSize: 100 }
|
|
951
|
-
)).filter((
|
|
951
|
+
)).filter((p) => p.id !== t).map((p) => p.id),
|
|
952
952
|
getAdapters: async (w) => e.dataAdapter
|
|
953
953
|
}), f = ne({
|
|
954
954
|
controlPlaneTenantId: t,
|
|
955
955
|
getControlPlaneAdapters: async () => e.dataAdapter,
|
|
956
956
|
getAdapters: async (w) => e.dataAdapter
|
|
957
957
|
}));
|
|
958
|
-
let
|
|
959
|
-
a && (
|
|
958
|
+
let u, o;
|
|
959
|
+
a && (u = re({
|
|
960
960
|
controlPlaneTenantId: t,
|
|
961
961
|
getChildTenantIds: async () => (await S(
|
|
962
|
-
(
|
|
962
|
+
(p) => e.dataAdapter.tenants.list(p),
|
|
963
963
|
"tenants",
|
|
964
964
|
{ cursorField: "id", pageSize: 100 }
|
|
965
|
-
)).filter((
|
|
965
|
+
)).filter((p) => p.id !== t).map((p) => p.id),
|
|
966
966
|
getAdapters: async (w) => e.dataAdapter
|
|
967
967
|
}), o = se({
|
|
968
968
|
controlPlaneTenantId: t,
|
|
@@ -970,7 +970,7 @@ function be(e) {
|
|
|
970
970
|
getAdapters: async (w) => e.dataAdapter,
|
|
971
971
|
syncPermissions: !0
|
|
972
972
|
}));
|
|
973
|
-
const
|
|
973
|
+
const m = async (w, p, ...y) => {
|
|
974
974
|
const _ = [];
|
|
975
975
|
if (w)
|
|
976
976
|
try {
|
|
@@ -978,9 +978,9 @@ function be(e) {
|
|
|
978
978
|
} catch (b) {
|
|
979
979
|
_.push(b instanceof Error ? b : new Error(String(b)));
|
|
980
980
|
}
|
|
981
|
-
if (
|
|
981
|
+
if (p)
|
|
982
982
|
try {
|
|
983
|
-
await
|
|
983
|
+
await p(...y);
|
|
984
984
|
} catch (b) {
|
|
985
985
|
_.push(b instanceof Error ? b : new Error(String(b)));
|
|
986
986
|
}
|
|
@@ -991,12 +991,12 @@ function be(e) {
|
|
|
991
991
|
_,
|
|
992
992
|
`Multiple hook errors: ${_.map((b) => b.message).join("; ")}`
|
|
993
993
|
);
|
|
994
|
-
}, g = async (w, ...
|
|
994
|
+
}, g = async (w, ...p) => {
|
|
995
995
|
const y = [];
|
|
996
996
|
for (const _ of w)
|
|
997
997
|
if (_)
|
|
998
998
|
try {
|
|
999
|
-
await _(...
|
|
999
|
+
await _(...p);
|
|
1000
1000
|
} catch (b) {
|
|
1001
1001
|
y.push(
|
|
1002
1002
|
b instanceof Error ? b : new Error(String(b))
|
|
@@ -1013,69 +1013,69 @@ function be(e) {
|
|
|
1013
1013
|
...n,
|
|
1014
1014
|
resourceServers: r ? {
|
|
1015
1015
|
...n == null ? void 0 : n.resourceServers,
|
|
1016
|
-
afterCreate: async (w,
|
|
1016
|
+
afterCreate: async (w, p) => {
|
|
1017
1017
|
var y;
|
|
1018
|
-
await
|
|
1018
|
+
await m(
|
|
1019
1019
|
(y = n == null ? void 0 : n.resourceServers) == null ? void 0 : y.afterCreate,
|
|
1020
1020
|
r == null ? void 0 : r.afterCreate,
|
|
1021
1021
|
w,
|
|
1022
|
-
|
|
1022
|
+
p
|
|
1023
1023
|
);
|
|
1024
1024
|
},
|
|
1025
|
-
afterUpdate: async (w,
|
|
1025
|
+
afterUpdate: async (w, p, y) => {
|
|
1026
1026
|
var _;
|
|
1027
|
-
await
|
|
1027
|
+
await m(
|
|
1028
1028
|
(_ = n == null ? void 0 : n.resourceServers) == null ? void 0 : _.afterUpdate,
|
|
1029
1029
|
r == null ? void 0 : r.afterUpdate,
|
|
1030
1030
|
w,
|
|
1031
|
-
|
|
1031
|
+
p,
|
|
1032
1032
|
y
|
|
1033
1033
|
);
|
|
1034
1034
|
},
|
|
1035
|
-
afterDelete: async (w,
|
|
1035
|
+
afterDelete: async (w, p) => {
|
|
1036
1036
|
var y;
|
|
1037
|
-
await
|
|
1037
|
+
await m(
|
|
1038
1038
|
(y = n == null ? void 0 : n.resourceServers) == null ? void 0 : y.afterDelete,
|
|
1039
1039
|
r == null ? void 0 : r.afterDelete,
|
|
1040
1040
|
w,
|
|
1041
|
-
|
|
1041
|
+
p
|
|
1042
1042
|
);
|
|
1043
1043
|
}
|
|
1044
1044
|
} : n == null ? void 0 : n.resourceServers,
|
|
1045
|
-
roles:
|
|
1045
|
+
roles: u ? {
|
|
1046
1046
|
...n == null ? void 0 : n.roles,
|
|
1047
|
-
afterCreate: async (w,
|
|
1047
|
+
afterCreate: async (w, p) => {
|
|
1048
1048
|
var y;
|
|
1049
|
-
await
|
|
1049
|
+
await m(
|
|
1050
1050
|
(y = n == null ? void 0 : n.roles) == null ? void 0 : y.afterCreate,
|
|
1051
|
-
|
|
1051
|
+
u == null ? void 0 : u.afterCreate,
|
|
1052
1052
|
w,
|
|
1053
|
-
|
|
1053
|
+
p
|
|
1054
1054
|
);
|
|
1055
1055
|
},
|
|
1056
|
-
afterUpdate: async (w,
|
|
1056
|
+
afterUpdate: async (w, p, y) => {
|
|
1057
1057
|
var _;
|
|
1058
|
-
await
|
|
1058
|
+
await m(
|
|
1059
1059
|
(_ = n == null ? void 0 : n.roles) == null ? void 0 : _.afterUpdate,
|
|
1060
|
-
|
|
1060
|
+
u == null ? void 0 : u.afterUpdate,
|
|
1061
1061
|
w,
|
|
1062
|
-
|
|
1062
|
+
p,
|
|
1063
1063
|
y
|
|
1064
1064
|
);
|
|
1065
1065
|
},
|
|
1066
|
-
afterDelete: async (w,
|
|
1066
|
+
afterDelete: async (w, p) => {
|
|
1067
1067
|
var y;
|
|
1068
|
-
await
|
|
1068
|
+
await m(
|
|
1069
1069
|
(y = n == null ? void 0 : n.roles) == null ? void 0 : y.afterDelete,
|
|
1070
|
-
|
|
1070
|
+
u == null ? void 0 : u.afterDelete,
|
|
1071
1071
|
w,
|
|
1072
|
-
|
|
1072
|
+
p
|
|
1073
1073
|
);
|
|
1074
1074
|
}
|
|
1075
1075
|
} : n == null ? void 0 : n.roles,
|
|
1076
1076
|
tenants: f || o ? {
|
|
1077
1077
|
...n == null ? void 0 : n.tenants,
|
|
1078
|
-
afterCreate: async (w,
|
|
1078
|
+
afterCreate: async (w, p) => {
|
|
1079
1079
|
var y;
|
|
1080
1080
|
await g(
|
|
1081
1081
|
[
|
|
@@ -1084,7 +1084,7 @@ function be(e) {
|
|
|
1084
1084
|
o == null ? void 0 : o.afterCreate
|
|
1085
1085
|
],
|
|
1086
1086
|
w,
|
|
1087
|
-
|
|
1087
|
+
p
|
|
1088
1088
|
);
|
|
1089
1089
|
}
|
|
1090
1090
|
} : n == null ? void 0 : n.tenants
|
|
@@ -1092,15 +1092,15 @@ function be(e) {
|
|
|
1092
1092
|
...c,
|
|
1093
1093
|
tenants: f || o ? {
|
|
1094
1094
|
...c.tenants,
|
|
1095
|
-
afterCreate: async (w,
|
|
1095
|
+
afterCreate: async (w, p) => {
|
|
1096
1096
|
var y;
|
|
1097
|
-
(y = c.tenants) != null && y.afterCreate && await c.tenants.afterCreate(w,
|
|
1097
|
+
(y = c.tenants) != null && y.afterCreate && await c.tenants.afterCreate(w, p), await g(
|
|
1098
1098
|
[
|
|
1099
1099
|
f == null ? void 0 : f.afterCreate,
|
|
1100
1100
|
o == null ? void 0 : o.afterCreate
|
|
1101
1101
|
],
|
|
1102
1102
|
w,
|
|
1103
|
-
|
|
1103
|
+
p
|
|
1104
1104
|
);
|
|
1105
1105
|
}
|
|
1106
1106
|
} : c.tenants
|
|
@@ -1108,19 +1108,19 @@ function be(e) {
|
|
|
1108
1108
|
l,
|
|
1109
1109
|
A
|
|
1110
1110
|
), j = L({
|
|
1111
|
-
...
|
|
1111
|
+
...d,
|
|
1112
1112
|
entityHooks: h,
|
|
1113
1113
|
// Register tenant routes via the extension mechanism
|
|
1114
1114
|
// This ensures they go through the full middleware chain (caching, tenant, auth, entity hooks)
|
|
1115
1115
|
managementApiExtensions: [
|
|
1116
|
-
...
|
|
1116
|
+
...d.managementApiExtensions || [],
|
|
1117
1117
|
{ path: "/tenants", router: C }
|
|
1118
1118
|
]
|
|
1119
|
-
}), { app: $, managementApp:
|
|
1120
|
-
return v.onError((w,
|
|
1119
|
+
}), { app: $, managementApp: R, ...I } = j, v = new N();
|
|
1120
|
+
return v.onError((w, p) => w instanceof T ? w.getResponse() : (console.error(w), p.json({ message: "Internal Server Error" }, 500))), v.use("/api/v2/*", le()), v.route("/", $), {
|
|
1121
1121
|
app: v,
|
|
1122
|
-
managementApp:
|
|
1123
|
-
...
|
|
1122
|
+
managementApp: R,
|
|
1123
|
+
...I,
|
|
1124
1124
|
multiTenancyConfig: l,
|
|
1125
1125
|
multiTenancyHooks: c
|
|
1126
1126
|
};
|
|
@@ -1131,9 +1131,9 @@ export {
|
|
|
1131
1131
|
de as createAccessControlMiddleware,
|
|
1132
1132
|
Z as createDatabaseHooks,
|
|
1133
1133
|
fe as createDatabaseMiddleware,
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1134
|
+
me as createMultiTenancy,
|
|
1135
|
+
F as createMultiTenancyHooks,
|
|
1136
|
+
U as createMultiTenancyMiddleware,
|
|
1137
1137
|
_e as createMultiTenancyPlugin,
|
|
1138
1138
|
le as createProtectSyncedMiddleware,
|
|
1139
1139
|
k as createProvisioningHooks,
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/markusahlstrand/authhero"
|
|
13
13
|
},
|
|
14
|
-
"version": "13.
|
|
14
|
+
"version": "13.13.2",
|
|
15
15
|
"description": "Multi-tenancy support for AuthHero with organization-based access control and per-tenant database isolation",
|
|
16
16
|
"files": [
|
|
17
17
|
"dist"
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"zod": "^3.24.0",
|
|
44
|
-
"
|
|
45
|
-
"authhero": "
|
|
44
|
+
"authhero": "2.0.0",
|
|
45
|
+
"@authhero/adapter-interfaces": "0.115.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@hono/zod-openapi": "^0.19.10",
|