@authhero/multi-tenancy 14.6.0 → 14.7.0

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 ae=Object.defineProperty;var re=(t,e,n)=>e in t?ae(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var D=(t,e,n)=>re(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const se=require("hono"),y=require("authhero"),S=require("@hono/zod-openapi");function B(t){const{controlPlaneTenantId:e,requireOrganizationMatch:n=!0}=t;return{async onTenantAccessValidation(a,s){if(s===e)return!0;if(n){const c=a.var.org_name,l=a.var.organization_id,r=c||l;return r?r.toLowerCase()===s.toLowerCase():!1}return!0}}}function K(t,e,n,a){if(e===n)return!0;const s=a||t;return s?s.toLowerCase()===e.toLowerCase():!1}function V(t){return{async resolveDataAdapters(e){try{return await t.getAdapters(e)}catch(n){console.error(`Failed to resolve data adapters for tenant ${e}:`,n);return}}}}function oe(t){return`urn:authhero:tenant:${t.toLowerCase()}`}function W(t){return{async beforeCreate(e,n){return!n.audience&&n.id?{...n,audience:oe(n.id)}:n},async afterCreate(e,n){const{accessControl:a,databaseIsolation:s}=t;a&&e.ctx&&await ie(e,n,a),s!=null&&s.onProvision&&await s.onProvision(n.id)},async beforeDelete(e,n){const{accessControl:a,databaseIsolation:s}=t;if(a)try{const l=(await e.adapters.organizations.list(a.controlPlaneTenantId)).organizations.find(r=>r.name===n);l&&await e.adapters.organizations.remove(a.controlPlaneTenantId,l.id)}catch(c){console.warn(`Failed to remove organization for tenant ${n}:`,c)}if(s!=null&&s.onDeprovision)try{await s.onDeprovision(n)}catch(c){console.warn(`Failed to deprovision database for tenant ${n}:`,c)}}}}async function ie(t,e,n){const{controlPlaneTenantId:a,defaultPermissions:s,defaultRoles:c,issuer:l,adminRoleName:r="Tenant Admin",adminRoleDescription:p="Full access to all tenant management operations",addCreatorToOrganization:o=!0}=n,i=await t.adapters.organizations.create(a,{name:e.id,display_name:e.friendly_name||e.id});let f;if(l&&(f=await le(t,a,r,p)),o&&t.ctx){const d=t.ctx.var.user;if(d!=null&&d.sub&&!await ce(t,a,d.sub))try{await t.adapters.userOrganizations.create(a,{user_id:d.sub,organization_id:i.id}),f&&await t.adapters.userRoles.create(a,d.sub,f,i.id)}catch(m){console.warn(`Failed to add creator ${d.sub} to organization ${i.id}:`,m)}}c&&c.length>0&&console.log(`Would assign roles ${c.join(", ")} to organization ${i.id}`),s&&s.length>0&&console.log(`Would grant permissions ${s.join(", ")} to organization ${i.id}`)}async function ce(t,e,n){const a=await t.adapters.userRoles.list(e,n,void 0,"");for(const s of a)if((await t.adapters.rolePermissions.list(e,s.id,{per_page:1e3})).some(r=>r.permission_name==="admin:organizations"))return!0;return!1}async function le(t,e,n,a){const c=(await t.adapters.roles.list(e,{})).roles.find(o=>o.name===n);if(c)return c.id;const l=await t.adapters.roles.create(e,{name:n,description:a}),r=y.MANAGEMENT_API_AUDIENCE,p=y.MANAGEMENT_API_SCOPES.map(o=>({role_id:l.id,resource_server_identifier:r,permission_name:o.value}));return await t.adapters.rolePermissions.assign(e,l.id,p),l.id}function N(t,e,n=()=>!0){const{controlPlaneTenantId:a,getChildTenantIds:s,getAdapters:c}=t,l=new Map;async function r(i,f,d){return(await e(i).list(f,{q:`name:${d}`,per_page:1}))[0]??null}async function p(i){const f=await s(),d=e(await c(a));await Promise.all(f.map(async u=>{try{const m=await c(u),g=e(m),w={...d.transform(i),is_system:!0},h=await r(m,u,i.name),_=h?g.getId(h):void 0;if(h&&_){const A=g.preserveOnUpdate?g.preserveOnUpdate(h,w):w;await g.update(u,_,A)}else await g.create(u,w)}catch(m){console.error(`Failed to sync ${d.listKey} "${i.name}" to tenant "${u}":`,m)}}))}async function o(i){const f=await s();await Promise.all(f.map(async d=>{try{const u=await c(d),m=e(u),g=await r(u,d,i),v=g?m.getId(g):void 0;g&&v&&await m.remove(d,v)}catch(u){console.error(`Failed to delete entity "${i}" from tenant "${d}":`,u)}}))}return{afterCreate:async(i,f)=>{i.tenantId===a&&n(f)&&await p(f)},afterUpdate:async(i,f,d)=>{i.tenantId===a&&n(d)&&await p(d)},beforeDelete:async(i,f)=>{if(i.tenantId!==a)return;const u=await e(i.adapters).get(i.tenantId,f);u&&n(u)&&l.set(f,u)},afterDelete:async(i,f)=>{if(i.tenantId!==a)return;const d=l.get(f);d&&(l.delete(f),await o(d.name))}}}function H(t,e,n=()=>!0){const{controlPlaneTenantId:a,getControlPlaneAdapters:s,getAdapters:c}=t;return{async afterCreate(l,r){if(r.id!==a)try{const p=await s(),o=await c(r.id),i=e(p),f=e(o),d=await y.fetchAll(u=>i.listPaginated(a,u),i.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(u=>n(u)).map(async u=>{try{const m=i.transform(u);await f.create(r.id,{...m,is_system:!0})}catch(m){console.error(`Failed to sync entity to new tenant "${r.id}":`,m)}}))}catch(p){console.error(`Failed to sync entities to new tenant "${r.id}":`,p)}}}}const G=t=>({list:async(e,n)=>(await t.resourceServers.list(e,n)).resource_servers,listPaginated:(e,n)=>t.resourceServers.list(e,n),get:(e,n)=>t.resourceServers.get(e,n),create:(e,n)=>t.resourceServers.create(e,n),update:(e,n,a)=>t.resourceServers.update(e,n,a),remove:(e,n)=>t.resourceServers.remove(e,n),listKey:"resource_servers",getId:e=>e.id,transform:e=>({id:e.id,name:e.name,identifier:e.identifier,scopes:e.scopes,signing_alg:e.signing_alg,token_lifetime:e.token_lifetime,token_lifetime_for_web:e.token_lifetime_for_web})}),L=t=>({list:async(e,n)=>(await t.roles.list(e,n)).roles,listPaginated:(e,n)=>t.roles.list(e,n),get:(e,n)=>t.roles.get(e,n),create:(e,n)=>t.roles.create(e,n),update:(e,n,a)=>t.roles.update(e,n,a),remove:(e,n)=>t.roles.remove(e,n),listKey:"roles",getId:e=>e.id,transform:e=>({id:e.id,name:e.name,description:e.description})});function U(t){var e;return((e=t.metadata)==null?void 0:e.sync)!==!1}function Q(t){const{sync:e={},filters:n={}}=t,a=e.resourceServers??!0,s=e.roles??!0,c=m=>U(m)?n.resourceServers?n.resourceServers(m):!0:!1,l=m=>U(m)?n.roles?n.roles(m):!0:!1,r=a?N(t,G,c):void 0,p=s?N(t,L,l):void 0,o=a?H(t,G,c):void 0,i=s?H(t,L,l):void 0,f=s?{async afterCreate(m,g){var v;if(g.id!==t.controlPlaneTenantId){await((v=i==null?void 0:i.afterCreate)==null?void 0:v.call(i,m,g));try{const w=await t.getControlPlaneAdapters(),h=await t.getAdapters(g.id),_=await y.fetchAll(b=>w.roles.list(t.controlPlaneTenantId,b),"roles",{cursorField:"id",pageSize:100}),A=new Map;for(const b of _.filter(T=>{var C;return((C=n.roles)==null?void 0:C.call(n,T))??!0})){const T=await d(h,g.id,b.name);T&&A.set(b.name,T.id)}for(const b of _.filter(T=>{var C;return((C=n.roles)==null?void 0:C.call(n,T))??!0})){const T=A.get(b.name);if(T)try{const C=await w.rolePermissions.list(t.controlPlaneTenantId,b.id,{});C.length>0&&await h.rolePermissions.assign(g.id,T,C.map(P=>({role_id:T,resource_server_identifier:P.resource_server_identifier,permission_name:P.permission_name})))}catch(C){console.error(`Failed to sync permissions for role "${b.name}" to tenant "${g.id}":`,C)}}}catch(w){console.error(`Failed to sync role permissions to tenant "${g.id}":`,w)}}}}:void 0;async function d(m,g,v){return(await m.roles.list(g,{q:`name:${v}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:r,roles:p},tenantHooks:{async afterCreate(m,g){const v=[o==null?void 0:o.afterCreate,(f==null?void 0:f.afterCreate)??(i==null?void 0:i.afterCreate)],w=[];for(const h of v)if(h)try{await h(m,g)}catch(_){w.push(_ instanceof Error?_:new Error(String(_)))}if(w.length===1)throw w[0];if(w.length>1)throw new AggregateError(w,w.map(h=>h.message).join("; "))}}}}var I=class extends Error{constructor(e=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});D(this,"res");D(this,"status");this.res=n==null?void 0:n.res,this.status=e}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function $(t,e){const n=new S.OpenAPIHono;return n.openapi(S.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:y.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:S.z.object({tenants:S.z.array(y.tenantSchema),start:S.z.number().optional(),limit:S.z.number().optional(),length:S.z.number().optional()})}},description:"List of tenants"}}}),async a=>{var m,g,v,w,h,_;const s=a.req.valid("query"),{page:c,per_page:l,include_totals:r,q:p}=s,o=a.var.user,i=(o==null?void 0:o.permissions)||[];if(i.includes("auth:read")||i.includes("admin:organizations")){const A=await a.env.data.tenants.list({page:c,per_page:l,include_totals:r,q:p});return r?a.json({tenants:A.tenants,start:((m=A.totals)==null?void 0:m.start)??0,limit:((g=A.totals)==null?void 0:g.limit)??l,length:A.tenants.length}):a.json({tenants:A.tenants})}const d=((v=t.accessControl)==null?void 0:v.controlPlaneTenantId)??((w=a.env.data.multiTenancyConfig)==null?void 0:w.controlPlaneTenantId);if(d&&(o!=null&&o.sub)){const b=(await y.fetchAll(O=>a.env.data.userOrganizations.listUserOrganizations(d,o.sub,O),"organizations")).map(O=>O.name);if(b.length===0)return r?a.json({tenants:[],start:0,limit:l??50,length:0}):a.json({tenants:[]});const T=b.length,C=c??0,P=l??50,z=C*P,M=b.slice(z,z+P);if(M.length===0)return r?a.json({tenants:[],start:z,limit:P,length:T}):a.json({tenants:[]});const E=M.map(O=>`id:${O}`).join(" OR "),ne=p?`(${E}) AND (${p})`:E,j=await a.env.data.tenants.list({q:ne,per_page:P,include_totals:!1});return r?a.json({tenants:j.tenants,start:z,limit:P,length:T}):a.json({tenants:j.tenants})}const u=await a.env.data.tenants.list({page:c,per_page:l,include_totals:r,q:p});return r?a.json({tenants:u.tenants,start:((h=u.totals)==null?void 0:h.start)??0,limit:((_=u.totals)==null?void 0:_.limit)??l,length:u.tenants.length}):a.json({tenants:u.tenants})}),n.openapi(S.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:y.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:y.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async a=>{var p,o;const s=a.var.user;if(!(s!=null&&s.sub))throw new I(401,{message:"Authentication required to create tenants"});let c=a.req.valid("json");const l={adapters:a.env.data,ctx:a};(p=e.tenants)!=null&&p.beforeCreate&&(c=await e.tenants.beforeCreate(l,c));const r=await a.env.data.tenants.create(c);return(o=e.tenants)!=null&&o.afterCreate&&await e.tenants.afterCreate(l,r),a.json(r,201)}),n.openapi(S.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:S.z.object({id:S.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 p,o,i,f;const{id:s}=a.req.valid("param"),c=((p=t.accessControl)==null?void 0:p.controlPlaneTenantId)??((o=a.env.data.multiTenancyConfig)==null?void 0:o.controlPlaneTenantId);if(c){const d=a.var.user;if(!(d!=null&&d.sub))throw new I(401,{message:"Authentication required"});if(s===c)throw new I(403,{message:"Cannot delete the control plane"});if(!(await y.fetchAll(g=>a.env.data.userOrganizations.listUserOrganizations(c,d.sub,g),"organizations")).some(g=>g.name===s))throw new I(403,{message:"Access denied to this tenant"})}if(!await a.env.data.tenants.get(s))throw new I(404,{message:"Tenant not found"});const r={adapters:a.env.data,ctx:a};return(i=e.tenants)!=null&&i.beforeDelete&&await e.tenants.beforeDelete(r,s),await a.env.data.tenants.remove(s),(f=e.tenants)!=null&&f.afterDelete&&await e.tenants.afterDelete(r,s),a.body(null,204)}),n}function de(t){const e=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:n,type:a}of e){const s=t.match(n);if(s&&s[1])return{type:a,id:s[1]}}return null}async function ue(t,e,n){try{switch(n.type){case"resource_server":{const a=await t.resourceServers.get(e,n.id);return(a==null?void 0:a.is_system)===!0}case"role":{const a=await t.roles.get(e,n.id);return(a==null?void 0:a.is_system)===!0}case"connection":{const a=await t.connections.get(e,n.id);return(a==null?void 0:a.is_system)===!0}default:return!1}}catch{return!1}}function fe(t){return{resource_server:"resource server",role:"role",connection:"connection"}[t]}function J(){return async(t,e)=>{if(!["PATCH","PUT","DELETE"].includes(t.req.method))return e();const n=de(t.req.path);if(!n)return e();const a=t.var.tenant_id||t.req.header("x-tenant-id")||t.req.header("tenant-id");if(!a)return e();if(await ue(t.env.data,a,n))throw new I(403,{message:`This ${fe(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return e()}}const me=["client_secret","app_secret","twilio_token"];function q(t){if(!t)return t;const e={...t};for(const n of me)delete e[n];return e}function X(t,e){const{controlPlaneTenantId:n,controlPlaneClientId:a,excludeSensitiveFields:s=!1}=e;return{...t,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:a},legacyClients:{...t.legacyClients,get:async c=>{var d;const l=await t.legacyClients.get(c);if(!l)return null;const r=a?await t.legacyClients.get(a):void 0,p=await t.connections.list(l.tenant.id),o=n?await t.connections.list(n):{connections:[]},i=p.connections.map(u=>{var w;const m=(w=o.connections)==null?void 0:w.find(h=>h.strategy===u.strategy);if(!(m!=null&&m.options))return u;const g=y.connectionSchema.parse({...m||{},...u}),v=s?q(m.options):m.options;return g.options=y.connectionOptionsSchema.parse({...v||{},...u.options}),g}).filter(u=>u),f={...(r==null?void 0:r.tenant)||{},...l.tenant};return!l.tenant.audience&&((d=r==null?void 0:r.tenant)!=null&&d.audience)&&(f.audience=r.tenant.audience),{...l,web_origins:[...(r==null?void 0:r.web_origins)||[],...l.web_origins||[]],allowed_logout_urls:[...(r==null?void 0:r.allowed_logout_urls)||[],...l.allowed_logout_urls||[]],callbacks:[...(r==null?void 0:r.callbacks)||[],...l.callbacks||[]],connections:i,tenant:f}}},connections:{...t.connections,get:async(c,l)=>{var d;const r=await t.connections.get(c,l);if(!r||!n||c===n)return r;const o=(d=(await t.connections.list(n)).connections)==null?void 0:d.find(u=>u.strategy===r.strategy);if(!(o!=null&&o.options))return r;const i=y.connectionSchema.parse({...o,...r}),f=s?q(o.options):o.options;return i.options=y.connectionOptionsSchema.parse({...f||{},...r.options}),i},list:async(c,l)=>{const r=await t.connections.list(c,l);if(!n||c===n)return r;const p=await t.connections.list(n),o=r.connections.map(i=>{var m;const f=(m=p.connections)==null?void 0:m.find(g=>g.strategy===i.strategy);if(!(f!=null&&f.options))return i;const d=y.connectionSchema.parse({...f,...i}),u=s?q(f.options):f.options;return d.options=y.connectionOptionsSchema.parse({...u||{},...i.options}),d});return{...r,connections:o}}}}}function R(t,e){return X(t,e)}function Y(t){return async(e,n)=>{const a=e.var.user;return(a==null?void 0:a.tenant_id)===t&&a.org_name&&e.set("tenant_id",a.org_name),n()}}function Z(t){return async(e,n)=>{if(!t.accessControl)return n();const{controlPlaneTenantId:a}=t.accessControl,s=e.var.org_name,c=e.var.organization_id,l=s||c;let r=e.var.tenant_id;const p=e.var.user,i=(p!=null&&p.aud?Array.isArray(p.aud)?p.aud:[p.aud]:[]).includes(y.MANAGEMENT_API_AUDIENCE);if(!r&&l&&i&&(e.set("tenant_id",l),r=l),!r)throw new I(400,{message:"Tenant ID not found in request"});if(!K(c,r,a,s))throw new I(403,{message:`Access denied to tenant ${r}`});return n()}}function x(t){return async(e,n)=>{if(!t.subdomainRouting)return n();const{baseDomain:a,reservedSubdomains:s=[],resolveSubdomain:c}=t.subdomainRouting,l=e.req.header("host")||"";let r=null;if(l.endsWith(a)){const o=l.slice(0,-(a.length+1));o&&!o.includes(".")&&(r=o)}if(r&&s.includes(r)&&(r=null),!r)return t.accessControl&&e.set("tenant_id",t.accessControl.controlPlaneTenantId),n();let p=null;if(c)p=await c(r);else if(t.subdomainRouting.useOrganizations!==!1&&t.accessControl)try{const o=await e.env.data.organizations.get(t.accessControl.controlPlaneTenantId,r);o&&(p=o.id)}catch{}if(!p)throw new I(404,{message:`Tenant not found for subdomain: ${r}`});return e.set("tenant_id",p),n()}}function ee(t){return async(e,n)=>{if(!t.databaseIsolation)return n();const a=e.var.tenant_id;if(!a)throw new I(400,{message:"Tenant ID not found in request"});try{const s=await t.databaseIsolation.getAdapters(a);e.env.data=s}catch(s){throw console.error(`Failed to resolve database for tenant ${a}:`,s),new I(500,{message:"Failed to resolve tenant database"})}return n()}}function k(t){const e=x(t),n=Z(t),a=ee(t);return async(s,c)=>(await e(s,async()=>{}),await n(s,async()=>{}),await a(s,async()=>{}),c())}function pe(t){const{dataAdapter:e,controlPlane:n,controlPlane:{tenantId:a="control_plane",clientId:s}={},sync:c={resourceServers:!0,roles:!0},defaultPermissions:l=["tenant:admin"],requireOrganizationMatch:r=!1,managementApiExtensions:p=[],entityHooks:o,getChildTenantIds:i,getAdapters:f,...d}=t;let u=e,m=e;n&&(u=R(e,{controlPlaneTenantId:a,controlPlaneClientId:s}),m=R(e,{controlPlaneTenantId:a,controlPlaneClientId:s,excludeSensitiveFields:!0}));const g=c!==!1,v=g?{resourceServers:c.resourceServers??!0,roles:c.roles??!0}:{resourceServers:!1,roles:!1},_={controlPlaneTenantId:a,getChildTenantIds:i??(async()=>(await y.fetchAll(M=>u.tenants.list(M),"tenants",{cursorField:"id",pageSize:100})).filter(M=>M.id!==a).map(M=>M.id)),getAdapters:f??(async()=>u),getControlPlaneAdapters:async()=>u,sync:v},{entityHooks:A,tenantHooks:b}=Q(_),T={resourceServers:[A.resourceServers,...(o==null?void 0:o.resourceServers)??[]],roles:[A.roles,...(o==null?void 0:o.roles)??[]],connections:(o==null?void 0:o.connections)??[],tenants:(o==null?void 0:o.tenants)??[],rolePermissions:(o==null?void 0:o.rolePermissions)??[]},C=$({accessControl:{controlPlaneTenantId:a,requireOrganizationMatch:r,defaultPermissions:l}},{tenants:b}),{app:P}=y.init({dataAdapter:u,managementDataAdapter:m,...d,entityHooks:T,managementApiExtensions:[...p,{path:"/tenants",router:C}]});return P.use("/api/v2/*",Y(a)),g&&P.use("/api/v2/*",J()),{app:P,controlPlaneTenantId:a}}function ge(t){const e=F(t);return{name:"multi-tenancy",middleware:k(t),hooks:e,routes:[{path:"/management",handler:$(t,e)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),t.accessControl&&console.log(` - Access control enabled (control plane: ${t.accessControl.controlPlaneTenantId})`),t.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${t.subdomainRouting.baseDomain})`),t.databaseIsolation&&console.log(" - Database isolation enabled")}}}function F(t){const e=t.accessControl?B(t.accessControl):{},n=t.databaseIsolation?V(t.databaseIsolation):{},a=W(t);return{...e,...n,tenants:a}}function te(t){const e=new se.Hono,n=F(t);return e.route("/tenants",$(t,n)),e}function we(t){return{hooks:F(t),middleware:k(t),app:te(t),config:t,wrapAdapters:(e,n)=>{var a;return R(e,{controlPlaneTenantId:(a=t.accessControl)==null?void 0:a.controlPlaneTenantId,controlPlaneClientId:n==null?void 0:n.controlPlaneClientId})}}}exports.createAccessControlHooks=B;exports.createAccessControlMiddleware=Z;exports.createControlPlaneTenantMiddleware=Y;exports.createDatabaseHooks=V;exports.createDatabaseMiddleware=ee;exports.createMultiTenancy=te;exports.createMultiTenancyHooks=F;exports.createMultiTenancyMiddleware=k;exports.createMultiTenancyPlugin=ge;exports.createProtectSyncedMiddleware=J;exports.createProvisioningHooks=W;exports.createRuntimeFallbackAdapter=X;exports.createSubdomainMiddleware=x;exports.createSyncHooks=Q;exports.createTenantsOpenAPIRouter=$;exports.initMultiTenant=pe;exports.setupMultiTenancy=we;exports.validateTenantAccess=K;exports.withRuntimeFallback=R;
1
+ "use strict";var re=Object.defineProperty;var ae=(t,e,n)=>e in t?re(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var D=(t,e,n)=>ae(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const se=require("hono"),y=require("authhero"),I=require("@hono/zod-openapi");function B(t){const{controlPlaneTenantId:e,requireOrganizationMatch:n=!0}=t;return{async onTenantAccessValidation(r,a){if(a===e)return!0;if(n){const c=r.var.org_name,d=r.var.organization_id,s=c||d;return s?s.toLowerCase()===a.toLowerCase():!1}return!0}}}function K(t,e,n,r){if(e===n)return!0;const a=r||t;return a?a.toLowerCase()===e.toLowerCase():!1}function V(t){return{async resolveDataAdapters(e){try{return await t.getAdapters(e)}catch(n){console.error(`Failed to resolve data adapters for tenant ${e}:`,n);return}}}}function oe(t){return`urn:authhero:tenant:${t.toLowerCase()}`}function W(t){return{async beforeCreate(e,n){return!n.audience&&n.id?{...n,audience:oe(n.id)}:n},async afterCreate(e,n){const{accessControl:r,databaseIsolation:a}=t;r&&e.ctx&&await ie(e,n,r),a!=null&&a.onProvision&&await a.onProvision(n.id)},async beforeDelete(e,n){const{accessControl:r,databaseIsolation:a}=t;if(r)try{const d=(await e.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(s=>s.name===n);d&&await e.adapters.organizations.remove(r.controlPlaneTenantId,d.id)}catch(c){console.warn(`Failed to remove organization for tenant ${n}:`,c)}if(a!=null&&a.onDeprovision)try{await a.onDeprovision(n)}catch(c){console.warn(`Failed to deprovision database for tenant ${n}:`,c)}}}}async function ie(t,e,n){const{controlPlaneTenantId:r,defaultPermissions:a,defaultRoles:c,issuer:d,adminRoleName:s="Tenant Admin",adminRoleDescription:f="Full access to all tenant management operations",addCreatorToOrganization:o=!0}=n,i=await t.adapters.organizations.create(r,{name:e.id,display_name:e.friendly_name||e.id});let u;if(d&&(u=await le(t,r,s,f)),o&&t.ctx){const l=t.ctx.var.user;if(l!=null&&l.sub&&!await ce(t,r,l.sub))try{await t.adapters.userOrganizations.create(r,{user_id:l.sub,organization_id:i.id}),u&&await t.adapters.userRoles.create(r,l.sub,u,i.id)}catch(p){console.warn(`Failed to add creator ${l.sub} to organization ${i.id}:`,p)}}c&&c.length>0&&console.log(`Would assign roles ${c.join(", ")} to organization ${i.id}`),a&&a.length>0&&console.log(`Would grant permissions ${a.join(", ")} to organization ${i.id}`)}async function ce(t,e,n){const r=await t.adapters.userRoles.list(e,n,void 0,"");for(const a of r)if((await t.adapters.rolePermissions.list(e,a.id,{per_page:1e3})).some(s=>s.permission_name==="admin:organizations"))return!0;return!1}async function le(t,e,n,r){const c=(await t.adapters.roles.list(e,{})).roles.find(o=>o.name===n);if(c)return c.id;const d=await t.adapters.roles.create(e,{name:n,description:r}),s=y.MANAGEMENT_API_AUDIENCE,f=y.MANAGEMENT_API_SCOPES.map(o=>({role_id:d.id,resource_server_identifier:s,permission_name:o.value}));return await t.adapters.rolePermissions.assign(e,d.id,f),d.id}function k(t,e,n=()=>!0){const{controlPlaneTenantId:r,getChildTenantIds:a,getAdapters:c}=t,d=new Map;async function s(i,u,l){return(await e(i).list(u,{q:`name:${l}`,per_page:1}))[0]??null}async function f(i){const u=await a(),l=e(await c(r));await Promise.all(u.map(async m=>{try{const p=await c(m),g=e(p),w={...l.transform(i),is_system:!0},h=await s(p,m,i.name),A=h?g.getId(h):void 0;if(h&&A){const P=g.preserveOnUpdate?g.preserveOnUpdate(h,w):w;await g.update(m,A,P)}else await g.create(m,w)}catch(p){console.error(`Failed to sync ${l.listKey} "${i.name}" to tenant "${m}":`,p)}}))}async function o(i){const u=await a();await Promise.all(u.map(async l=>{try{const m=await c(l),p=e(m),g=await s(m,l,i),v=g?p.getId(g):void 0;g&&v&&await p.remove(l,v)}catch(m){console.error(`Failed to delete entity "${i}" from tenant "${l}":`,m)}}))}return{afterCreate:async(i,u)=>{i.tenantId===r&&n(u)&&await f(u)},afterUpdate:async(i,u,l)=>{i.tenantId===r&&n(l)&&await f(l)},beforeDelete:async(i,u)=>{if(i.tenantId!==r)return;const m=await e(i.adapters).get(i.tenantId,u);m&&n(m)&&d.set(u,m)},afterDelete:async(i,u)=>{if(i.tenantId!==r)return;const l=d.get(u);l&&(d.delete(u),await o(l.name))}}}function N(t,e,n=()=>!0){const{controlPlaneTenantId:r,getControlPlaneAdapters:a,getAdapters:c}=t;return{async afterCreate(d,s){if(s.id!==r)try{const f=await a(),o=await c(s.id),i=e(f),u=e(o),l=await y.fetchAll(m=>i.listPaginated(r,m),i.listKey,{cursorField:"id",pageSize:100});await Promise.all(l.filter(m=>n(m)).map(async m=>{try{const p=i.transform(m);await u.create(s.id,{...p,is_system:!0})}catch(p){console.error(`Failed to sync entity to new tenant "${s.id}":`,p)}}))}catch(f){console.error(`Failed to sync entities to new tenant "${s.id}":`,f)}}}}const H=t=>({list:async(e,n)=>(await t.resourceServers.list(e,n)).resource_servers,listPaginated:(e,n)=>t.resourceServers.list(e,n),get:(e,n)=>t.resourceServers.get(e,n),create:(e,n)=>t.resourceServers.create(e,n),update:(e,n,r)=>t.resourceServers.update(e,n,r),remove:(e,n)=>t.resourceServers.remove(e,n),listKey:"resource_servers",getId:e=>e.id,transform:e=>({id:e.id,name:e.name,identifier:e.identifier,scopes:e.scopes,signing_alg:e.signing_alg,token_lifetime:e.token_lifetime,token_lifetime_for_web:e.token_lifetime_for_web})}),G=t=>({list:async(e,n)=>(await t.roles.list(e,n)).roles,listPaginated:(e,n)=>t.roles.list(e,n),get:(e,n)=>t.roles.get(e,n),create:(e,n)=>t.roles.create(e,n),update:(e,n,r)=>t.roles.update(e,n,r),remove:(e,n)=>t.roles.remove(e,n),listKey:"roles",getId:e=>e.id,transform:e=>({id:e.id,name:e.name,description:e.description})});function L(t){var e;return((e=t.metadata)==null?void 0:e.sync)!==!1}function Q(t){const{sync:e={},filters:n={}}=t,r=e.resourceServers??!0,a=e.roles??!0,c=p=>L(p)?n.resourceServers?n.resourceServers(p):!0:!1,d=p=>L(p)?n.roles?n.roles(p):!0:!1,s=r?k(t,H,c):void 0,f=a?k(t,G,d):void 0,o=r?N(t,H,c):void 0,i=a?N(t,G,d):void 0,u=a?{async afterCreate(p,g){var v;if(g.id!==t.controlPlaneTenantId){await((v=i==null?void 0:i.afterCreate)==null?void 0:v.call(i,p,g));try{const w=await t.getControlPlaneAdapters(),h=await t.getAdapters(g.id),A=await y.fetchAll(_=>w.roles.list(t.controlPlaneTenantId,_),"roles",{cursorField:"id",pageSize:100}),P=new Map;for(const _ of A.filter(T=>{var b;return((b=n.roles)==null?void 0:b.call(n,T))??!0})){const T=await l(h,g.id,_.name);T&&P.set(_.name,T.id)}for(const _ of A.filter(T=>{var b;return((b=n.roles)==null?void 0:b.call(n,T))??!0})){const T=P.get(_.name);if(T)try{const b=await w.rolePermissions.list(t.controlPlaneTenantId,_.id,{});b.length>0&&await h.rolePermissions.assign(g.id,T,b.map(C=>({role_id:T,resource_server_identifier:C.resource_server_identifier,permission_name:C.permission_name})))}catch(b){console.error(`Failed to sync permissions for role "${_.name}" to tenant "${g.id}":`,b)}}}catch(w){console.error(`Failed to sync role permissions to tenant "${g.id}":`,w)}}}}:void 0;async function l(p,g,v){return(await p.roles.list(g,{q:`name:${v}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:s,roles:f},tenantHooks:{async afterCreate(p,g){const v=[o==null?void 0:o.afterCreate,(u==null?void 0:u.afterCreate)??(i==null?void 0:i.afterCreate)],w=[];for(const h of v)if(h)try{await h(p,g)}catch(A){w.push(A instanceof Error?A:new Error(String(A)))}if(w.length===1)throw w[0];if(w.length>1)throw new AggregateError(w,w.map(h=>h.message).join("; "))}}}}var S=class extends Error{constructor(e=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});D(this,"res");D(this,"status");this.res=n==null?void 0:n.res,this.status=e}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function $(t,e){const n=new I.OpenAPIHono;return n.openapi(I.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:y.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:I.z.object({tenants:I.z.array(y.tenantSchema),start:I.z.number().optional(),limit:I.z.number().optional(),length:I.z.number().optional()})}},description:"List of tenants"}}}),async r=>{var p,g,v,w,h,A;const a=r.req.valid("query"),{page:c,per_page:d,include_totals:s,q:f}=a,o=r.var.user,i=(o==null?void 0:o.permissions)||[];if(i.includes("auth:read")||i.includes("admin:organizations")){const P=await r.env.data.tenants.list({page:c,per_page:d,include_totals:s,q:f});return s?r.json({tenants:P.tenants,start:((p=P.totals)==null?void 0:p.start)??0,limit:((g=P.totals)==null?void 0:g.limit)??d,length:P.tenants.length}):r.json({tenants:P.tenants})}const l=((v=t.accessControl)==null?void 0:v.controlPlaneTenantId)??((w=r.env.data.multiTenancyConfig)==null?void 0:w.controlPlaneTenantId);if(l&&(o!=null&&o.sub)){const _=(await y.fetchAll(O=>r.env.data.userOrganizations.listUserOrganizations(l,o.sub,O),"organizations")).map(O=>O.name);if(_.length===0)return s?r.json({tenants:[],start:0,limit:d??50,length:0}):r.json({tenants:[]});const T=_.length,b=c??0,C=d??50,z=b*C,M=_.slice(z,z+C);if(M.length===0)return s?r.json({tenants:[],start:z,limit:C,length:T}):r.json({tenants:[]});const E=M.map(O=>`id:${O}`).join(" OR "),ne=f?`(${E}) AND (${f})`:E,j=await r.env.data.tenants.list({q:ne,per_page:C,include_totals:!1});return s?r.json({tenants:j.tenants,start:z,limit:C,length:T}):r.json({tenants:j.tenants})}const m=await r.env.data.tenants.list({page:c,per_page:d,include_totals:s,q:f});return s?r.json({tenants:m.tenants,start:((h=m.totals)==null?void 0:h.start)??0,limit:((A=m.totals)==null?void 0:A.limit)??d,length:m.tenants.length}):r.json({tenants:m.tenants})}),n.openapi(I.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:y.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:y.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async r=>{var f,o;const a=r.var.user;if(!(a!=null&&a.sub))throw new S(401,{message:"Authentication required to create tenants"});let c=r.req.valid("json");const d={adapters:r.env.data,ctx:r};(f=e.tenants)!=null&&f.beforeCreate&&(c=await e.tenants.beforeCreate(d,c));const s=await r.env.data.tenants.create(c);return(o=e.tenants)!=null&&o.afterCreate&&await e.tenants.afterCreate(d,s),r.json(s,201)}),n.openapi(I.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:I.z.object({id:I.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 r=>{var f,o,i,u;const{id:a}=r.req.valid("param"),c=((f=t.accessControl)==null?void 0:f.controlPlaneTenantId)??((o=r.env.data.multiTenancyConfig)==null?void 0:o.controlPlaneTenantId);if(c){const l=r.var.user;if(!(l!=null&&l.sub))throw new S(401,{message:"Authentication required"});if(a===c)throw new S(403,{message:"Cannot delete the control plane"});if(!(await y.fetchAll(g=>r.env.data.userOrganizations.listUserOrganizations(c,l.sub,g),"organizations")).some(g=>g.name===a))throw new S(403,{message:"Access denied to this tenant"})}if(!await r.env.data.tenants.get(a))throw new S(404,{message:"Tenant not found"});const s={adapters:r.env.data,ctx:r};return(i=e.tenants)!=null&&i.beforeDelete&&await e.tenants.beforeDelete(s,a),await r.env.data.tenants.remove(a),(u=e.tenants)!=null&&u.afterDelete&&await e.tenants.afterDelete(s,a),r.body(null,204)}),n}function de(t){const e=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:n,type:r}of e){const a=t.match(n);if(a&&a[1])return{type:r,id:a[1]}}return null}async function ue(t,e,n){try{switch(n.type){case"resource_server":{const r=await t.resourceServers.get(e,n.id);return(r==null?void 0:r.is_system)===!0}case"role":{const r=await t.roles.get(e,n.id);return(r==null?void 0:r.is_system)===!0}case"connection":{const r=await t.connections.get(e,n.id);return(r==null?void 0:r.is_system)===!0}default:return!1}}catch{return!1}}function fe(t){return{resource_server:"resource server",role:"role",connection:"connection"}[t]}function J(){return async(t,e)=>{if(!["PATCH","PUT","DELETE"].includes(t.req.method))return e();const n=de(t.req.path);if(!n)return e();const r=t.var.tenant_id||t.req.header("x-tenant-id")||t.req.header("tenant-id");if(!r)return e();if(await ue(t.env.data,r,n))throw new S(403,{message:`This ${fe(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return e()}}const me=["client_secret","app_secret","twilio_token"];function U(t){if(!t)return t;const e={...t};for(const n of me)delete e[n];return e}function X(t,e){const{controlPlaneTenantId:n,controlPlaneClientId:r,excludeSensitiveFields:a=!1}=e;return{...t,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r},connections:{...t.connections,get:async(c,d)=>{var l;const s=await t.connections.get(c,d);if(!s||!n||c===n)return s;const o=(l=(await t.connections.list(n)).connections)==null?void 0:l.find(m=>m.strategy===s.strategy);if(!(o!=null&&o.options))return s;const i=y.connectionSchema.parse({...o,...s}),u=a?U(o.options):o.options;return i.options=y.connectionOptionsSchema.parse({...u||{},...s.options}),i},list:async(c,d)=>{const s=await t.connections.list(c,d);if(!n||c===n)return s;const f=await t.connections.list(n),o=s.connections.map(i=>{var p;const u=(p=f.connections)==null?void 0:p.find(g=>g.strategy===i.strategy);if(!(u!=null&&u.options))return i;const l=y.connectionSchema.parse({...u,...i}),m=a?U(u.options):u.options;return l.options=y.connectionOptionsSchema.parse({...m||{},...i.options}),l});return{...s,connections:o}}}}}function R(t,e){return X(t,e)}function Y(t){return async(e,n)=>{const r=e.var.user;return(r==null?void 0:r.tenant_id)===t&&r.org_name&&e.set("tenant_id",r.org_name),n()}}function Z(t){return async(e,n)=>{if(!t.accessControl)return n();const{controlPlaneTenantId:r}=t.accessControl,a=e.var.org_name,c=e.var.organization_id,d=a||c;let s=e.var.tenant_id;const f=e.var.user,i=(f!=null&&f.aud?Array.isArray(f.aud)?f.aud:[f.aud]:[]).includes(y.MANAGEMENT_API_AUDIENCE);if(!s&&d&&i&&(e.set("tenant_id",d),s=d),!s)throw new S(400,{message:"Tenant ID not found in request"});if(!K(c,s,r,a))throw new S(403,{message:`Access denied to tenant ${s}`});return n()}}function x(t){return async(e,n)=>{if(!t.subdomainRouting)return n();const{baseDomain:r,reservedSubdomains:a=[],resolveSubdomain:c}=t.subdomainRouting,d=e.req.header("host")||"";let s=null;if(d.endsWith(r)){const o=d.slice(0,-(r.length+1));o&&!o.includes(".")&&(s=o)}if(s&&a.includes(s)&&(s=null),!s)return t.accessControl&&e.set("tenant_id",t.accessControl.controlPlaneTenantId),n();let f=null;if(c)f=await c(s);else if(t.subdomainRouting.useOrganizations!==!1&&t.accessControl)try{const o=await e.env.data.organizations.get(t.accessControl.controlPlaneTenantId,s);o&&(f=o.id)}catch{}if(!f)throw new S(404,{message:`Tenant not found for subdomain: ${s}`});return e.set("tenant_id",f),n()}}function ee(t){return async(e,n)=>{if(!t.databaseIsolation)return n();const r=e.var.tenant_id;if(!r)throw new S(400,{message:"Tenant ID not found in request"});try{const a=await t.databaseIsolation.getAdapters(r);e.env.data=a}catch(a){throw console.error(`Failed to resolve database for tenant ${r}:`,a),new S(500,{message:"Failed to resolve tenant database"})}return n()}}function q(t){const e=x(t),n=Z(t),r=ee(t);return async(a,c)=>(await e(a,async()=>{}),await n(a,async()=>{}),await r(a,async()=>{}),c())}function pe(t){const{dataAdapter:e,controlPlane:n,controlPlane:{tenantId:r="control_plane",clientId:a}={},sync:c={resourceServers:!0,roles:!0},defaultPermissions:d=["tenant:admin"],requireOrganizationMatch:s=!1,managementApiExtensions:f=[],entityHooks:o,getChildTenantIds:i,getAdapters:u,...l}=t;let m=e,p=e;n&&(m=R(e,{controlPlaneTenantId:r,controlPlaneClientId:a}),p=R(e,{controlPlaneTenantId:r,controlPlaneClientId:a,excludeSensitiveFields:!0}));const g=c!==!1,v=g?{resourceServers:c.resourceServers??!0,roles:c.roles??!0}:{resourceServers:!1,roles:!1},A={controlPlaneTenantId:r,getChildTenantIds:i??(async()=>(await y.fetchAll(M=>m.tenants.list(M),"tenants",{cursorField:"id",pageSize:100})).filter(M=>M.id!==r).map(M=>M.id)),getAdapters:u??(async()=>m),getControlPlaneAdapters:async()=>m,sync:v},{entityHooks:P,tenantHooks:_}=Q(A),T={resourceServers:[P.resourceServers,...(o==null?void 0:o.resourceServers)??[]],roles:[P.roles,...(o==null?void 0:o.roles)??[]],connections:(o==null?void 0:o.connections)??[],tenants:(o==null?void 0:o.tenants)??[],rolePermissions:(o==null?void 0:o.rolePermissions)??[]},b=$({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:s,defaultPermissions:d}},{tenants:_}),{app:C}=y.init({dataAdapter:m,managementDataAdapter:p,...l,entityHooks:T,managementApiExtensions:[...f,{path:"/tenants",router:b}]});return C.use("/api/v2/*",Y(r)),g&&C.use("/api/v2/*",J()),{app:C,controlPlaneTenantId:r}}function ge(t){const e=F(t);return{name:"multi-tenancy",middleware:q(t),hooks:e,routes:[{path:"/management",handler:$(t,e)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),t.accessControl&&console.log(` - Access control enabled (control plane: ${t.accessControl.controlPlaneTenantId})`),t.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${t.subdomainRouting.baseDomain})`),t.databaseIsolation&&console.log(" - Database isolation enabled")}}}function F(t){const e=t.accessControl?B(t.accessControl):{},n=t.databaseIsolation?V(t.databaseIsolation):{},r=W(t);return{...e,...n,tenants:r}}function te(t){const e=new se.Hono,n=F(t);return e.route("/tenants",$(t,n)),e}function we(t){return{hooks:F(t),middleware:q(t),app:te(t),config:t,wrapAdapters:(e,n)=>{var r;return R(e,{controlPlaneTenantId:(r=t.accessControl)==null?void 0:r.controlPlaneTenantId,controlPlaneClientId:n==null?void 0:n.controlPlaneClientId})}}}exports.createAccessControlHooks=B;exports.createAccessControlMiddleware=Z;exports.createControlPlaneTenantMiddleware=Y;exports.createDatabaseHooks=V;exports.createDatabaseMiddleware=ee;exports.createMultiTenancy=te;exports.createMultiTenancyHooks=F;exports.createMultiTenancyMiddleware=q;exports.createMultiTenancyPlugin=ge;exports.createProtectSyncedMiddleware=J;exports.createProvisioningHooks=W;exports.createRuntimeFallbackAdapter=X;exports.createSubdomainMiddleware=x;exports.createSyncHooks=Q;exports.createTenantsOpenAPIRouter=$;exports.initMultiTenant=pe;exports.setupMultiTenancy=we;exports.validateTenantAccess=K;exports.withRuntimeFallback=R;
@@ -1,24 +1,24 @@
1
1
  var X = Object.defineProperty;
2
2
  var Y = (t, e, n) => e in t ? X(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
3
- var F = (t, e, n) => Y(t, typeof e != "symbol" ? e + "" : e, n);
3
+ var O = (t, e, n) => Y(t, typeof e != "symbol" ? e + "" : e, n);
4
4
  import { Hono as Z } from "hono";
5
- import { MANAGEMENT_API_SCOPES as x, MANAGEMENT_API_AUDIENCE as W, fetchAll as O, auth0QuerySchema as ee, tenantSchema as G, tenantInsertSchema as te, connectionSchema as R, connectionOptionsSchema as D, init as ne } from "authhero";
6
- import { OpenAPIHono as re, createRoute as M, z as S } from "@hono/zod-openapi";
7
- function se(t) {
5
+ import { MANAGEMENT_API_SCOPES as x, MANAGEMENT_API_AUDIENCE as W, fetchAll as F, auth0QuerySchema as ee, tenantSchema as N, tenantInsertSchema as te, connectionSchema as k, connectionOptionsSchema as H, init as ne } from "authhero";
6
+ import { OpenAPIHono as re, createRoute as R, z as S } from "@hono/zod-openapi";
7
+ function ae(t) {
8
8
  const { controlPlaneTenantId: e, requireOrganizationMatch: n = !0 } = t;
9
9
  return {
10
10
  async onTenantAccessValidation(r, a) {
11
11
  if (a === e)
12
12
  return !0;
13
13
  if (n) {
14
- const c = r.var.org_name, l = r.var.organization_id, s = c || l;
14
+ const c = r.var.org_name, d = r.var.organization_id, s = c || d;
15
15
  return s ? s.toLowerCase() === a.toLowerCase() : !1;
16
16
  }
17
17
  return !0;
18
18
  }
19
19
  };
20
20
  }
21
- function ae(t, e, n, r) {
21
+ function se(t, e, n, r) {
22
22
  if (e === n)
23
23
  return !0;
24
24
  const a = r || t;
@@ -58,12 +58,12 @@ function ce(t) {
58
58
  const { accessControl: r, databaseIsolation: a } = t;
59
59
  if (r)
60
60
  try {
61
- const l = (await e.adapters.organizations.list(
61
+ const d = (await e.adapters.organizations.list(
62
62
  r.controlPlaneTenantId
63
63
  )).organizations.find((s) => s.name === n);
64
- l && await e.adapters.organizations.remove(
64
+ d && await e.adapters.organizations.remove(
65
65
  r.controlPlaneTenantId,
66
- l.id
66
+ d.id
67
67
  );
68
68
  } catch (c) {
69
69
  console.warn(
@@ -88,9 +88,9 @@ async function le(t, e, n) {
88
88
  controlPlaneTenantId: r,
89
89
  defaultPermissions: a,
90
90
  defaultRoles: c,
91
- issuer: l,
91
+ issuer: d,
92
92
  adminRoleName: s = "Tenant Admin",
93
- adminRoleDescription: p = "Full access to all tenant management operations",
93
+ adminRoleDescription: f = "Full access to all tenant management operations",
94
94
  addCreatorToOrganization: o = !0
95
95
  } = n, i = await t.adapters.organizations.create(
96
96
  r,
@@ -99,34 +99,34 @@ async function le(t, e, n) {
99
99
  display_name: e.friendly_name || e.id
100
100
  }
101
101
  );
102
- let f;
103
- if (l && (f = await ue(
102
+ let u;
103
+ if (d && (u = await ue(
104
104
  t,
105
105
  r,
106
106
  s,
107
- p
107
+ f
108
108
  )), o && t.ctx) {
109
- const d = t.ctx.var.user;
110
- if (d != null && d.sub && !await de(
109
+ const l = t.ctx.var.user;
110
+ if (l != null && l.sub && !await de(
111
111
  t,
112
112
  r,
113
- d.sub
113
+ l.sub
114
114
  ))
115
115
  try {
116
116
  await t.adapters.userOrganizations.create(r, {
117
- user_id: d.sub,
117
+ user_id: l.sub,
118
118
  organization_id: i.id
119
- }), f && await t.adapters.userRoles.create(
119
+ }), u && await t.adapters.userRoles.create(
120
120
  r,
121
- d.sub,
122
- f,
121
+ l.sub,
122
+ u,
123
123
  i.id
124
124
  // organizationId
125
125
  );
126
- } catch (m) {
126
+ } catch (p) {
127
127
  console.warn(
128
- `Failed to add creator ${d.sub} to organization ${i.id}:`,
129
- m
128
+ `Failed to add creator ${l.sub} to organization ${i.id}:`,
129
+ p
130
130
  );
131
131
  }
132
132
  }
@@ -159,123 +159,123 @@ async function ue(t, e, n, r) {
159
159
  const c = (await t.adapters.roles.list(e, {})).roles.find((o) => o.name === n);
160
160
  if (c)
161
161
  return c.id;
162
- const l = await t.adapters.roles.create(e, {
162
+ const d = await t.adapters.roles.create(e, {
163
163
  name: n,
164
164
  description: r
165
- }), s = W, p = x.map((o) => ({
166
- role_id: l.id,
165
+ }), s = W, f = x.map((o) => ({
166
+ role_id: d.id,
167
167
  resource_server_identifier: s,
168
168
  permission_name: o.value
169
169
  }));
170
170
  return await t.adapters.rolePermissions.assign(
171
171
  e,
172
- l.id,
173
- p
174
- ), l.id;
172
+ d.id,
173
+ f
174
+ ), d.id;
175
175
  }
176
- function L(t, e, n = () => !0) {
177
- const { controlPlaneTenantId: r, getChildTenantIds: a, getAdapters: c } = t, l = /* @__PURE__ */ new Map();
178
- async function s(i, f, d) {
179
- return (await e(i).list(f, {
180
- q: `name:${d}`,
176
+ function G(t, e, n = () => !0) {
177
+ const { controlPlaneTenantId: r, getChildTenantIds: a, getAdapters: c } = t, d = /* @__PURE__ */ new Map();
178
+ async function s(i, u, l) {
179
+ return (await e(i).list(u, {
180
+ q: `name:${l}`,
181
181
  per_page: 1
182
182
  }))[0] ?? null;
183
183
  }
184
- async function p(i) {
185
- const f = await a(), d = e(await c(r));
184
+ async function f(i) {
185
+ const u = await a(), l = e(await c(r));
186
186
  await Promise.all(
187
- f.map(async (u) => {
187
+ u.map(async (m) => {
188
188
  try {
189
- const m = await c(u), g = e(m), w = {
190
- ...d.transform(i),
189
+ const p = await c(m), g = e(p), w = {
190
+ ...l.transform(i),
191
191
  is_system: !0
192
- }, y = await s(m, u, i.name), _ = y ? g.getId(y) : void 0;
193
- if (y && _) {
194
- const T = g.preserveOnUpdate ? g.preserveOnUpdate(y, w) : w;
195
- await g.update(u, _, T);
192
+ }, y = await s(p, m, i.name), T = y ? g.getId(y) : void 0;
193
+ if (y && T) {
194
+ const A = g.preserveOnUpdate ? g.preserveOnUpdate(y, w) : w;
195
+ await g.update(m, T, A);
196
196
  } else
197
- await g.create(u, w);
198
- } catch (m) {
197
+ await g.create(m, w);
198
+ } catch (p) {
199
199
  console.error(
200
- `Failed to sync ${d.listKey} "${i.name}" to tenant "${u}":`,
201
- m
200
+ `Failed to sync ${l.listKey} "${i.name}" to tenant "${m}":`,
201
+ p
202
202
  );
203
203
  }
204
204
  })
205
205
  );
206
206
  }
207
207
  async function o(i) {
208
- const f = await a();
208
+ const u = await a();
209
209
  await Promise.all(
210
- f.map(async (d) => {
210
+ u.map(async (l) => {
211
211
  try {
212
- const u = await c(d), m = e(u), g = await s(u, d, i), h = g ? m.getId(g) : void 0;
213
- g && h && await m.remove(d, h);
214
- } catch (u) {
212
+ const m = await c(l), p = e(m), g = await s(m, l, i), h = g ? p.getId(g) : void 0;
213
+ g && h && await p.remove(l, h);
214
+ } catch (m) {
215
215
  console.error(
216
- `Failed to delete entity "${i}" from tenant "${d}":`,
217
- u
216
+ `Failed to delete entity "${i}" from tenant "${l}":`,
217
+ m
218
218
  );
219
219
  }
220
220
  })
221
221
  );
222
222
  }
223
223
  return {
224
- afterCreate: async (i, f) => {
225
- i.tenantId === r && n(f) && await p(f);
224
+ afterCreate: async (i, u) => {
225
+ i.tenantId === r && n(u) && await f(u);
226
226
  },
227
- afterUpdate: async (i, f, d) => {
228
- i.tenantId === r && n(d) && await p(d);
227
+ afterUpdate: async (i, u, l) => {
228
+ i.tenantId === r && n(l) && await f(l);
229
229
  },
230
- beforeDelete: async (i, f) => {
230
+ beforeDelete: async (i, u) => {
231
231
  if (i.tenantId !== r) return;
232
- const u = await e(i.adapters).get(i.tenantId, f);
233
- u && n(u) && l.set(f, u);
232
+ const m = await e(i.adapters).get(i.tenantId, u);
233
+ m && n(m) && d.set(u, m);
234
234
  },
235
- afterDelete: async (i, f) => {
235
+ afterDelete: async (i, u) => {
236
236
  if (i.tenantId !== r) return;
237
- const d = l.get(f);
238
- d && (l.delete(f), await o(d.name));
237
+ const l = d.get(u);
238
+ l && (d.delete(u), await o(l.name));
239
239
  }
240
240
  };
241
241
  }
242
- function U(t, e, n = () => !0) {
242
+ function L(t, e, n = () => !0) {
243
243
  const { controlPlaneTenantId: r, getControlPlaneAdapters: a, getAdapters: c } = t;
244
244
  return {
245
- async afterCreate(l, s) {
245
+ async afterCreate(d, s) {
246
246
  if (s.id !== r)
247
247
  try {
248
- const p = await a(), o = await c(s.id), i = e(p), f = e(o), d = await O(
249
- (u) => i.listPaginated(r, u),
248
+ const f = await a(), o = await c(s.id), i = e(f), u = e(o), l = await F(
249
+ (m) => i.listPaginated(r, m),
250
250
  i.listKey,
251
251
  { cursorField: "id", pageSize: 100 }
252
252
  );
253
253
  await Promise.all(
254
- d.filter((u) => n(u)).map(async (u) => {
254
+ l.filter((m) => n(m)).map(async (m) => {
255
255
  try {
256
- const m = i.transform(u);
257
- await f.create(s.id, {
258
- ...m,
256
+ const p = i.transform(m);
257
+ await u.create(s.id, {
258
+ ...p,
259
259
  is_system: !0
260
260
  });
261
- } catch (m) {
261
+ } catch (p) {
262
262
  console.error(
263
263
  `Failed to sync entity to new tenant "${s.id}":`,
264
- m
264
+ p
265
265
  );
266
266
  }
267
267
  })
268
268
  );
269
- } catch (p) {
269
+ } catch (f) {
270
270
  console.error(
271
271
  `Failed to sync entities to new tenant "${s.id}":`,
272
- p
272
+ f
273
273
  );
274
274
  }
275
275
  }
276
276
  };
277
277
  }
278
- const B = (t) => ({
278
+ const U = (t) => ({
279
279
  list: async (e, n) => (await t.resourceServers.list(e, n)).resource_servers,
280
280
  listPaginated: (e, n) => t.resourceServers.list(e, n),
281
281
  get: (e, n) => t.resourceServers.get(e, n),
@@ -293,7 +293,7 @@ const B = (t) => ({
293
293
  token_lifetime: e.token_lifetime,
294
294
  token_lifetime_for_web: e.token_lifetime_for_web
295
295
  })
296
- }), K = (t) => ({
296
+ }), B = (t) => ({
297
297
  list: async (e, n) => (await t.roles.list(e, n)).roles,
298
298
  listPaginated: (e, n) => t.roles.list(e, n),
299
299
  get: (e, n) => t.roles.get(e, n),
@@ -308,81 +308,81 @@ const B = (t) => ({
308
308
  description: e.description
309
309
  })
310
310
  });
311
- function V(t) {
311
+ function K(t) {
312
312
  var e;
313
313
  return ((e = t.metadata) == null ? void 0 : e.sync) !== !1;
314
314
  }
315
315
  function fe(t) {
316
- const { sync: e = {}, filters: n = {} } = t, r = e.resourceServers ?? !0, a = e.roles ?? !0, c = (m) => V(m) ? n.resourceServers ? n.resourceServers(m) : !0 : !1, l = (m) => V(m) ? n.roles ? n.roles(m) : !0 : !1, s = r ? L(
316
+ const { sync: e = {}, filters: n = {} } = t, r = e.resourceServers ?? !0, a = e.roles ?? !0, c = (p) => K(p) ? n.resourceServers ? n.resourceServers(p) : !0 : !1, d = (p) => K(p) ? n.roles ? n.roles(p) : !0 : !1, s = r ? G(
317
317
  t,
318
- B,
318
+ U,
319
319
  c
320
- ) : void 0, p = a ? L(
321
- t,
322
- K,
323
- l
324
- ) : void 0, o = r ? U(
320
+ ) : void 0, f = a ? G(
325
321
  t,
326
322
  B,
323
+ d
324
+ ) : void 0, o = r ? L(
325
+ t,
326
+ U,
327
327
  c
328
- ) : void 0, i = a ? U(
328
+ ) : void 0, i = a ? L(
329
329
  t,
330
- K,
331
- l
332
- ) : void 0, f = a ? {
333
- async afterCreate(m, g) {
330
+ B,
331
+ d
332
+ ) : void 0, u = a ? {
333
+ async afterCreate(p, g) {
334
334
  var h;
335
335
  if (g.id !== t.controlPlaneTenantId) {
336
- await ((h = i == null ? void 0 : i.afterCreate) == null ? void 0 : h.call(i, m, g));
336
+ await ((h = i == null ? void 0 : i.afterCreate) == null ? void 0 : h.call(i, p, g));
337
337
  try {
338
- const w = await t.getControlPlaneAdapters(), y = await t.getAdapters(g.id), _ = await O(
339
- (A) => w.roles.list(
338
+ const w = await t.getControlPlaneAdapters(), y = await t.getAdapters(g.id), T = await F(
339
+ (_) => w.roles.list(
340
340
  t.controlPlaneTenantId,
341
- A
341
+ _
342
342
  ),
343
343
  "roles",
344
344
  { cursorField: "id", pageSize: 100 }
345
- ), T = /* @__PURE__ */ new Map();
346
- for (const A of _.filter(
345
+ ), A = /* @__PURE__ */ new Map();
346
+ for (const _ of T.filter(
347
347
  (v) => {
348
- var b;
349
- return ((b = n.roles) == null ? void 0 : b.call(n, v)) ?? !0;
348
+ var P;
349
+ return ((P = n.roles) == null ? void 0 : P.call(n, v)) ?? !0;
350
350
  }
351
351
  )) {
352
- const v = await d(
352
+ const v = await l(
353
353
  y,
354
354
  g.id,
355
- A.name
355
+ _.name
356
356
  );
357
- v && T.set(A.name, v.id);
357
+ v && A.set(_.name, v.id);
358
358
  }
359
- for (const A of _.filter(
359
+ for (const _ of T.filter(
360
360
  (v) => {
361
- var b;
362
- return ((b = n.roles) == null ? void 0 : b.call(n, v)) ?? !0;
361
+ var P;
362
+ return ((P = n.roles) == null ? void 0 : P.call(n, v)) ?? !0;
363
363
  }
364
364
  )) {
365
- const v = T.get(A.name);
365
+ const v = A.get(_.name);
366
366
  if (v)
367
367
  try {
368
- const b = await w.rolePermissions.list(
368
+ const P = await w.rolePermissions.list(
369
369
  t.controlPlaneTenantId,
370
- A.id,
370
+ _.id,
371
371
  {}
372
372
  );
373
- b.length > 0 && await y.rolePermissions.assign(
373
+ P.length > 0 && await y.rolePermissions.assign(
374
374
  g.id,
375
375
  v,
376
- b.map((C) => ({
376
+ P.map((C) => ({
377
377
  role_id: v,
378
378
  resource_server_identifier: C.resource_server_identifier,
379
379
  permission_name: C.permission_name
380
380
  }))
381
381
  );
382
- } catch (b) {
382
+ } catch (P) {
383
383
  console.error(
384
- `Failed to sync permissions for role "${A.name}" to tenant "${g.id}":`,
385
- b
384
+ `Failed to sync permissions for role "${_.name}" to tenant "${g.id}":`,
385
+ P
386
386
  );
387
387
  }
388
388
  }
@@ -395,8 +395,8 @@ function fe(t) {
395
395
  }
396
396
  }
397
397
  } : void 0;
398
- async function d(m, g, h) {
399
- return (await m.roles.list(g, {
398
+ async function l(p, g, h) {
399
+ return (await p.roles.list(g, {
400
400
  q: `name:${h}`,
401
401
  per_page: 1
402
402
  })).roles[0] ?? null;
@@ -404,20 +404,20 @@ function fe(t) {
404
404
  return {
405
405
  entityHooks: {
406
406
  resourceServers: s,
407
- roles: p
407
+ roles: f
408
408
  },
409
409
  tenantHooks: {
410
- async afterCreate(m, g) {
410
+ async afterCreate(p, g) {
411
411
  const h = [
412
412
  o == null ? void 0 : o.afterCreate,
413
- (f == null ? void 0 : f.afterCreate) ?? (i == null ? void 0 : i.afterCreate)
413
+ (u == null ? void 0 : u.afterCreate) ?? (i == null ? void 0 : i.afterCreate)
414
414
  ], w = [];
415
415
  for (const y of h)
416
416
  if (y)
417
417
  try {
418
- await y(m, g);
419
- } catch (_) {
420
- w.push(_ instanceof Error ? _ : new Error(String(_)));
418
+ await y(p, g);
419
+ } catch (T) {
420
+ w.push(T instanceof Error ? T : new Error(String(T)));
421
421
  }
422
422
  if (w.length === 1) throw w[0];
423
423
  if (w.length > 1)
@@ -429,7 +429,7 @@ function fe(t) {
429
429
  }
430
430
  };
431
431
  }
432
- var P = class extends Error {
432
+ var b = class extends Error {
433
433
  /**
434
434
  * Creates an instance of `HTTPException`.
435
435
  * @param status - HTTP status code for the exception. Defaults to 500.
@@ -437,8 +437,8 @@ var P = class extends Error {
437
437
  */
438
438
  constructor(e = 500, n) {
439
439
  super(n == null ? void 0 : n.message, { cause: n == null ? void 0 : n.cause });
440
- F(this, "res");
441
- F(this, "status");
440
+ O(this, "res");
441
+ O(this, "status");
442
442
  this.res = n == null ? void 0 : n.res, this.status = e;
443
443
  }
444
444
  /**
@@ -455,10 +455,10 @@ var P = class extends Error {
455
455
  });
456
456
  }
457
457
  };
458
- function E(t, e) {
458
+ function M(t, e) {
459
459
  const n = new re();
460
460
  return n.openapi(
461
- M({
461
+ R({
462
462
  tags: ["tenants"],
463
463
  method: "get",
464
464
  path: "/",
@@ -475,7 +475,7 @@ function E(t, e) {
475
475
  content: {
476
476
  "application/json": {
477
477
  schema: S.object({
478
- tenants: S.array(G),
478
+ tenants: S.array(N),
479
479
  start: S.number().optional(),
480
480
  limit: S.number().optional(),
481
481
  length: S.number().optional()
@@ -487,40 +487,40 @@ function E(t, e) {
487
487
  }
488
488
  }),
489
489
  async (r) => {
490
- var m, g, h, w, y, _;
491
- const a = r.req.valid("query"), { page: c, per_page: l, include_totals: s, q: p } = a, o = r.var.user, i = (o == null ? void 0 : o.permissions) || [];
490
+ var p, g, h, w, y, T;
491
+ const a = r.req.valid("query"), { page: c, per_page: d, include_totals: s, q: f } = a, o = r.var.user, i = (o == null ? void 0 : o.permissions) || [];
492
492
  if (i.includes("auth:read") || i.includes("admin:organizations")) {
493
- const T = await r.env.data.tenants.list({
493
+ const A = await r.env.data.tenants.list({
494
494
  page: c,
495
- per_page: l,
495
+ per_page: d,
496
496
  include_totals: s,
497
- q: p
497
+ q: f
498
498
  });
499
499
  return s ? r.json({
500
- tenants: T.tenants,
501
- start: ((m = T.totals) == null ? void 0 : m.start) ?? 0,
502
- limit: ((g = T.totals) == null ? void 0 : g.limit) ?? l,
503
- length: T.tenants.length
504
- }) : r.json({ tenants: T.tenants });
500
+ tenants: A.tenants,
501
+ start: ((p = A.totals) == null ? void 0 : p.start) ?? 0,
502
+ limit: ((g = A.totals) == null ? void 0 : g.limit) ?? d,
503
+ length: A.tenants.length
504
+ }) : r.json({ tenants: A.tenants });
505
505
  }
506
- const d = ((h = t.accessControl) == null ? void 0 : h.controlPlaneTenantId) ?? ((w = r.env.data.multiTenancyConfig) == null ? void 0 : w.controlPlaneTenantId);
507
- if (d && (o != null && o.sub)) {
508
- const A = (await O(
506
+ const l = ((h = t.accessControl) == null ? void 0 : h.controlPlaneTenantId) ?? ((w = r.env.data.multiTenancyConfig) == null ? void 0 : w.controlPlaneTenantId);
507
+ if (l && (o != null && o.sub)) {
508
+ const _ = (await F(
509
509
  (z) => r.env.data.userOrganizations.listUserOrganizations(
510
- d,
510
+ l,
511
511
  o.sub,
512
512
  z
513
513
  ),
514
514
  "organizations"
515
515
  )).map((z) => z.name);
516
- if (A.length === 0)
516
+ if (_.length === 0)
517
517
  return s ? r.json({
518
518
  tenants: [],
519
519
  start: 0,
520
- limit: l ?? 50,
520
+ limit: d ?? 50,
521
521
  length: 0
522
522
  }) : r.json({ tenants: [] });
523
- const v = A.length, b = c ?? 0, C = l ?? 50, $ = b * C, I = A.slice($, $ + C);
523
+ const v = _.length, P = c ?? 0, C = d ?? 50, $ = P * C, I = _.slice($, $ + C);
524
524
  if (I.length === 0)
525
525
  return s ? r.json({
526
526
  tenants: [],
@@ -528,34 +528,34 @@ function E(t, e) {
528
528
  limit: C,
529
529
  length: v
530
530
  }) : r.json({ tenants: [] });
531
- const N = I.map((z) => `id:${z}`).join(" OR "), J = p ? `(${N}) AND (${p})` : N, H = await r.env.data.tenants.list({
531
+ const j = I.map((z) => `id:${z}`).join(" OR "), J = f ? `(${j}) AND (${f})` : j, E = await r.env.data.tenants.list({
532
532
  q: J,
533
533
  per_page: C,
534
534
  include_totals: !1
535
535
  // We calculate totals from accessibleTenantIds
536
536
  });
537
537
  return s ? r.json({
538
- tenants: H.tenants,
538
+ tenants: E.tenants,
539
539
  start: $,
540
540
  limit: C,
541
541
  length: v
542
- }) : r.json({ tenants: H.tenants });
542
+ }) : r.json({ tenants: E.tenants });
543
543
  }
544
- const u = await r.env.data.tenants.list({
544
+ const m = await r.env.data.tenants.list({
545
545
  page: c,
546
- per_page: l,
546
+ per_page: d,
547
547
  include_totals: s,
548
- q: p
548
+ q: f
549
549
  });
550
550
  return s ? r.json({
551
- tenants: u.tenants,
552
- start: ((y = u.totals) == null ? void 0 : y.start) ?? 0,
553
- limit: ((_ = u.totals) == null ? void 0 : _.limit) ?? l,
554
- length: u.tenants.length
555
- }) : r.json({ tenants: u.tenants });
551
+ tenants: m.tenants,
552
+ start: ((y = m.totals) == null ? void 0 : y.start) ?? 0,
553
+ limit: ((T = m.totals) == null ? void 0 : T.limit) ?? d,
554
+ length: m.tenants.length
555
+ }) : r.json({ tenants: m.tenants });
556
556
  }
557
557
  ), n.openapi(
558
- M({
558
+ R({
559
559
  tags: ["tenants"],
560
560
  method: "post",
561
561
  path: "/",
@@ -577,7 +577,7 @@ function E(t, e) {
577
577
  201: {
578
578
  content: {
579
579
  "application/json": {
580
- schema: G
580
+ schema: N
581
581
  }
582
582
  },
583
583
  description: "Tenant created"
@@ -591,23 +591,23 @@ function E(t, e) {
591
591
  }
592
592
  }),
593
593
  async (r) => {
594
- var p, o;
594
+ var f, o;
595
595
  const a = r.var.user;
596
596
  if (!(a != null && a.sub))
597
- throw new P(401, {
597
+ throw new b(401, {
598
598
  message: "Authentication required to create tenants"
599
599
  });
600
600
  let c = r.req.valid("json");
601
- const l = {
601
+ const d = {
602
602
  adapters: r.env.data,
603
603
  ctx: r
604
604
  };
605
- (p = e.tenants) != null && p.beforeCreate && (c = await e.tenants.beforeCreate(l, c));
605
+ (f = e.tenants) != null && f.beforeCreate && (c = await e.tenants.beforeCreate(d, c));
606
606
  const s = await r.env.data.tenants.create(c);
607
- return (o = e.tenants) != null && o.afterCreate && await e.tenants.afterCreate(l, s), r.json(s, 201);
607
+ return (o = e.tenants) != null && o.afterCreate && await e.tenants.afterCreate(d, s), r.json(s, 201);
608
608
  }
609
609
  ), n.openapi(
610
- M({
610
+ R({
611
611
  tags: ["tenants"],
612
612
  method: "delete",
613
613
  path: "/{id}",
@@ -634,39 +634,39 @@ function E(t, e) {
634
634
  }
635
635
  }),
636
636
  async (r) => {
637
- var p, o, i, f;
638
- const { id: a } = r.req.valid("param"), c = ((p = t.accessControl) == null ? void 0 : p.controlPlaneTenantId) ?? ((o = r.env.data.multiTenancyConfig) == null ? void 0 : o.controlPlaneTenantId);
637
+ var f, o, i, u;
638
+ const { id: a } = r.req.valid("param"), c = ((f = t.accessControl) == null ? void 0 : f.controlPlaneTenantId) ?? ((o = r.env.data.multiTenancyConfig) == null ? void 0 : o.controlPlaneTenantId);
639
639
  if (c) {
640
- const d = r.var.user;
641
- if (!(d != null && d.sub))
642
- throw new P(401, {
640
+ const l = r.var.user;
641
+ if (!(l != null && l.sub))
642
+ throw new b(401, {
643
643
  message: "Authentication required"
644
644
  });
645
645
  if (a === c)
646
- throw new P(403, {
646
+ throw new b(403, {
647
647
  message: "Cannot delete the control plane"
648
648
  });
649
- if (!(await O(
649
+ if (!(await F(
650
650
  (g) => r.env.data.userOrganizations.listUserOrganizations(
651
651
  c,
652
- d.sub,
652
+ l.sub,
653
653
  g
654
654
  ),
655
655
  "organizations"
656
656
  )).some((g) => g.name === a))
657
- throw new P(403, {
657
+ throw new b(403, {
658
658
  message: "Access denied to this tenant"
659
659
  });
660
660
  }
661
661
  if (!await r.env.data.tenants.get(a))
662
- throw new P(404, {
662
+ throw new b(404, {
663
663
  message: "Tenant not found"
664
664
  });
665
665
  const s = {
666
666
  adapters: r.env.data,
667
667
  ctx: r
668
668
  };
669
- return (i = e.tenants) != null && i.beforeDelete && await e.tenants.beforeDelete(s, a), await r.env.data.tenants.remove(a), (f = e.tenants) != null && f.afterDelete && await e.tenants.afterDelete(s, a), r.body(null, 204);
669
+ return (i = e.tenants) != null && i.beforeDelete && await e.tenants.beforeDelete(s, a), await r.env.data.tenants.remove(a), (u = e.tenants) != null && u.afterDelete && await e.tenants.afterDelete(s, a), r.body(null, 204);
670
670
  }
671
671
  ), n;
672
672
  }
@@ -726,7 +726,7 @@ function we() {
726
726
  if (!r)
727
727
  return e();
728
728
  if (await pe(t.env.data, r, n))
729
- throw new P(403, {
729
+ throw new b(403, {
730
730
  message: `This ${ge(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`
731
731
  });
732
732
  return e();
@@ -737,7 +737,7 @@ const ye = [
737
737
  "app_secret",
738
738
  "twilio_token"
739
739
  ];
740
- function q(t) {
740
+ function V(t) {
741
741
  if (!t) return t;
742
742
  const e = { ...t };
743
743
  for (const n of ye)
@@ -757,96 +757,49 @@ function he(t, e) {
757
757
  controlPlaneTenantId: n,
758
758
  controlPlaneClientId: r
759
759
  },
760
- legacyClients: {
761
- ...t.legacyClients,
762
- get: async (c) => {
763
- var d;
764
- const l = await t.legacyClients.get(c);
765
- if (!l)
766
- return null;
767
- const s = r ? await t.legacyClients.get(r) : void 0, p = await t.connections.list(
768
- l.tenant.id
769
- ), o = n ? await t.connections.list(n) : { connections: [] }, i = p.connections.map((u) => {
770
- var w;
771
- const m = (w = o.connections) == null ? void 0 : w.find(
772
- (y) => y.strategy === u.strategy
773
- );
774
- if (!(m != null && m.options))
775
- return u;
776
- const g = R.parse({
777
- ...m || {},
778
- ...u
779
- }), h = a ? q(m.options) : m.options;
780
- return g.options = D.parse({
781
- ...h || {},
782
- ...u.options
783
- }), g;
784
- }).filter((u) => u), f = {
785
- ...(s == null ? void 0 : s.tenant) || {},
786
- ...l.tenant
787
- };
788
- return !l.tenant.audience && ((d = s == null ? void 0 : s.tenant) != null && d.audience) && (f.audience = s.tenant.audience), {
789
- ...l,
790
- web_origins: [
791
- ...(s == null ? void 0 : s.web_origins) || [],
792
- ...l.web_origins || []
793
- ],
794
- allowed_logout_urls: [
795
- ...(s == null ? void 0 : s.allowed_logout_urls) || [],
796
- ...l.allowed_logout_urls || []
797
- ],
798
- callbacks: [
799
- ...(s == null ? void 0 : s.callbacks) || [],
800
- ...l.callbacks || []
801
- ],
802
- connections: i,
803
- tenant: f
804
- };
805
- }
806
- },
807
760
  connections: {
808
761
  ...t.connections,
809
- get: async (c, l) => {
810
- var d;
762
+ get: async (c, d) => {
763
+ var l;
811
764
  const s = await t.connections.get(
812
765
  c,
813
- l
766
+ d
814
767
  );
815
768
  if (!s || !n || c === n)
816
769
  return s;
817
- const o = (d = (await t.connections.list(n)).connections) == null ? void 0 : d.find(
818
- (u) => u.strategy === s.strategy
770
+ const o = (l = (await t.connections.list(n)).connections) == null ? void 0 : l.find(
771
+ (m) => m.strategy === s.strategy
819
772
  );
820
773
  if (!(o != null && o.options))
821
774
  return s;
822
- const i = R.parse({
775
+ const i = k.parse({
823
776
  ...o,
824
777
  ...s
825
- }), f = a ? q(o.options) : o.options;
826
- return i.options = D.parse({
827
- ...f || {},
778
+ }), u = a ? V(o.options) : o.options;
779
+ return i.options = H.parse({
780
+ ...u || {},
828
781
  ...s.options
829
782
  }), i;
830
783
  },
831
- list: async (c, l) => {
832
- const s = await t.connections.list(c, l);
784
+ list: async (c, d) => {
785
+ const s = await t.connections.list(c, d);
833
786
  if (!n || c === n)
834
787
  return s;
835
- const p = await t.connections.list(n), o = s.connections.map((i) => {
836
- var m;
837
- const f = (m = p.connections) == null ? void 0 : m.find(
788
+ const f = await t.connections.list(n), o = s.connections.map((i) => {
789
+ var p;
790
+ const u = (p = f.connections) == null ? void 0 : p.find(
838
791
  (g) => g.strategy === i.strategy
839
792
  );
840
- if (!(f != null && f.options))
793
+ if (!(u != null && u.options))
841
794
  return i;
842
- const d = R.parse({
843
- ...f,
795
+ const l = k.parse({
796
+ ...u,
844
797
  ...i
845
- }), u = a ? q(f.options) : f.options;
846
- return d.options = D.parse({
847
- ...u || {},
798
+ }), m = a ? V(u.options) : u.options;
799
+ return l.options = H.parse({
800
+ ...m || {},
848
801
  ...i.options
849
- }), d;
802
+ }), l;
850
803
  });
851
804
  return {
852
805
  ...s,
@@ -863,7 +816,7 @@ function he(t, e) {
863
816
  // They remain part of ...baseAdapters and can be properly wrapped by caching.
864
817
  };
865
818
  }
866
- function j(t, e) {
819
+ function D(t, e) {
867
820
  return he(t, e);
868
821
  }
869
822
  function ve(t) {
@@ -872,30 +825,30 @@ function ve(t) {
872
825
  return (r == null ? void 0 : r.tenant_id) === t && r.org_name && e.set("tenant_id", r.org_name), n();
873
826
  };
874
827
  }
875
- function _e(t) {
828
+ function Te(t) {
876
829
  return async (e, n) => {
877
830
  if (!t.accessControl)
878
831
  return n();
879
- const { controlPlaneTenantId: r } = t.accessControl, a = e.var.org_name, c = e.var.organization_id, l = a || c;
832
+ const { controlPlaneTenantId: r } = t.accessControl, a = e.var.org_name, c = e.var.organization_id, d = a || c;
880
833
  let s = e.var.tenant_id;
881
- const p = e.var.user, i = (p != null && p.aud ? Array.isArray(p.aud) ? p.aud : [p.aud] : []).includes(W);
882
- if (!s && l && i && (e.set("tenant_id", l), s = l), !s)
883
- throw new P(400, {
834
+ const f = e.var.user, i = (f != null && f.aud ? Array.isArray(f.aud) ? f.aud : [f.aud] : []).includes(W);
835
+ if (!s && d && i && (e.set("tenant_id", d), s = d), !s)
836
+ throw new b(400, {
884
837
  message: "Tenant ID not found in request"
885
838
  });
886
- if (!ae(
839
+ if (!se(
887
840
  c,
888
841
  s,
889
842
  r,
890
843
  a
891
844
  ))
892
- throw new P(403, {
845
+ throw new b(403, {
893
846
  message: `Access denied to tenant ${s}`
894
847
  });
895
848
  return n();
896
849
  };
897
850
  }
898
- function Te(t) {
851
+ function Ae(t) {
899
852
  return async (e, n) => {
900
853
  if (!t.subdomainRouting)
901
854
  return n();
@@ -903,40 +856,40 @@ function Te(t) {
903
856
  baseDomain: r,
904
857
  reservedSubdomains: a = [],
905
858
  resolveSubdomain: c
906
- } = t.subdomainRouting, l = e.req.header("host") || "";
859
+ } = t.subdomainRouting, d = e.req.header("host") || "";
907
860
  let s = null;
908
- if (l.endsWith(r)) {
909
- const o = l.slice(0, -(r.length + 1));
861
+ if (d.endsWith(r)) {
862
+ const o = d.slice(0, -(r.length + 1));
910
863
  o && !o.includes(".") && (s = o);
911
864
  }
912
865
  if (s && a.includes(s) && (s = null), !s)
913
866
  return t.accessControl && e.set("tenant_id", t.accessControl.controlPlaneTenantId), n();
914
- let p = null;
867
+ let f = null;
915
868
  if (c)
916
- p = await c(s);
869
+ f = await c(s);
917
870
  else if (t.subdomainRouting.useOrganizations !== !1 && t.accessControl)
918
871
  try {
919
872
  const o = await e.env.data.organizations.get(
920
873
  t.accessControl.controlPlaneTenantId,
921
874
  s
922
875
  );
923
- o && (p = o.id);
876
+ o && (f = o.id);
924
877
  } catch {
925
878
  }
926
- if (!p)
927
- throw new P(404, {
879
+ if (!f)
880
+ throw new b(404, {
928
881
  message: `Tenant not found for subdomain: ${s}`
929
882
  });
930
- return e.set("tenant_id", p), n();
883
+ return e.set("tenant_id", f), n();
931
884
  };
932
885
  }
933
- function Ae(t) {
886
+ function _e(t) {
934
887
  return async (e, n) => {
935
888
  if (!t.databaseIsolation)
936
889
  return n();
937
890
  const r = e.var.tenant_id;
938
891
  if (!r)
939
- throw new P(400, {
892
+ throw new b(400, {
940
893
  message: "Tenant ID not found in request"
941
894
  });
942
895
  try {
@@ -946,7 +899,7 @@ function Ae(t) {
946
899
  throw console.error(
947
900
  `Failed to resolve database for tenant ${r}:`,
948
901
  a
949
- ), new P(500, {
902
+ ), new b(500, {
950
903
  message: "Failed to resolve tenant database"
951
904
  });
952
905
  }
@@ -954,7 +907,7 @@ function Ae(t) {
954
907
  };
955
908
  }
956
909
  function Q(t) {
957
- const e = Te(t), n = _e(t), r = Ae(t);
910
+ const e = Ae(t), n = Te(t), r = _e(t);
958
911
  return async (a, c) => (await e(a, async () => {
959
912
  }), await n(a, async () => {
960
913
  }), await r(a, async () => {
@@ -969,19 +922,19 @@ function $e(t) {
969
922
  clientId: a
970
923
  } = {},
971
924
  sync: c = { resourceServers: !0, roles: !0 },
972
- defaultPermissions: l = ["tenant:admin"],
925
+ defaultPermissions: d = ["tenant:admin"],
973
926
  requireOrganizationMatch: s = !1,
974
- managementApiExtensions: p = [],
927
+ managementApiExtensions: f = [],
975
928
  entityHooks: o,
976
929
  getChildTenantIds: i,
977
- getAdapters: f,
978
- ...d
930
+ getAdapters: u,
931
+ ...l
979
932
  } = t;
980
- let u = e, m = e;
981
- n && (u = j(e, {
933
+ let m = e, p = e;
934
+ n && (m = D(e, {
982
935
  controlPlaneTenantId: r,
983
936
  controlPlaneClientId: a
984
- }), m = j(e, {
937
+ }), p = D(e, {
985
938
  controlPlaneTenantId: r,
986
939
  controlPlaneClientId: a,
987
940
  excludeSensitiveFields: !0
@@ -989,48 +942,48 @@ function $e(t) {
989
942
  const g = c !== !1, h = g ? {
990
943
  resourceServers: c.resourceServers ?? !0,
991
944
  roles: c.roles ?? !0
992
- } : { resourceServers: !1, roles: !1 }, _ = {
945
+ } : { resourceServers: !1, roles: !1 }, T = {
993
946
  controlPlaneTenantId: r,
994
- getChildTenantIds: i ?? (async () => (await O(
995
- (I) => u.tenants.list(I),
947
+ getChildTenantIds: i ?? (async () => (await F(
948
+ (I) => m.tenants.list(I),
996
949
  "tenants",
997
950
  { cursorField: "id", pageSize: 100 }
998
951
  )).filter((I) => I.id !== r).map((I) => I.id)),
999
- getAdapters: f ?? (async () => u),
1000
- getControlPlaneAdapters: async () => u,
952
+ getAdapters: u ?? (async () => m),
953
+ getControlPlaneAdapters: async () => m,
1001
954
  sync: h
1002
- }, { entityHooks: T, tenantHooks: A } = fe(_), v = {
955
+ }, { entityHooks: A, tenantHooks: _ } = fe(T), v = {
1003
956
  resourceServers: [
1004
- T.resourceServers,
957
+ A.resourceServers,
1005
958
  ...(o == null ? void 0 : o.resourceServers) ?? []
1006
959
  ],
1007
- roles: [T.roles, ...(o == null ? void 0 : o.roles) ?? []],
960
+ roles: [A.roles, ...(o == null ? void 0 : o.roles) ?? []],
1008
961
  connections: (o == null ? void 0 : o.connections) ?? [],
1009
962
  tenants: (o == null ? void 0 : o.tenants) ?? [],
1010
963
  rolePermissions: (o == null ? void 0 : o.rolePermissions) ?? []
1011
- }, b = E(
964
+ }, P = M(
1012
965
  {
1013
966
  accessControl: {
1014
967
  controlPlaneTenantId: r,
1015
968
  requireOrganizationMatch: s,
1016
- defaultPermissions: l
969
+ defaultPermissions: d
1017
970
  }
1018
971
  },
1019
- { tenants: A }
972
+ { tenants: _ }
1020
973
  ), { app: C } = ne({
1021
- dataAdapter: u,
1022
- managementDataAdapter: m,
1023
- ...d,
974
+ dataAdapter: m,
975
+ managementDataAdapter: p,
976
+ ...l,
1024
977
  entityHooks: v,
1025
978
  managementApiExtensions: [
1026
- ...p,
1027
- { path: "/tenants", router: b }
979
+ ...f,
980
+ { path: "/tenants", router: P }
1028
981
  ]
1029
982
  });
1030
983
  return C.use("/api/v2/*", ve(r)), g && C.use("/api/v2/*", we()), { app: C, controlPlaneTenantId: r };
1031
984
  }
1032
985
  function ze(t) {
1033
- const e = k(t);
986
+ const e = q(t);
1034
987
  return {
1035
988
  name: "multi-tenancy",
1036
989
  // Apply multi-tenancy middleware for subdomain routing, database resolution, etc.
@@ -1041,7 +994,7 @@ function ze(t) {
1041
994
  routes: [
1042
995
  {
1043
996
  path: "/management",
1044
- handler: E(t, e)
997
+ handler: M(t, e)
1045
998
  }
1046
999
  ],
1047
1000
  // Called when plugin is registered
@@ -1054,23 +1007,23 @@ function ze(t) {
1054
1007
  }
1055
1008
  };
1056
1009
  }
1057
- function k(t) {
1058
- const e = t.accessControl ? se(t.accessControl) : {}, n = t.databaseIsolation ? oe(t.databaseIsolation) : {}, r = ce(t);
1010
+ function q(t) {
1011
+ const e = t.accessControl ? ae(t.accessControl) : {}, n = t.databaseIsolation ? oe(t.databaseIsolation) : {}, r = ce(t);
1059
1012
  return {
1060
1013
  ...e,
1061
1014
  ...n,
1062
1015
  tenants: r
1063
1016
  };
1064
1017
  }
1065
- function be(t) {
1066
- const e = new Z(), n = k(t);
1067
- return e.route("/tenants", E(t, n)), e;
1018
+ function Pe(t) {
1019
+ const e = new Z(), n = q(t);
1020
+ return e.route("/tenants", M(t, n)), e;
1068
1021
  }
1069
- function Oe(t) {
1022
+ function Fe(t) {
1070
1023
  return {
1071
- hooks: k(t),
1024
+ hooks: q(t),
1072
1025
  middleware: Q(t),
1073
- app: be(t),
1026
+ app: Pe(t),
1074
1027
  config: t,
1075
1028
  /**
1076
1029
  * Wraps data adapters with runtime fallback from the control plane.
@@ -1082,7 +1035,7 @@ function Oe(t) {
1082
1035
  */
1083
1036
  wrapAdapters: (e, n) => {
1084
1037
  var r;
1085
- return j(e, {
1038
+ return D(e, {
1086
1039
  controlPlaneTenantId: (r = t.accessControl) == null ? void 0 : r.controlPlaneTenantId,
1087
1040
  controlPlaneClientId: n == null ? void 0 : n.controlPlaneClientId
1088
1041
  });
@@ -1090,23 +1043,23 @@ function Oe(t) {
1090
1043
  };
1091
1044
  }
1092
1045
  export {
1093
- se as createAccessControlHooks,
1094
- _e as createAccessControlMiddleware,
1046
+ ae as createAccessControlHooks,
1047
+ Te as createAccessControlMiddleware,
1095
1048
  ve as createControlPlaneTenantMiddleware,
1096
1049
  oe as createDatabaseHooks,
1097
- Ae as createDatabaseMiddleware,
1098
- be as createMultiTenancy,
1099
- k as createMultiTenancyHooks,
1050
+ _e as createDatabaseMiddleware,
1051
+ Pe as createMultiTenancy,
1052
+ q as createMultiTenancyHooks,
1100
1053
  Q as createMultiTenancyMiddleware,
1101
1054
  ze as createMultiTenancyPlugin,
1102
1055
  we as createProtectSyncedMiddleware,
1103
1056
  ce as createProvisioningHooks,
1104
1057
  he as createRuntimeFallbackAdapter,
1105
- Te as createSubdomainMiddleware,
1058
+ Ae as createSubdomainMiddleware,
1106
1059
  fe as createSyncHooks,
1107
- E as createTenantsOpenAPIRouter,
1060
+ M as createTenantsOpenAPIRouter,
1108
1061
  $e as initMultiTenant,
1109
- Oe as setupMultiTenancy,
1110
- ae as validateTenantAccess,
1111
- j as withRuntimeFallback
1062
+ Fe as setupMultiTenancy,
1063
+ se as validateTenantAccess,
1064
+ D as withRuntimeFallback
1112
1065
  };
@@ -1 +1 @@
1
- {"version":3,"file":"settings-inheritance.d.ts","sourceRoot":"","sources":["../../../src/middleware/settings-inheritance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAKb,MAAM,UAAU,CAAC;AA+BlB;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CAmNd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CAEd"}
1
+ {"version":3,"file":"settings-inheritance.d.ts","sourceRoot":"","sources":["../../../src/middleware/settings-inheritance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAIb,MAAM,UAAU,CAAC;AA+BlB;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CA0Hd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CAEd"}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "type": "git",
12
12
  "url": "https://github.com/markusahlstrand/authhero"
13
13
  },
14
- "version": "14.6.0",
14
+ "version": "14.7.0",
15
15
  "description": "Multi-tenancy support for AuthHero with organization-based access control and per-tenant database isolation",
16
16
  "files": [
17
17
  "dist"
@@ -36,9 +36,9 @@
36
36
  "typescript": "^5.6.0",
37
37
  "vite": "^6.0.0",
38
38
  "vitest": "^2.1.0",
39
- "authhero": "4.12.0",
40
- "@authhero/adapter-interfaces": "0.122.0",
41
- "@authhero/kysely-adapter": "10.83.0"
39
+ "@authhero/kysely-adapter": "10.88.0",
40
+ "authhero": "4.23.0",
41
+ "@authhero/adapter-interfaces": "0.127.0"
42
42
  },
43
43
  "dependencies": {
44
44
  "zod": "^3.24.0"