@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.
@@ -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;
@@ -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, any>;
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, any>;
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, any>;
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 OnExecuteValidateSignupEmail = OnExecuteValidateRegistrationUsername;
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.
@@ -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 U } from "hono";
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, u = a.var.organization_id, l = n || u;
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 u = (await t.adapters.organizations.list(
86
+ const d = (await t.adapters.organizations.list(
87
87
  a.controlPlaneTenantId
88
88
  )).organizations.find((l) => l.name === s);
89
- u && await t.adapters.organizations.remove(
89
+ d && await t.adapters.organizations.remove(
90
90
  a.controlPlaneTenantId,
91
- u.id
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: u,
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 d;
128
- if (u && (d = await ee(
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
- }), d && await e.adapters.userRoles.create(
144
+ }), u && await e.adapters.userRoles.create(
145
145
  a,
146
146
  o.sub,
147
- d,
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 u = await e.adapters.roles.create(t, {
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: u.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
- u.id,
197
+ d.id,
198
198
  c
199
- ), u.id;
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 u = { ...n };
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 u[c];
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
- u = c;
227
+ d = c;
228
228
  }
229
229
  if (i != null && i.excludedKeys)
230
230
  for (const c of i.excludedKeys)
231
- delete u[c];
232
- i != null && i.transformSettings && (u = i.transformSettings(
233
- u,
231
+ delete d[c];
232
+ i != null && i.transformSettings && (d = i.transformSettings(
233
+ d,
234
234
  t.id
235
- )), Object.keys(u).length > 0 && await e.adapters.tenants.update(t.id, u);
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 u(r, f, d) {
245
+ async function d(r, f, u) {
246
246
  return (await r.resourceServers.list(f, {
247
- q: `identifier:${d}`,
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 d = await s();
252
+ const u = await s();
253
253
  await Promise.all(
254
- d.map(async (o) => {
254
+ u.map(async (o) => {
255
255
  try {
256
- const p = await a(o), h = { ...n ? n(r, o) : {
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 u(
271
- p,
270
+ const A = await d(
271
+ m,
272
272
  o,
273
273
  r.identifier
274
274
  );
275
- A && A.id ? await p.resourceServers.update(
275
+ A && A.id ? await m.resourceServers.update(
276
276
  o,
277
277
  A.id,
278
278
  h
279
- ) : await p.resourceServers.create(o, h);
279
+ ) : await m.resourceServers.create(o, h);
280
280
  } else {
281
- const A = await u(
282
- p,
281
+ const A = await d(
282
+ m,
283
283
  o,
284
284
  r.identifier
285
285
  );
286
- A && A.id ? await p.resourceServers.update(
286
+ A && A.id ? await m.resourceServers.update(
287
287
  o,
288
288
  A.id,
289
289
  h
290
- ) : await p.resourceServers.create(o, h);
290
+ ) : await m.resourceServers.create(o, h);
291
291
  }
292
- } catch (p) {
292
+ } catch (m) {
293
293
  console.error(
294
294
  `Failed to sync resource server "${r.identifier}" to tenant "${o}":`,
295
- p
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 (d) => {
304
+ f.map(async (u) => {
305
305
  try {
306
- const o = await a(d), p = await u(
306
+ const o = await a(u), m = await d(
307
307
  o,
308
- d,
308
+ u,
309
309
  r
310
310
  );
311
- p && p.id && await o.resourceServers.remove(d, p.id);
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 "${d}":`,
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, d) => {
326
- r.tenantId === t && i(d) && await l(d, "update");
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(u, l) {
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
- (d) => c.resourceServers.list(
346
+ (u) => c.resourceServers.list(
347
347
  t,
348
- d
348
+ u
349
349
  ),
350
350
  "resource_servers",
351
351
  { cursorField: "id", pageSize: 100 }
352
352
  );
353
353
  await Promise.all(
354
- f.filter((d) => i(d)).map(async (d) => {
355
- const o = d;
354
+ f.filter((u) => i(u)).map(async (u) => {
355
+ const o = u;
356
356
  try {
357
- const p = n ? n(o, l.id) : {
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
- ...p,
371
+ ...m,
372
372
  is_system: !0
373
373
  });
374
- } catch (p) {
374
+ } catch (m) {
375
375
  console.error(
376
376
  `Failed to sync resource server "${o.identifier}" to new tenant "${l.id}":`,
377
- p
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 u(c, r, f) {
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 (d) => {
408
+ f.map(async (u) => {
409
409
  try {
410
- const o = await a(d), g = { ...n ? n(c, d) : {
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 u(o, d, c.name);
415
+ const h = await d(o, u, c.name);
416
416
  h && h.id ? await o.roles.update(
417
- d,
417
+ u,
418
418
  h.id,
419
419
  g
420
- ) : await o.roles.create(d, g);
420
+ ) : await o.roles.create(u, g);
421
421
  } else {
422
- const h = await u(o, d, c.name);
422
+ const h = await d(o, u, c.name);
423
423
  h && h.id ? await o.roles.update(
424
- d,
424
+ u,
425
425
  h.id,
426
426
  g
427
- ) : await o.roles.create(d, g);
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 "${d}":`,
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: u = !0
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), d = await S(
466
- (p) => r.roles.list(t, p),
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
- d.filter((p) => i(p)).map(async (p) => {
472
- const g = p;
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
- ), u)
490
- for (const [p, g] of o)
489
+ ), d)
490
+ for (const [m, g] of o)
491
491
  try {
492
492
  const h = await r.rolePermissions.list(
493
493
  t,
494
- p,
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 p, g, h, A;
554
- 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");
555
- if (console.log("User scopes:", f, "hasAuthRead:", d), d) {
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: u,
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: ((p = C.totals) == null ? void 0 : p.start) ?? 0,
565
- limit: ((g = C.totals) == null ? void 0 : g.limit) ?? u,
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
- (R) => a.env.data.userOrganizations.listUserOrganizations(
571
+ (z) => a.env.data.userOrganizations.listUserOrganizations(
572
572
  C,
573
573
  r.sub,
574
- R
574
+ z
575
575
  ),
576
576
  "organizations"
577
- )).map((R) => R.name);
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: u ?? 50,
582
+ limit: d ?? 50,
583
583
  length: 0
584
584
  }) : a.json({ tenants: [] });
585
- const z = $.length, F = n ?? 0, v = u ?? 50, w = F * v, m = $.slice(w, w + v);
586
- if (m.length === 0)
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: z
591
+ length: R
592
592
  }) : a.json({ tenants: [] });
593
- const y = m.map((R) => `id:${R}`).join(" OR "), _ = c ? `(${y}) AND (${c})` : y, b = await a.env.data.tenants.list({
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: z
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: u,
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) ?? u,
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 u = {
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(u, n));
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(u, l), a.json(l, 201);
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
- (p) => a.env.data.userOrganizations.listUserOrganizations(
712
+ (m) => a.env.data.userOrganizations.listUserOrganizations(
713
713
  f,
714
714
  r.sub,
715
- p
715
+ m
716
716
  ),
717
717
  "organizations"
718
- )).some((p) => p.name === i))
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 u = {
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(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);
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, u = t.req.header("host") || "";
825
+ } = e.subdomainRouting, d = t.req.header("host") || "";
826
826
  let l = null;
827
- if (u.endsWith(a)) {
828
- const r = u.slice(0, -(a.length + 1));
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 N(e) {
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 = I(e);
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: N(e),
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 I(e) {
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 pe(e) {
916
- const t = new U(), s = I(e);
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: I(e),
922
- middleware: N(e),
923
- app: pe(e),
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
- ...u
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 = I(l);
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
- (m) => e.dataAdapter.tenants.list(m),
948
+ (p) => e.dataAdapter.tenants.list(p),
949
949
  "tenants",
950
950
  { cursorField: "id", pageSize: 100 }
951
- )).filter((m) => m.id !== t).map((m) => m.id),
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 d, o;
959
- a && (d = re({
958
+ let u, o;
959
+ a && (u = re({
960
960
  controlPlaneTenantId: t,
961
961
  getChildTenantIds: async () => (await S(
962
- (m) => e.dataAdapter.tenants.list(m),
962
+ (p) => e.dataAdapter.tenants.list(p),
963
963
  "tenants",
964
964
  { cursorField: "id", pageSize: 100 }
965
- )).filter((m) => m.id !== t).map((m) => m.id),
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 p = async (w, m, ...y) => {
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 (m)
981
+ if (p)
982
982
  try {
983
- await m(...y);
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, ...m) => {
994
+ }, g = async (w, ...p) => {
995
995
  const y = [];
996
996
  for (const _ of w)
997
997
  if (_)
998
998
  try {
999
- await _(...m);
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, m) => {
1016
+ afterCreate: async (w, p) => {
1017
1017
  var y;
1018
- await p(
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
- m
1022
+ p
1023
1023
  );
1024
1024
  },
1025
- afterUpdate: async (w, m, y) => {
1025
+ afterUpdate: async (w, p, y) => {
1026
1026
  var _;
1027
- await p(
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
- m,
1031
+ p,
1032
1032
  y
1033
1033
  );
1034
1034
  },
1035
- afterDelete: async (w, m) => {
1035
+ afterDelete: async (w, p) => {
1036
1036
  var y;
1037
- await p(
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
- m
1041
+ p
1042
1042
  );
1043
1043
  }
1044
1044
  } : n == null ? void 0 : n.resourceServers,
1045
- roles: d ? {
1045
+ roles: u ? {
1046
1046
  ...n == null ? void 0 : n.roles,
1047
- afterCreate: async (w, m) => {
1047
+ afterCreate: async (w, p) => {
1048
1048
  var y;
1049
- await p(
1049
+ await m(
1050
1050
  (y = n == null ? void 0 : n.roles) == null ? void 0 : y.afterCreate,
1051
- d == null ? void 0 : d.afterCreate,
1051
+ u == null ? void 0 : u.afterCreate,
1052
1052
  w,
1053
- m
1053
+ p
1054
1054
  );
1055
1055
  },
1056
- afterUpdate: async (w, m, y) => {
1056
+ afterUpdate: async (w, p, y) => {
1057
1057
  var _;
1058
- await p(
1058
+ await m(
1059
1059
  (_ = n == null ? void 0 : n.roles) == null ? void 0 : _.afterUpdate,
1060
- d == null ? void 0 : d.afterUpdate,
1060
+ u == null ? void 0 : u.afterUpdate,
1061
1061
  w,
1062
- m,
1062
+ p,
1063
1063
  y
1064
1064
  );
1065
1065
  },
1066
- afterDelete: async (w, m) => {
1066
+ afterDelete: async (w, p) => {
1067
1067
  var y;
1068
- await p(
1068
+ await m(
1069
1069
  (y = n == null ? void 0 : n.roles) == null ? void 0 : y.afterDelete,
1070
- d == null ? void 0 : d.afterDelete,
1070
+ u == null ? void 0 : u.afterDelete,
1071
1071
  w,
1072
- m
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, m) => {
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
- m
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, m) => {
1095
+ afterCreate: async (w, p) => {
1096
1096
  var y;
1097
- (y = c.tenants) != null && y.afterCreate && await c.tenants.afterCreate(w, m), await g(
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
- m
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
- ...u,
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
- ...u.managementApiExtensions || [],
1116
+ ...d.managementApiExtensions || [],
1117
1117
  { path: "/tenants", router: C }
1118
1118
  ]
1119
- }), { app: $, managementApp: z, ...F } = j, v = new U();
1120
- return v.onError((w, m) => w instanceof T ? w.getResponse() : (console.error(w), m.json({ message: "Internal Server Error" }, 500))), v.use("/api/v2/*", le()), v.route("/", $), {
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: z,
1123
- ...F,
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
- pe as createMultiTenancy,
1135
- I as createMultiTenancyHooks,
1136
- N as createMultiTenancyMiddleware,
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.12.1",
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
- "@authhero/adapter-interfaces": "0.115.0",
45
- "authhero": "1.3.0"
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",