@authhero/multi-tenancy 13.19.0 → 13.20.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.
- package/dist/multi-tenancy.cjs +1 -1
- package/dist/multi-tenancy.d.ts +2 -2
- package/dist/multi-tenancy.mjs +12 -12
- package/package.json +4 -4
package/dist/multi-tenancy.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var ee=Object.defineProperty;var te=(n,e,t)=>e in n?ee(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var k=(n,e,t)=>te(n,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ne=require("hono"),P=require("authhero"),C=require("@hono/zod-openapi"),I=require("@authhero/adapter-interfaces");function U(n){const{controlPlaneTenantId:e,requireOrganizationMatch:t=!0}=n;return{async onTenantAccessValidation(s,a){if(a===e)return!0;if(t){const i=s.var.org_name,o=s.var.organization_id,r=i||o;return r?r===a:!1}return!0}}}function B(n,e,t,s){if(e===t)return!0;const a=s||n;return a?a===e:!1}function K(n){return{async resolveDataAdapters(e){try{return await n.getAdapters(e)}catch(t){console.error(`Failed to resolve data adapters for tenant ${e}:`,t);return}}}}function L(n){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:P.getTenantAudience(t.id)}:t},async afterCreate(e,t){const{accessControl:s,databaseIsolation:a}=n;s&&e.ctx&&await se(e,t,s),a!=null&&a.onProvision&&await a.onProvision(t.id)},async beforeDelete(e,t){const{accessControl:s,databaseIsolation:a}=n;if(s)try{const o=(await e.adapters.organizations.list(s.controlPlaneTenantId)).organizations.find(r=>r.name===t);o&&await e.adapters.organizations.remove(s.controlPlaneTenantId,o.id)}catch(i){console.warn(`Failed to remove organization for tenant ${t}:`,i)}if(a!=null&&a.onDeprovision)try{await a.onDeprovision(t)}catch(i){console.warn(`Failed to deprovision database for tenant ${t}:`,i)}}}}async function se(n,e,t){const{controlPlaneTenantId:s,defaultPermissions:a,defaultRoles:i,issuer:o,adminRoleName:r="Tenant Admin",adminRoleDescription:m="Full access to all tenant management operations",addCreatorToOrganization:d=!0}=t,c=await n.adapters.organizations.create(s,{name:e.id,display_name:e.friendly_name||e.id});let p;if(o&&(p=await re(n,s,r,m)),d&&n.ctx){const l=n.ctx.var.user;if(l!=null&&l.sub&&!await ae(n,s,l.sub))try{await n.adapters.userOrganizations.create(s,{user_id:l.sub,organization_id:c.id}),p&&await n.adapters.userRoles.create(s,l.sub,p,c.id)}catch(w){console.warn(`Failed to add creator ${l.sub} to organization ${c.id}:`,w)}}i&&i.length>0&&console.log(`Would assign roles ${i.join(", ")} to organization ${c.id}`),a&&a.length>0&&console.log(`Would grant permissions ${a.join(", ")} to organization ${c.id}`)}async function ae(n,e,t){const s=await n.adapters.userRoles.list(e,t,void 0,"");for(const a of s)if((await n.adapters.rolePermissions.list(e,a.id,{per_page:1e3})).some(r=>r.permission_name==="admin:organizations"))return!0;return!1}async function re(n,e,t,s){const i=(await n.adapters.roles.list(e,{})).roles.find(d=>d.name===t);if(i)return i.id;const o=await n.adapters.roles.create(e,{name:t,description:s}),r=P.MANAGEMENT_API_AUDIENCE,m=P.MANAGEMENT_API_SCOPES.map(d=>({role_id:o.id,resource_server_identifier:r,permission_name:d.value}));return await n.adapters.rolePermissions.assign(e,o.id,m),o.id}const oe=["client_id","client_secret","app_secret","kid","team_id","twilio_sid","twilio_token"];function q(n,e,t=()=>!0){const{controlPlaneTenantId:s,getChildTenantIds:a,getAdapters:i}=n,o=new Map;async function r(c,p,l){return(await e(c).list(p,{q:`name:${l}`,per_page:1}))[0]??null}async function m(c){const p=await a(),l=e(await i(s));await Promise.all(p.map(async u=>{try{const w=await i(u),g=e(w),h={...l.transform(c),is_system:!0},y=await r(w,u,c.name),_=y?g.getId(y):void 0;if(y&&_){const b=g.preserveOnUpdate?g.preserveOnUpdate(y,h):h;await g.update(u,_,b)}else await g.create(u,h)}catch(w){console.error(`Failed to sync ${l.listKey} "${c.name}" to tenant "${u}":`,w)}}))}async function d(c){const p=await a();await Promise.all(p.map(async l=>{try{const u=await i(l),w=e(u),g=await r(u,l,c),f=g?w.getId(g):void 0;g&&f&&await w.remove(l,f)}catch(u){console.error(`Failed to delete entity "${c}" from tenant "${l}":`,u)}}))}return{afterCreate:async(c,p)=>{c.tenantId===s&&t(p)&&await m(p)},afterUpdate:async(c,p,l)=>{c.tenantId===s&&t(l)&&await m(l)},beforeDelete:async(c,p)=>{if(c.tenantId!==s)return;const u=await e(c.adapters).get(c.tenantId,p);u&&t(u)&&o.set(p,u)},afterDelete:async(c,p)=>{if(c.tenantId!==s)return;const l=o.get(p);l&&(o.delete(p),await d(l.name))}}}function D(n,e,t=()=>!0){const{controlPlaneTenantId:s,getControlPlaneAdapters:a,getAdapters:i}=n;return{async afterCreate(o,r){if(r.id!==s)try{const m=await a(),d=await i(r.id),c=e(m),p=e(d),l=await P.fetchAll(u=>c.listPaginated(s,u),c.listKey,{cursorField:"id",pageSize:100});await Promise.all(l.filter(u=>t(u)).map(async u=>{try{const w=c.transform(u);await p.create(r.id,{...w,is_system:!0})}catch(w){console.error(`Failed to sync entity to new tenant "${r.id}":`,w)}}))}catch(m){console.error(`Failed to sync entities to new tenant "${r.id}":`,m)}}}}const N=n=>({list:async(e,t)=>(await n.resourceServers.list(e,t)).resource_servers,listPaginated:(e,t)=>n.resourceServers.list(e,t),get:(e,t)=>n.resourceServers.get(e,t),create:(e,t)=>n.resourceServers.create(e,t),update:(e,t,s)=>n.resourceServers.update(e,t,s),remove:(e,t)=>n.resourceServers.remove(e,t),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})}),H=n=>({list:async(e,t)=>(await n.roles.list(e,t)).roles,listPaginated:(e,t)=>n.roles.list(e,t),get:(e,t)=>n.roles.get(e,t),create:(e,t)=>n.roles.create(e,t),update:(e,t,s)=>n.roles.update(e,t,s),remove:(e,t)=>n.roles.remove(e,t),listKey:"roles",getId:e=>e.id,transform:e=>({id:e.id,name:e.name,description:e.description})}),G=n=>({list:async(e,t)=>(await n.connections.list(e,t)).connections,listPaginated:(e,t)=>n.connections.list(e,t),get:(e,t)=>n.connections.get(e,t),create:(e,t)=>n.connections.create(e,t),update:(e,t,s)=>n.connections.update(e,t,s),remove:(e,t)=>n.connections.remove(e,t),listKey:"connections",getId:e=>e.id,transform:e=>{const t=e.options?{...e.options}:{};for(const s of oe)delete t[s];return{id:e.id,name:e.name,display_name:e.display_name,strategy:e.strategy,options:t,response_type:e.response_type,response_mode:e.response_mode,is_domain_connection:e.is_domain_connection,show_as_button:e.show_as_button,metadata:e.metadata}},preserveOnUpdate:(e,t)=>{const s=e.options||{};return{...t,options:{...t.options,client_id:s.client_id,client_secret:s.client_secret,app_secret:s.app_secret,kid:s.kid,team_id:s.team_id,twilio_sid:s.twilio_sid,twilio_token:s.twilio_token}}}});function V(n){const{sync:e={},filters:t={}}=n,s=e.resourceServers??!0,a=e.roles??!0,i=e.connections??!0,o=s?q(n,N,t.resourceServers):void 0,r=a?q(n,H,t.roles):void 0,m=i?q(n,G,t.connections):void 0,d=s?D(n,N,t.resourceServers):void 0,c=a?D(n,H,t.roles):void 0,p=i?D(n,G,t.connections):void 0,l=a?{async afterCreate(g,f){var h;if(f.id!==n.controlPlaneTenantId){await((h=c==null?void 0:c.afterCreate)==null?void 0:h.call(c,g,f));try{const y=await n.getControlPlaneAdapters(),_=await n.getAdapters(f.id),b=await P.fetchAll(v=>y.roles.list(n.controlPlaneTenantId,v),"roles",{cursorField:"id",pageSize:100}),z=new Map;for(const v of b.filter(T=>{var A;return((A=t.roles)==null?void 0:A.call(t,T))??!0})){const T=await u(_,f.id,v.name);T&&z.set(v.name,T.id)}for(const v of b.filter(T=>{var A;return((A=t.roles)==null?void 0:A.call(t,T))??!0})){const T=z.get(v.name);if(T)try{const A=await y.rolePermissions.list(n.controlPlaneTenantId,v.id,{});A.length>0&&await _.rolePermissions.assign(f.id,T,A.map(M=>({role_id:T,resource_server_identifier:M.resource_server_identifier,permission_name:M.permission_name})))}catch(A){console.error(`Failed to sync permissions for role "${v.name}" to tenant "${f.id}":`,A)}}}catch(y){console.error(`Failed to sync role permissions to tenant "${f.id}":`,y)}}}}:void 0;async function u(g,f,h){return(await g.roles.list(f,{q:`name:${h}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:o,roles:r,connections:m},tenantHooks:{async afterCreate(g,f){const h=[d==null?void 0:d.afterCreate,(l==null?void 0:l.afterCreate)??(c==null?void 0:c.afterCreate),p==null?void 0:p.afterCreate],y=[];for(const _ of h)if(_)try{await _(g,f)}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,y.map(_=>_.message).join("; "))}}}}var S=class extends Error{constructor(e=500,t){super(t==null?void 0:t.message,{cause:t==null?void 0:t.cause});k(this,"res");k(this,"status");this.res=t==null?void 0:t.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 R(n,e){const t=new C.OpenAPIHono;return t.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 s=>{var u,w,g,f;const a=s.req.valid("query"),{page:i,per_page:o,include_totals:r,q:m}=a,d=s.var.user,c=(d==null?void 0:d.permissions)||[];if(c.includes("auth:read")||c.includes("admin:organizations")){const h=await s.env.data.tenants.list({page:i,per_page:o,include_totals:r,q:m});return r?s.json({tenants:h.tenants,start:((u=h.totals)==null?void 0:u.start)??0,limit:((w=h.totals)==null?void 0:w.limit)??o,length:h.tenants.length}):s.json({tenants:h.tenants})}if(n.accessControl&&(d!=null&&d.sub)){const h=n.accessControl.controlPlaneTenantId,_=(await P.fetchAll(O=>s.env.data.userOrganizations.listUserOrganizations(h,d.sub,O),"organizations")).map(O=>O.name);if(_.length===0)return r?s.json({tenants:[],start:0,limit:o??50,length:0}):s.json({tenants:[]});const b=_.length,z=i??0,v=o??50,T=z*v,A=_.slice(T,T+v);if(A.length===0)return r?s.json({tenants:[],start:T,limit:v,length:b}):s.json({tenants:[]});const M=A.map(O=>`id:${O}`).join(" OR "),x=m?`(${M}) AND (${m})`:M,E=await s.env.data.tenants.list({q:x,per_page:v,include_totals:!1});return r?s.json({tenants:E.tenants,start:T,limit:v,length:b}):s.json({tenants:E.tenants})}const l=await s.env.data.tenants.list({page:i,per_page:o,include_totals:r,q:m});return r?s.json({tenants:l.tenants,start:((g=l.totals)==null?void 0:g.start)??0,limit:((f=l.totals)==null?void 0:f.limit)??o,length:l.tenants.length}):s.json({tenants:l.tenants})}),t.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 s=>{var m,d;const a=s.var.user;if(!(a!=null&&a.sub))throw new S(401,{message:"Authentication required to create tenants"});let i=s.req.valid("json");const o={adapters:s.env.data,ctx:s};(m=e.tenants)!=null&&m.beforeCreate&&(i=await e.tenants.beforeCreate(o,i));const r=await s.env.data.tenants.create(i);return(d=e.tenants)!=null&&d.afterCreate&&await e.tenants.afterCreate(o,r),s.json(r,201)}),t.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 s=>{var r,m;const{id:a}=s.req.valid("param");if(n.accessControl){const d=s.var.user,c=n.accessControl.controlPlaneTenantId;if(!(d!=null&&d.sub))throw new S(401,{message:"Authentication required"});if(a===c)throw new S(403,{message:"Cannot delete the control plane"});if(!(await P.fetchAll(u=>s.env.data.userOrganizations.listUserOrganizations(c,d.sub,u),"organizations")).some(u=>u.name===a))throw new S(403,{message:"Access denied to this tenant"})}if(!await s.env.data.tenants.get(a))throw new S(404,{message:"Tenant not found"});const o={adapters:s.env.data,ctx:s};return(r=e.tenants)!=null&&r.beforeDelete&&await e.tenants.beforeDelete(o,a),await s.env.data.tenants.remove(a),(m=e.tenants)!=null&&m.afterDelete&&await e.tenants.afterDelete(o,a),s.body(null,204)}),t}function ie(n){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:t,type:s}of e){const a=n.match(t);if(a&&a[1])return{type:s,id:a[1]}}return null}async function ce(n,e,t){try{switch(t.type){case"resource_server":{const s=await n.resourceServers.get(e,t.id);return(s==null?void 0:s.is_system)===!0}case"role":{const s=await n.roles.get(e,t.id);return(s==null?void 0:s.is_system)===!0}case"connection":{const s=await n.connections.get(e,t.id);return(s==null?void 0:s.is_system)===!0}default:return!1}}catch{return!1}}function le(n){return{resource_server:"resource server",role:"role",connection:"connection"}[n]}function W(){return async(n,e)=>{if(!["PATCH","PUT","DELETE"].includes(n.req.method))return e();const t=ie(n.req.path);if(!t)return e();const s=n.var.tenant_id||n.req.header("x-tenant-id")||n.req.header("tenant-id");if(!s)return e();if(await ce(n.env.data,s,t))throw new S(403,{message:`This ${le(t.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return e()}}function F(n,e){const{controlPlaneTenantId:t,controlPlaneClientId:s}=e;return{...n,legacyClients:{...n.legacyClients,get:async a=>{var p;const i=await n.legacyClients.get(a);if(!i)return null;const o=s?await n.legacyClients.get(s):void 0,r=await n.connections.list(i.tenant.id),m=t?await n.connections.list(t):{connections:[]},d=r.connections.map(l=>{var g;const u=(g=m.connections)==null?void 0:g.find(f=>f.name===l.name);if(!(u!=null&&u.options))return l;const w=I.connectionSchema.parse({...u||{},...l});return w.options=I.connectionOptionsSchema.parse({...u.options||{},...l.options}),w}).filter(l=>l),c={...(o==null?void 0:o.tenant)||{},...i.tenant};return!i.tenant.audience&&((p=o==null?void 0:o.tenant)!=null&&p.audience)&&(c.audience=o.tenant.audience),{...i,web_origins:[...(o==null?void 0:o.web_origins)||[],...i.web_origins||[]],allowed_logout_urls:[...(o==null?void 0:o.allowed_logout_urls)||[],...i.allowed_logout_urls||[]],callbacks:[...(o==null?void 0:o.callbacks)||[],...i.callbacks||[]],connections:d,tenant:c}}},connections:{...n.connections,get:async(a,i)=>{const o=await n.connections.get(a,i);if(!o||!t)return o;const r=await n.connections.get(t,i);if(!r)return o;const m=I.connectionSchema.parse({...r,...o});return m.options=I.connectionOptionsSchema.parse({...r.options||{},...o.options}),m},list:async(a,i)=>{const o=await n.connections.list(a,i);if(!t||a===t)return o;const r=await n.connections.list(t),m=o.connections.map(d=>{var l;const c=(l=r.connections)==null?void 0:l.find(u=>u.name===d.name);if(!(c!=null&&c.options))return d;const p=I.connectionSchema.parse({...c,...d});return p.options=I.connectionOptionsSchema.parse({...c.options||{},...d.options}),p});return{...o,connections:m}}}}}function Q(n,e){return F(n,e)}const de=F,ue=Q;function J(n){return async(e,t)=>{if(!n.accessControl)return t();const s=e.var.tenant_id,a=e.var.organization_id;if(!s)throw new S(400,{message:"Tenant ID not found in request"});if(!B(a,s,n.accessControl.controlPlaneTenantId))throw new S(403,{message:`Access denied to tenant ${s}`});return t()}}function X(n){return async(e,t)=>{if(!n.subdomainRouting)return t();const{baseDomain:s,reservedSubdomains:a=[],resolveSubdomain:i}=n.subdomainRouting,o=e.req.header("host")||"";let r=null;if(o.endsWith(s)){const d=o.slice(0,-(s.length+1));d&&!d.includes(".")&&(r=d)}if(r&&a.includes(r)&&(r=null),!r)return n.accessControl&&e.set("tenant_id",n.accessControl.controlPlaneTenantId),t();let m=null;if(i)m=await i(r);else if(n.subdomainRouting.useOrganizations!==!1&&n.accessControl)try{const d=await e.env.data.organizations.get(n.accessControl.controlPlaneTenantId,r);d&&(m=d.id)}catch{}if(!m)throw new S(404,{message:`Tenant not found for subdomain: ${r}`});return e.set("tenant_id",m),t()}}function Y(n){return async(e,t)=>{if(!n.databaseIsolation)return t();const s=e.var.tenant_id;if(!s)throw new S(400,{message:"Tenant ID not found in request"});try{const a=await n.databaseIsolation.getAdapters(s);e.env.data=a}catch(a){throw console.error(`Failed to resolve database for tenant ${s}:`,a),new S(500,{message:"Failed to resolve tenant database"})}return t()}}function j(n){const e=X(n),t=J(n),s=Y(n);return async(a,i)=>(await e(a,async()=>{}),await t(a,async()=>{}),await s(a,async()=>{}),i())}function me(n){const{dataAdapter:e,controlPlaneTenantId:t="control_plane",sync:s={resourceServers:!0,roles:!0,connections:!0},defaultPermissions:a=["tenant:admin"],requireOrganizationMatch:i=!1,managementApiExtensions:o=[],entityHooks:r,getChildTenantIds:m,getAdapters:d,...c}=n,p=s!==!1,l=p?{resourceServers:s.resourceServers??!0,roles:s.roles??!0,connections:s.connections??!0}:{resourceServers:!1,roles:!1,connections:!1},g={controlPlaneTenantId:t,getChildTenantIds:m??(async()=>(await P.fetchAll(v=>e.tenants.list(v),"tenants",{cursorField:"id",pageSize:100})).filter(v=>v.id!==t).map(v=>v.id)),getAdapters:d??(async()=>e),getControlPlaneAdapters:async()=>e,sync:l},{entityHooks:f,tenantHooks:h}=V(g),y={resourceServers:[f.resourceServers,...(r==null?void 0:r.resourceServers)??[]],roles:[f.roles,...(r==null?void 0:r.roles)??[]],connections:[f.connections,...(r==null?void 0:r.connections)??[]],tenants:(r==null?void 0:r.tenants)??[],rolePermissions:(r==null?void 0:r.rolePermissions)??[]},_=R({accessControl:{controlPlaneTenantId:t,requireOrganizationMatch:i,defaultPermissions:a}},{tenants:h}),{app:b}=P.init({dataAdapter:e,...c,entityHooks:y,managementApiExtensions:[...o,{path:"/tenants",router:_}]});return p&&b.use("/api/v2/*",W()),{app:b,controlPlaneTenantId:t}}function pe(n){const e=$(n);return{name:"multi-tenancy",middleware:j(n),hooks:e,routes:[{path:"/management",handler:R(n,e)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),n.accessControl&&console.log(` - Access control enabled (control plane: ${n.accessControl.controlPlaneTenantId})`),n.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${n.subdomainRouting.baseDomain})`),n.databaseIsolation&&console.log(" - Database isolation enabled")}}}function $(n){const e=n.accessControl?U(n.accessControl):{},t=n.databaseIsolation?K(n.databaseIsolation):{},s=L(n);return{...e,...t,tenants:s}}function Z(n){const e=new ne.Hono,t=$(n);return e.route("/tenants",R(n,t)),e}function fe(n){return{hooks:$(n),middleware:j(n),app:Z(n),config:n}}exports.createAccessControlHooks=U;exports.createAccessControlMiddleware=J;exports.createDatabaseHooks=K;exports.createDatabaseMiddleware=Y;exports.createMultiTenancy=Z;exports.createMultiTenancyHooks=$;exports.createMultiTenancyMiddleware=j;exports.createMultiTenancyPlugin=pe;exports.createProtectSyncedMiddleware=W;exports.createProvisioningHooks=L;exports.createRuntimeFallbackAdapter=F;exports.createSettingsInheritanceAdapter=de;exports.createSubdomainMiddleware=X;exports.createSyncHooks=V;exports.createTenantsOpenAPIRouter=R;exports.initMultiTenant=me;exports.setupMultiTenancy=fe;exports.validateTenantAccess=B;exports.withRuntimeFallback=Q;exports.withSettingsInheritance=ue;
|
|
1
|
+
"use strict";var ee=Object.defineProperty;var te=(n,e,t)=>e in n?ee(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var k=(n,e,t)=>te(n,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ne=require("hono"),P=require("authhero"),C=require("@hono/zod-openapi"),I=require("@authhero/adapter-interfaces");function U(n){const{controlPlaneTenantId:e,requireOrganizationMatch:t=!0}=n;return{async onTenantAccessValidation(s,a){if(a===e)return!0;if(t){const i=s.var.org_name,o=s.var.organization_id,r=i||o;return r?r.toLowerCase()===a.toLowerCase():!1}return!0}}}function L(n,e,t,s){if(e===t)return!0;const a=s||n;return a?a.toLowerCase()===e.toLowerCase():!1}function B(n){return{async resolveDataAdapters(e){try{return await n.getAdapters(e)}catch(t){console.error(`Failed to resolve data adapters for tenant ${e}:`,t);return}}}}function K(n){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:P.getTenantAudience(t.id)}:t},async afterCreate(e,t){const{accessControl:s,databaseIsolation:a}=n;s&&e.ctx&&await se(e,t,s),a!=null&&a.onProvision&&await a.onProvision(t.id)},async beforeDelete(e,t){const{accessControl:s,databaseIsolation:a}=n;if(s)try{const o=(await e.adapters.organizations.list(s.controlPlaneTenantId)).organizations.find(r=>r.name===t);o&&await e.adapters.organizations.remove(s.controlPlaneTenantId,o.id)}catch(i){console.warn(`Failed to remove organization for tenant ${t}:`,i)}if(a!=null&&a.onDeprovision)try{await a.onDeprovision(t)}catch(i){console.warn(`Failed to deprovision database for tenant ${t}:`,i)}}}}async function se(n,e,t){const{controlPlaneTenantId:s,defaultPermissions:a,defaultRoles:i,issuer:o,adminRoleName:r="Tenant Admin",adminRoleDescription:m="Full access to all tenant management operations",addCreatorToOrganization:d=!0}=t,c=await n.adapters.organizations.create(s,{name:e.id,display_name:e.friendly_name||e.id});let p;if(o&&(p=await re(n,s,r,m)),d&&n.ctx){const l=n.ctx.var.user;if(l!=null&&l.sub&&!await ae(n,s,l.sub))try{await n.adapters.userOrganizations.create(s,{user_id:l.sub,organization_id:c.id}),p&&await n.adapters.userRoles.create(s,l.sub,p,c.id)}catch(w){console.warn(`Failed to add creator ${l.sub} to organization ${c.id}:`,w)}}i&&i.length>0&&console.log(`Would assign roles ${i.join(", ")} to organization ${c.id}`),a&&a.length>0&&console.log(`Would grant permissions ${a.join(", ")} to organization ${c.id}`)}async function ae(n,e,t){const s=await n.adapters.userRoles.list(e,t,void 0,"");for(const a of s)if((await n.adapters.rolePermissions.list(e,a.id,{per_page:1e3})).some(r=>r.permission_name==="admin:organizations"))return!0;return!1}async function re(n,e,t,s){const i=(await n.adapters.roles.list(e,{})).roles.find(d=>d.name===t);if(i)return i.id;const o=await n.adapters.roles.create(e,{name:t,description:s}),r=P.MANAGEMENT_API_AUDIENCE,m=P.MANAGEMENT_API_SCOPES.map(d=>({role_id:o.id,resource_server_identifier:r,permission_name:d.value}));return await n.adapters.rolePermissions.assign(e,o.id,m),o.id}const oe=["client_id","client_secret","app_secret","kid","team_id","twilio_sid","twilio_token"];function q(n,e,t=()=>!0){const{controlPlaneTenantId:s,getChildTenantIds:a,getAdapters:i}=n,o=new Map;async function r(c,p,l){return(await e(c).list(p,{q:`name:${l}`,per_page:1}))[0]??null}async function m(c){const p=await a(),l=e(await i(s));await Promise.all(p.map(async u=>{try{const w=await i(u),g=e(w),h={...l.transform(c),is_system:!0},y=await r(w,u,c.name),_=y?g.getId(y):void 0;if(y&&_){const b=g.preserveOnUpdate?g.preserveOnUpdate(y,h):h;await g.update(u,_,b)}else await g.create(u,h)}catch(w){console.error(`Failed to sync ${l.listKey} "${c.name}" to tenant "${u}":`,w)}}))}async function d(c){const p=await a();await Promise.all(p.map(async l=>{try{const u=await i(l),w=e(u),g=await r(u,l,c),f=g?w.getId(g):void 0;g&&f&&await w.remove(l,f)}catch(u){console.error(`Failed to delete entity "${c}" from tenant "${l}":`,u)}}))}return{afterCreate:async(c,p)=>{c.tenantId===s&&t(p)&&await m(p)},afterUpdate:async(c,p,l)=>{c.tenantId===s&&t(l)&&await m(l)},beforeDelete:async(c,p)=>{if(c.tenantId!==s)return;const u=await e(c.adapters).get(c.tenantId,p);u&&t(u)&&o.set(p,u)},afterDelete:async(c,p)=>{if(c.tenantId!==s)return;const l=o.get(p);l&&(o.delete(p),await d(l.name))}}}function D(n,e,t=()=>!0){const{controlPlaneTenantId:s,getControlPlaneAdapters:a,getAdapters:i}=n;return{async afterCreate(o,r){if(r.id!==s)try{const m=await a(),d=await i(r.id),c=e(m),p=e(d),l=await P.fetchAll(u=>c.listPaginated(s,u),c.listKey,{cursorField:"id",pageSize:100});await Promise.all(l.filter(u=>t(u)).map(async u=>{try{const w=c.transform(u);await p.create(r.id,{...w,is_system:!0})}catch(w){console.error(`Failed to sync entity to new tenant "${r.id}":`,w)}}))}catch(m){console.error(`Failed to sync entities to new tenant "${r.id}":`,m)}}}}const N=n=>({list:async(e,t)=>(await n.resourceServers.list(e,t)).resource_servers,listPaginated:(e,t)=>n.resourceServers.list(e,t),get:(e,t)=>n.resourceServers.get(e,t),create:(e,t)=>n.resourceServers.create(e,t),update:(e,t,s)=>n.resourceServers.update(e,t,s),remove:(e,t)=>n.resourceServers.remove(e,t),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})}),H=n=>({list:async(e,t)=>(await n.roles.list(e,t)).roles,listPaginated:(e,t)=>n.roles.list(e,t),get:(e,t)=>n.roles.get(e,t),create:(e,t)=>n.roles.create(e,t),update:(e,t,s)=>n.roles.update(e,t,s),remove:(e,t)=>n.roles.remove(e,t),listKey:"roles",getId:e=>e.id,transform:e=>({id:e.id,name:e.name,description:e.description})}),G=n=>({list:async(e,t)=>(await n.connections.list(e,t)).connections,listPaginated:(e,t)=>n.connections.list(e,t),get:(e,t)=>n.connections.get(e,t),create:(e,t)=>n.connections.create(e,t),update:(e,t,s)=>n.connections.update(e,t,s),remove:(e,t)=>n.connections.remove(e,t),listKey:"connections",getId:e=>e.id,transform:e=>{const t=e.options?{...e.options}:{};for(const s of oe)delete t[s];return{id:e.id,name:e.name,display_name:e.display_name,strategy:e.strategy,options:t,response_type:e.response_type,response_mode:e.response_mode,is_domain_connection:e.is_domain_connection,show_as_button:e.show_as_button,metadata:e.metadata}},preserveOnUpdate:(e,t)=>{const s=e.options||{};return{...t,options:{...t.options,client_id:s.client_id,client_secret:s.client_secret,app_secret:s.app_secret,kid:s.kid,team_id:s.team_id,twilio_sid:s.twilio_sid,twilio_token:s.twilio_token}}}});function V(n){const{sync:e={},filters:t={}}=n,s=e.resourceServers??!0,a=e.roles??!0,i=e.connections??!0,o=s?q(n,N,t.resourceServers):void 0,r=a?q(n,H,t.roles):void 0,m=i?q(n,G,t.connections):void 0,d=s?D(n,N,t.resourceServers):void 0,c=a?D(n,H,t.roles):void 0,p=i?D(n,G,t.connections):void 0,l=a?{async afterCreate(g,f){var h;if(f.id!==n.controlPlaneTenantId){await((h=c==null?void 0:c.afterCreate)==null?void 0:h.call(c,g,f));try{const y=await n.getControlPlaneAdapters(),_=await n.getAdapters(f.id),b=await P.fetchAll(v=>y.roles.list(n.controlPlaneTenantId,v),"roles",{cursorField:"id",pageSize:100}),z=new Map;for(const v of b.filter(T=>{var A;return((A=t.roles)==null?void 0:A.call(t,T))??!0})){const T=await u(_,f.id,v.name);T&&z.set(v.name,T.id)}for(const v of b.filter(T=>{var A;return((A=t.roles)==null?void 0:A.call(t,T))??!0})){const T=z.get(v.name);if(T)try{const A=await y.rolePermissions.list(n.controlPlaneTenantId,v.id,{});A.length>0&&await _.rolePermissions.assign(f.id,T,A.map(M=>({role_id:T,resource_server_identifier:M.resource_server_identifier,permission_name:M.permission_name})))}catch(A){console.error(`Failed to sync permissions for role "${v.name}" to tenant "${f.id}":`,A)}}}catch(y){console.error(`Failed to sync role permissions to tenant "${f.id}":`,y)}}}}:void 0;async function u(g,f,h){return(await g.roles.list(f,{q:`name:${h}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:o,roles:r,connections:m},tenantHooks:{async afterCreate(g,f){const h=[d==null?void 0:d.afterCreate,(l==null?void 0:l.afterCreate)??(c==null?void 0:c.afterCreate),p==null?void 0:p.afterCreate],y=[];for(const _ of h)if(_)try{await _(g,f)}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,y.map(_=>_.message).join("; "))}}}}var S=class extends Error{constructor(e=500,t){super(t==null?void 0:t.message,{cause:t==null?void 0:t.cause});k(this,"res");k(this,"status");this.res=t==null?void 0:t.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 R(n,e){const t=new C.OpenAPIHono;return t.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 s=>{var u,w,g,f;const a=s.req.valid("query"),{page:i,per_page:o,include_totals:r,q:m}=a,d=s.var.user,c=(d==null?void 0:d.permissions)||[];if(c.includes("auth:read")||c.includes("admin:organizations")){const h=await s.env.data.tenants.list({page:i,per_page:o,include_totals:r,q:m});return r?s.json({tenants:h.tenants,start:((u=h.totals)==null?void 0:u.start)??0,limit:((w=h.totals)==null?void 0:w.limit)??o,length:h.tenants.length}):s.json({tenants:h.tenants})}if(n.accessControl&&(d!=null&&d.sub)){const h=n.accessControl.controlPlaneTenantId,_=(await P.fetchAll(O=>s.env.data.userOrganizations.listUserOrganizations(h,d.sub,O),"organizations")).map(O=>O.name);if(_.length===0)return r?s.json({tenants:[],start:0,limit:o??50,length:0}):s.json({tenants:[]});const b=_.length,z=i??0,v=o??50,T=z*v,A=_.slice(T,T+v);if(A.length===0)return r?s.json({tenants:[],start:T,limit:v,length:b}):s.json({tenants:[]});const M=A.map(O=>`id:${O}`).join(" OR "),x=m?`(${M}) AND (${m})`:M,E=await s.env.data.tenants.list({q:x,per_page:v,include_totals:!1});return r?s.json({tenants:E.tenants,start:T,limit:v,length:b}):s.json({tenants:E.tenants})}const l=await s.env.data.tenants.list({page:i,per_page:o,include_totals:r,q:m});return r?s.json({tenants:l.tenants,start:((g=l.totals)==null?void 0:g.start)??0,limit:((f=l.totals)==null?void 0:f.limit)??o,length:l.tenants.length}):s.json({tenants:l.tenants})}),t.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 s=>{var m,d;const a=s.var.user;if(!(a!=null&&a.sub))throw new S(401,{message:"Authentication required to create tenants"});let i=s.req.valid("json");const o={adapters:s.env.data,ctx:s};(m=e.tenants)!=null&&m.beforeCreate&&(i=await e.tenants.beforeCreate(o,i));const r=await s.env.data.tenants.create(i);return(d=e.tenants)!=null&&d.afterCreate&&await e.tenants.afterCreate(o,r),s.json(r,201)}),t.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 s=>{var r,m;const{id:a}=s.req.valid("param");if(n.accessControl){const d=s.var.user,c=n.accessControl.controlPlaneTenantId;if(!(d!=null&&d.sub))throw new S(401,{message:"Authentication required"});if(a===c)throw new S(403,{message:"Cannot delete the control plane"});if(!(await P.fetchAll(u=>s.env.data.userOrganizations.listUserOrganizations(c,d.sub,u),"organizations")).some(u=>u.name===a))throw new S(403,{message:"Access denied to this tenant"})}if(!await s.env.data.tenants.get(a))throw new S(404,{message:"Tenant not found"});const o={adapters:s.env.data,ctx:s};return(r=e.tenants)!=null&&r.beforeDelete&&await e.tenants.beforeDelete(o,a),await s.env.data.tenants.remove(a),(m=e.tenants)!=null&&m.afterDelete&&await e.tenants.afterDelete(o,a),s.body(null,204)}),t}function ie(n){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:t,type:s}of e){const a=n.match(t);if(a&&a[1])return{type:s,id:a[1]}}return null}async function ce(n,e,t){try{switch(t.type){case"resource_server":{const s=await n.resourceServers.get(e,t.id);return(s==null?void 0:s.is_system)===!0}case"role":{const s=await n.roles.get(e,t.id);return(s==null?void 0:s.is_system)===!0}case"connection":{const s=await n.connections.get(e,t.id);return(s==null?void 0:s.is_system)===!0}default:return!1}}catch{return!1}}function le(n){return{resource_server:"resource server",role:"role",connection:"connection"}[n]}function W(){return async(n,e)=>{if(!["PATCH","PUT","DELETE"].includes(n.req.method))return e();const t=ie(n.req.path);if(!t)return e();const s=n.var.tenant_id||n.req.header("x-tenant-id")||n.req.header("tenant-id");if(!s)return e();if(await ce(n.env.data,s,t))throw new S(403,{message:`This ${le(t.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return e()}}function F(n,e){const{controlPlaneTenantId:t,controlPlaneClientId:s}=e;return{...n,legacyClients:{...n.legacyClients,get:async a=>{var p;const i=await n.legacyClients.get(a);if(!i)return null;const o=s?await n.legacyClients.get(s):void 0,r=await n.connections.list(i.tenant.id),m=t?await n.connections.list(t):{connections:[]},d=r.connections.map(l=>{var g;const u=(g=m.connections)==null?void 0:g.find(f=>f.name===l.name);if(!(u!=null&&u.options))return l;const w=I.connectionSchema.parse({...u||{},...l});return w.options=I.connectionOptionsSchema.parse({...u.options||{},...l.options}),w}).filter(l=>l),c={...(o==null?void 0:o.tenant)||{},...i.tenant};return!i.tenant.audience&&((p=o==null?void 0:o.tenant)!=null&&p.audience)&&(c.audience=o.tenant.audience),{...i,web_origins:[...(o==null?void 0:o.web_origins)||[],...i.web_origins||[]],allowed_logout_urls:[...(o==null?void 0:o.allowed_logout_urls)||[],...i.allowed_logout_urls||[]],callbacks:[...(o==null?void 0:o.callbacks)||[],...i.callbacks||[]],connections:d,tenant:c}}},connections:{...n.connections,get:async(a,i)=>{const o=await n.connections.get(a,i);if(!o||!t)return o;const r=await n.connections.get(t,i);if(!r)return o;const m=I.connectionSchema.parse({...r,...o});return m.options=I.connectionOptionsSchema.parse({...r.options||{},...o.options}),m},list:async(a,i)=>{const o=await n.connections.list(a,i);if(!t||a===t)return o;const r=await n.connections.list(t),m=o.connections.map(d=>{var l;const c=(l=r.connections)==null?void 0:l.find(u=>u.name===d.name);if(!(c!=null&&c.options))return d;const p=I.connectionSchema.parse({...c,...d});return p.options=I.connectionOptionsSchema.parse({...c.options||{},...d.options}),p});return{...o,connections:m}}}}}function Q(n,e){return F(n,e)}const de=F,ue=Q;function J(n){return async(e,t)=>{if(!n.accessControl)return t();const s=e.var.tenant_id,a=e.var.organization_id;if(!s)throw new S(400,{message:"Tenant ID not found in request"});if(!L(a,s,n.accessControl.controlPlaneTenantId))throw new S(403,{message:`Access denied to tenant ${s}`});return t()}}function X(n){return async(e,t)=>{if(!n.subdomainRouting)return t();const{baseDomain:s,reservedSubdomains:a=[],resolveSubdomain:i}=n.subdomainRouting,o=e.req.header("host")||"";let r=null;if(o.endsWith(s)){const d=o.slice(0,-(s.length+1));d&&!d.includes(".")&&(r=d)}if(r&&a.includes(r)&&(r=null),!r)return n.accessControl&&e.set("tenant_id",n.accessControl.controlPlaneTenantId),t();let m=null;if(i)m=await i(r);else if(n.subdomainRouting.useOrganizations!==!1&&n.accessControl)try{const d=await e.env.data.organizations.get(n.accessControl.controlPlaneTenantId,r);d&&(m=d.id)}catch{}if(!m)throw new S(404,{message:`Tenant not found for subdomain: ${r}`});return e.set("tenant_id",m),t()}}function Y(n){return async(e,t)=>{if(!n.databaseIsolation)return t();const s=e.var.tenant_id;if(!s)throw new S(400,{message:"Tenant ID not found in request"});try{const a=await n.databaseIsolation.getAdapters(s);e.env.data=a}catch(a){throw console.error(`Failed to resolve database for tenant ${s}:`,a),new S(500,{message:"Failed to resolve tenant database"})}return t()}}function j(n){const e=X(n),t=J(n),s=Y(n);return async(a,i)=>(await e(a,async()=>{}),await t(a,async()=>{}),await s(a,async()=>{}),i())}function me(n){const{dataAdapter:e,controlPlaneTenantId:t="control_plane",sync:s={resourceServers:!0,roles:!0,connections:!0},defaultPermissions:a=["tenant:admin"],requireOrganizationMatch:i=!1,managementApiExtensions:o=[],entityHooks:r,getChildTenantIds:m,getAdapters:d,...c}=n,p=s!==!1,l=p?{resourceServers:s.resourceServers??!0,roles:s.roles??!0,connections:s.connections??!0}:{resourceServers:!1,roles:!1,connections:!1},g={controlPlaneTenantId:t,getChildTenantIds:m??(async()=>(await P.fetchAll(v=>e.tenants.list(v),"tenants",{cursorField:"id",pageSize:100})).filter(v=>v.id!==t).map(v=>v.id)),getAdapters:d??(async()=>e),getControlPlaneAdapters:async()=>e,sync:l},{entityHooks:f,tenantHooks:h}=V(g),y={resourceServers:[f.resourceServers,...(r==null?void 0:r.resourceServers)??[]],roles:[f.roles,...(r==null?void 0:r.roles)??[]],connections:[f.connections,...(r==null?void 0:r.connections)??[]],tenants:(r==null?void 0:r.tenants)??[],rolePermissions:(r==null?void 0:r.rolePermissions)??[]},_=R({accessControl:{controlPlaneTenantId:t,requireOrganizationMatch:i,defaultPermissions:a}},{tenants:h}),{app:b}=P.init({dataAdapter:e,...c,entityHooks:y,managementApiExtensions:[...o,{path:"/tenants",router:_}]});return p&&b.use("/api/v2/*",W()),{app:b,controlPlaneTenantId:t}}function pe(n){const e=$(n);return{name:"multi-tenancy",middleware:j(n),hooks:e,routes:[{path:"/management",handler:R(n,e)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),n.accessControl&&console.log(` - Access control enabled (control plane: ${n.accessControl.controlPlaneTenantId})`),n.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${n.subdomainRouting.baseDomain})`),n.databaseIsolation&&console.log(" - Database isolation enabled")}}}function $(n){const e=n.accessControl?U(n.accessControl):{},t=n.databaseIsolation?B(n.databaseIsolation):{},s=K(n);return{...e,...t,tenants:s}}function Z(n){const e=new ne.Hono,t=$(n);return e.route("/tenants",R(n,t)),e}function fe(n){return{hooks:$(n),middleware:j(n),app:Z(n),config:n}}exports.createAccessControlHooks=U;exports.createAccessControlMiddleware=J;exports.createDatabaseHooks=B;exports.createDatabaseMiddleware=Y;exports.createMultiTenancy=Z;exports.createMultiTenancyHooks=$;exports.createMultiTenancyMiddleware=j;exports.createMultiTenancyPlugin=pe;exports.createProtectSyncedMiddleware=W;exports.createProvisioningHooks=K;exports.createRuntimeFallbackAdapter=F;exports.createSettingsInheritanceAdapter=de;exports.createSubdomainMiddleware=X;exports.createSyncHooks=V;exports.createTenantsOpenAPIRouter=R;exports.initMultiTenant=me;exports.setupMultiTenancy=fe;exports.validateTenantAccess=L;exports.withRuntimeFallback=Q;exports.withSettingsInheritance=ue;
|
package/dist/multi-tenancy.d.ts
CHANGED
|
@@ -14117,9 +14117,9 @@ declare const organizationInsertSchema: z.ZodObject<{
|
|
|
14117
14117
|
export type OrganizationInsert = z.infer<typeof organizationInsertSchema>;
|
|
14118
14118
|
declare const organizationSchema: z.ZodObject<{
|
|
14119
14119
|
id: z.ZodString;
|
|
14120
|
+
name: z.ZodString;
|
|
14120
14121
|
created_at: z.ZodString;
|
|
14121
14122
|
updated_at: z.ZodString;
|
|
14122
|
-
name: z.ZodString;
|
|
14123
14123
|
display_name: z.ZodOptional<z.ZodString>;
|
|
14124
14124
|
branding: z.ZodOptional<z.ZodObject<{
|
|
14125
14125
|
logo_url: z.ZodOptional<z.ZodString>;
|
|
@@ -29073,9 +29073,9 @@ declare const organizationInsertSchema$1: z.ZodObject<{
|
|
|
29073
29073
|
type OrganizationInsert$1 = z.infer<typeof organizationInsertSchema$1>;
|
|
29074
29074
|
declare const organizationSchema$1: z.ZodObject<{
|
|
29075
29075
|
id: z.ZodString;
|
|
29076
|
+
name: z.ZodString;
|
|
29076
29077
|
created_at: z.ZodString;
|
|
29077
29078
|
updated_at: z.ZodString;
|
|
29078
|
-
name: z.ZodString;
|
|
29079
29079
|
display_name: z.ZodOptional<z.ZodString>;
|
|
29080
29080
|
branding: z.ZodOptional<z.ZodObject<{
|
|
29081
29081
|
logo_url: z.ZodOptional<z.ZodString>;
|
package/dist/multi-tenancy.mjs
CHANGED
|
@@ -13,7 +13,7 @@ function ne(n) {
|
|
|
13
13
|
return !0;
|
|
14
14
|
if (t) {
|
|
15
15
|
const i = s.var.org_name, o = s.var.organization_id, a = i || o;
|
|
16
|
-
return a ? a === r : !1;
|
|
16
|
+
return a ? a.toLowerCase() === r.toLowerCase() : !1;
|
|
17
17
|
}
|
|
18
18
|
return !0;
|
|
19
19
|
}
|
|
@@ -23,7 +23,7 @@ function se(n, e, t, s) {
|
|
|
23
23
|
if (e === t)
|
|
24
24
|
return !0;
|
|
25
25
|
const r = s || n;
|
|
26
|
-
return r ? r === e : !1;
|
|
26
|
+
return r ? r.toLowerCase() === e.toLowerCase() : !1;
|
|
27
27
|
}
|
|
28
28
|
function re(n) {
|
|
29
29
|
return {
|
|
@@ -582,8 +582,8 @@ function k(n, e) {
|
|
|
582
582
|
limit: _,
|
|
583
583
|
length: b
|
|
584
584
|
}) : s.json({ tenants: [] });
|
|
585
|
-
const P = A.map((z) => `id:${z}`).join(" OR "),
|
|
586
|
-
q:
|
|
585
|
+
const P = A.map((z) => `id:${z}`).join(" OR "), K = m ? `(${P}) AND (${m})` : P, E = await s.env.data.tenants.list({
|
|
586
|
+
q: K,
|
|
587
587
|
per_page: _,
|
|
588
588
|
include_totals: !1
|
|
589
589
|
// We calculate totals from accessibleTenantIds
|
|
@@ -786,7 +786,7 @@ function fe() {
|
|
|
786
786
|
return e();
|
|
787
787
|
};
|
|
788
788
|
}
|
|
789
|
-
function
|
|
789
|
+
function L(n, e) {
|
|
790
790
|
const { controlPlaneTenantId: t, controlPlaneClientId: s } = e;
|
|
791
791
|
return {
|
|
792
792
|
...n,
|
|
@@ -897,9 +897,9 @@ function B(n, e) {
|
|
|
897
897
|
};
|
|
898
898
|
}
|
|
899
899
|
function ge(n, e) {
|
|
900
|
-
return
|
|
900
|
+
return L(n, e);
|
|
901
901
|
}
|
|
902
|
-
const Ie =
|
|
902
|
+
const Ie = L, Se = ge;
|
|
903
903
|
function we(n) {
|
|
904
904
|
return async (e, t) => {
|
|
905
905
|
if (!n.accessControl)
|
|
@@ -978,7 +978,7 @@ function ye(n) {
|
|
|
978
978
|
return t();
|
|
979
979
|
};
|
|
980
980
|
}
|
|
981
|
-
function
|
|
981
|
+
function B(n) {
|
|
982
982
|
const e = he(n), t = we(n), s = ye(n);
|
|
983
983
|
return async (r, i) => (await e(r, async () => {
|
|
984
984
|
}), await t(r, async () => {
|
|
@@ -1048,7 +1048,7 @@ function ze(n) {
|
|
|
1048
1048
|
return {
|
|
1049
1049
|
name: "multi-tenancy",
|
|
1050
1050
|
// Apply multi-tenancy middleware for subdomain routing, database resolution, etc.
|
|
1051
|
-
middleware:
|
|
1051
|
+
middleware: B(n),
|
|
1052
1052
|
// Provide lifecycle hooks
|
|
1053
1053
|
hooks: e,
|
|
1054
1054
|
// Mount tenant management routes
|
|
@@ -1083,7 +1083,7 @@ function _e(n) {
|
|
|
1083
1083
|
function $e(n) {
|
|
1084
1084
|
return {
|
|
1085
1085
|
hooks: j(n),
|
|
1086
|
-
middleware:
|
|
1086
|
+
middleware: B(n),
|
|
1087
1087
|
app: _e(n),
|
|
1088
1088
|
config: n
|
|
1089
1089
|
};
|
|
@@ -1095,11 +1095,11 @@ export {
|
|
|
1095
1095
|
ye as createDatabaseMiddleware,
|
|
1096
1096
|
_e as createMultiTenancy,
|
|
1097
1097
|
j as createMultiTenancyHooks,
|
|
1098
|
-
|
|
1098
|
+
B as createMultiTenancyMiddleware,
|
|
1099
1099
|
ze as createMultiTenancyPlugin,
|
|
1100
1100
|
fe as createProtectSyncedMiddleware,
|
|
1101
1101
|
ae as createProvisioningHooks,
|
|
1102
|
-
|
|
1102
|
+
L as createRuntimeFallbackAdapter,
|
|
1103
1103
|
Ie as createSettingsInheritanceAdapter,
|
|
1104
1104
|
he as createSubdomainMiddleware,
|
|
1105
1105
|
de as createSyncHooks,
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/markusahlstrand/authhero"
|
|
13
13
|
},
|
|
14
|
-
"version": "13.
|
|
14
|
+
"version": "13.20.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"
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"typescript": "^5.6.0",
|
|
38
38
|
"vite": "^6.0.0",
|
|
39
39
|
"vitest": "^2.1.0",
|
|
40
|
-
"@authhero/kysely-adapter": "10.76.
|
|
41
|
-
"authhero": "3.
|
|
40
|
+
"@authhero/kysely-adapter": "10.76.2",
|
|
41
|
+
"authhero": "3.6.0"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"zod": "^3.24.0",
|
|
45
|
-
"@authhero/adapter-interfaces": "0.
|
|
45
|
+
"@authhero/adapter-interfaces": "0.118.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@hono/zod-openapi": "^0.19.10",
|