@authhero/multi-tenancy 14.1.0 → 14.3.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.
Files changed (38) hide show
  1. package/dist/multi-tenancy.cjs +1 -1
  2. package/dist/multi-tenancy.mjs +45 -39
  3. package/dist/types/hooks/access-control.d.ts +25 -0
  4. package/dist/types/hooks/access-control.d.ts.map +1 -0
  5. package/dist/types/hooks/database.d.ts +35 -0
  6. package/dist/types/hooks/database.d.ts.map +1 -0
  7. package/dist/types/hooks/index.d.ts +5 -0
  8. package/dist/types/hooks/index.d.ts.map +1 -0
  9. package/dist/types/hooks/provisioning.d.ts +15 -0
  10. package/dist/types/hooks/provisioning.d.ts.map +1 -0
  11. package/dist/types/hooks/resource-server-sync.d.ts +140 -0
  12. package/dist/types/hooks/resource-server-sync.d.ts.map +1 -0
  13. package/dist/types/hooks/role-sync.d.ts +145 -0
  14. package/dist/types/hooks/role-sync.d.ts.map +1 -0
  15. package/dist/types/hooks/sync.d.ts +79 -0
  16. package/dist/types/hooks/sync.d.ts.map +1 -0
  17. package/dist/types/index.d.ts +117 -0
  18. package/dist/types/index.d.ts.map +1 -0
  19. package/dist/types/init.d.ts +110 -0
  20. package/dist/types/init.d.ts.map +1 -0
  21. package/dist/types/middleware/index.d.ts +114 -0
  22. package/dist/types/middleware/index.d.ts.map +1 -0
  23. package/dist/types/middleware/protect-synced.d.ts +40 -0
  24. package/dist/types/middleware/protect-synced.d.ts.map +1 -0
  25. package/dist/types/middleware/settings-inheritance.d.ts +89 -0
  26. package/dist/types/middleware/settings-inheritance.d.ts.map +1 -0
  27. package/dist/types/plugin.d.ts +66 -0
  28. package/dist/types/plugin.d.ts.map +1 -0
  29. package/dist/types/routes/index.d.ts +2 -0
  30. package/dist/types/routes/index.d.ts.map +1 -0
  31. package/dist/types/routes/tenants.d.ts +18 -0
  32. package/dist/types/routes/tenants.d.ts.map +1 -0
  33. package/dist/types/types.d.ts +295 -0
  34. package/dist/types/types.d.ts.map +1 -0
  35. package/dist/types/utils/index.d.ts +3 -0
  36. package/dist/types/utils/index.d.ts.map +1 -0
  37. package/package.json +8 -8
  38. package/dist/multi-tenancy.d.ts +0 -41308
@@ -1 +1 @@
1
- "use strict";var x=Object.defineProperty;var ee=(t,e,n)=>e in t?x(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var $=(t,e,n)=>ee(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const te=require("hono"),I=require("authhero"),_=require("@hono/zod-openapi"),S=require("@authhero/adapter-interfaces");function G(t){const{controlPlaneTenantId:e,requireOrganizationMatch:n=!0}=t;return{async onTenantAccessValidation(a,r){if(r===e)return!0;if(n){const i=a.var.org_name,o=a.var.organization_id,s=i||o;return s?s.toLowerCase()===r.toLowerCase():!1}return!0}}}function U(t,e,n,a){if(e===n)return!0;const r=a||t;return r?r.toLowerCase()===e.toLowerCase():!1}function L(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 ne(t){return`urn:authhero:tenant:${t.toLowerCase()}`}function B(t){return{async beforeCreate(e,n){return!n.audience&&n.id?{...n,audience:ne(n.id)}:n},async afterCreate(e,n){const{accessControl:a,databaseIsolation:r}=t;a&&e.ctx&&await ae(e,n,a),r!=null&&r.onProvision&&await r.onProvision(n.id)},async beforeDelete(e,n){const{accessControl:a,databaseIsolation:r}=t;if(a)try{const o=(await e.adapters.organizations.list(a.controlPlaneTenantId)).organizations.find(s=>s.name===n);o&&await e.adapters.organizations.remove(a.controlPlaneTenantId,o.id)}catch(i){console.warn(`Failed to remove organization for tenant ${n}:`,i)}if(r!=null&&r.onDeprovision)try{await r.onDeprovision(n)}catch(i){console.warn(`Failed to deprovision database for tenant ${n}:`,i)}}}}async function ae(t,e,n){const{controlPlaneTenantId:a,defaultPermissions:r,defaultRoles:i,issuer:o,adminRoleName:s="Tenant Admin",adminRoleDescription:c="Full access to all tenant management operations",addCreatorToOrganization:m=!0}=n,l=await t.adapters.organizations.create(a,{name:e.id,display_name:e.friendly_name||e.id});let f;if(o&&(f=await re(t,a,s,c)),m&&t.ctx){const d=t.ctx.var.user;if(d!=null&&d.sub&&!await se(t,a,d.sub))try{await t.adapters.userOrganizations.create(a,{user_id:d.sub,organization_id:l.id}),f&&await t.adapters.userRoles.create(a,d.sub,f,l.id)}catch(p){console.warn(`Failed to add creator ${d.sub} to organization ${l.id}:`,p)}}i&&i.length>0&&console.log(`Would assign roles ${i.join(", ")} to organization ${l.id}`),r&&r.length>0&&console.log(`Would grant permissions ${r.join(", ")} to organization ${l.id}`)}async function se(t,e,n){const a=await t.adapters.userRoles.list(e,n,void 0,"");for(const r of a)if((await t.adapters.rolePermissions.list(e,r.id,{per_page:1e3})).some(s=>s.permission_name==="admin:organizations"))return!0;return!1}async function re(t,e,n,a){const i=(await t.adapters.roles.list(e,{})).roles.find(m=>m.name===n);if(i)return i.id;const o=await t.adapters.roles.create(e,{name:n,description:a}),s=I.MANAGEMENT_API_AUDIENCE,c=I.MANAGEMENT_API_SCOPES.map(m=>({role_id:o.id,resource_server_identifier:s,permission_name:m.value}));return await t.adapters.rolePermissions.assign(e,o.id,c),o.id}function j(t,e,n=()=>!0){const{controlPlaneTenantId:a,getChildTenantIds:r,getAdapters:i}=t,o=new Map;async function s(l,f,d){return(await e(l).list(f,{q:`name:${d}`,per_page:1}))[0]??null}async function c(l){const f=await r(),d=e(await i(a));await Promise.all(f.map(async u=>{try{const p=await i(u),g=e(p),w={...d.transform(l),is_system:!0},C=await s(p,u,l.name),v=C?g.getId(C):void 0;if(C&&v){const y=g.preserveOnUpdate?g.preserveOnUpdate(C,w):w;await g.update(u,v,y)}else await g.create(u,w)}catch(p){console.error(`Failed to sync ${d.listKey} "${l.name}" to tenant "${u}":`,p)}}))}async function m(l){const f=await r();await Promise.all(f.map(async d=>{try{const u=await i(d),p=e(u),g=await s(u,d,l),h=g?p.getId(g):void 0;g&&h&&await p.remove(d,h)}catch(u){console.error(`Failed to delete entity "${l}" from tenant "${d}":`,u)}}))}return{afterCreate:async(l,f)=>{l.tenantId===a&&n(f)&&await c(f)},afterUpdate:async(l,f,d)=>{l.tenantId===a&&n(d)&&await c(d)},beforeDelete:async(l,f)=>{if(l.tenantId!==a)return;const u=await e(l.adapters).get(l.tenantId,f);u&&n(u)&&o.set(f,u)},afterDelete:async(l,f)=>{if(l.tenantId!==a)return;const d=o.get(f);d&&(o.delete(f),await m(d.name))}}}function E(t,e,n=()=>!0){const{controlPlaneTenantId:a,getControlPlaneAdapters:r,getAdapters:i}=t;return{async afterCreate(o,s){if(s.id!==a)try{const c=await r(),m=await i(s.id),l=e(c),f=e(m),d=await I.fetchAll(u=>l.listPaginated(a,u),l.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(u=>n(u)).map(async u=>{try{const p=l.transform(u);await f.create(s.id,{...p,is_system:!0})}catch(p){console.error(`Failed to sync entity to new tenant "${s.id}":`,p)}}))}catch(c){console.error(`Failed to sync entities to new tenant "${s.id}":`,c)}}}}const N=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})}),H=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 K(t){const{sync:e={},filters:n={}}=t,a=e.resourceServers??!0,r=e.roles??!0,i=a?j(t,N,n.resourceServers):void 0,o=r?j(t,H,n.roles):void 0,s=a?E(t,N,n.resourceServers):void 0,c=r?E(t,H,n.roles):void 0,m=r?{async afterCreate(d,u){var p;if(u.id!==t.controlPlaneTenantId){await((p=c==null?void 0:c.afterCreate)==null?void 0:p.call(c,d,u));try{const g=await t.getControlPlaneAdapters(),h=await t.getAdapters(u.id),w=await I.fetchAll(v=>g.roles.list(t.controlPlaneTenantId,v),"roles",{cursorField:"id",pageSize:100}),C=new Map;for(const v of w.filter(y=>{var T;return((T=n.roles)==null?void 0:T.call(n,y))??!0})){const y=await l(h,u.id,v.name);y&&C.set(v.name,y.id)}for(const v of w.filter(y=>{var T;return((T=n.roles)==null?void 0:T.call(n,y))??!0})){const y=C.get(v.name);if(y)try{const T=await g.rolePermissions.list(t.controlPlaneTenantId,v.id,{});T.length>0&&await h.rolePermissions.assign(u.id,y,T.map(A=>({role_id:y,resource_server_identifier:A.resource_server_identifier,permission_name:A.permission_name})))}catch(T){console.error(`Failed to sync permissions for role "${v.name}" to tenant "${u.id}":`,T)}}}catch(g){console.error(`Failed to sync role permissions to tenant "${u.id}":`,g)}}}}:void 0;async function l(d,u,p){return(await d.roles.list(u,{q:`name:${p}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:i,roles:o},tenantHooks:{async afterCreate(d,u){const p=[s==null?void 0:s.afterCreate,(m==null?void 0:m.afterCreate)??(c==null?void 0:c.afterCreate)],g=[];for(const h of p)if(h)try{await h(d,u)}catch(w){g.push(w instanceof Error?w:new Error(String(w)))}if(g.length===1)throw g[0];if(g.length>1)throw new AggregateError(g,g.map(h=>h.message).join("; "))}}}}var b=class extends Error{constructor(e=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});$(this,"res");$(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 M(t,e){const n=new _.OpenAPIHono;return n.openapi(_.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:S.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:_.z.object({tenants:_.z.array(S.tenantSchema),start:_.z.number().optional(),limit:_.z.number().optional(),length:_.z.number().optional()})}},description:"List of tenants"}}}),async a=>{var u,p,g,h;const r=a.req.valid("query"),{page:i,per_page:o,include_totals:s,q:c}=r,m=a.var.user,l=(m==null?void 0:m.permissions)||[];if(l.includes("auth:read")||l.includes("admin:organizations")){const w=await a.env.data.tenants.list({page:i,per_page:o,include_totals:s,q:c});return s?a.json({tenants:w.tenants,start:((u=w.totals)==null?void 0:u.start)??0,limit:((p=w.totals)==null?void 0:p.limit)??o,length:w.tenants.length}):a.json({tenants:w.tenants})}if(t.accessControl&&(m!=null&&m.sub)){const w=t.accessControl.controlPlaneTenantId,v=(await I.fetchAll(P=>a.env.data.userOrganizations.listUserOrganizations(w,m.sub,P),"organizations")).map(P=>P.name);if(v.length===0)return s?a.json({tenants:[],start:0,limit:o??50,length:0}):a.json({tenants:[]});const y=v.length,T=i??0,A=o??50,z=T*A,D=v.slice(z,z+A);if(D.length===0)return s?a.json({tenants:[],start:z,limit:A,length:y}):a.json({tenants:[]});const F=D.map(P=>`id:${P}`).join(" OR "),Z=c?`(${F}) AND (${c})`:F,k=await a.env.data.tenants.list({q:Z,per_page:A,include_totals:!1});return s?a.json({tenants:k.tenants,start:z,limit:A,length:y}):a.json({tenants:k.tenants})}const d=await a.env.data.tenants.list({page:i,per_page:o,include_totals:s,q:c});return s?a.json({tenants:d.tenants,start:((g=d.totals)==null?void 0:g.start)??0,limit:((h=d.totals)==null?void 0:h.limit)??o,length:d.tenants.length}):a.json({tenants:d.tenants})}),n.openapi(_.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:S.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:S.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async a=>{var c,m;const r=a.var.user;if(!(r!=null&&r.sub))throw new b(401,{message:"Authentication required to create tenants"});let i=a.req.valid("json");const o={adapters:a.env.data,ctx:a};(c=e.tenants)!=null&&c.beforeCreate&&(i=await e.tenants.beforeCreate(o,i));const s=await a.env.data.tenants.create(i);return(m=e.tenants)!=null&&m.afterCreate&&await e.tenants.afterCreate(o,s),a.json(s,201)}),n.openapi(_.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:_.z.object({id:_.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 s,c;const{id:r}=a.req.valid("param");if(t.accessControl){const m=a.var.user,l=t.accessControl.controlPlaneTenantId;if(!(m!=null&&m.sub))throw new b(401,{message:"Authentication required"});if(r===l)throw new b(403,{message:"Cannot delete the control plane"});if(!(await I.fetchAll(u=>a.env.data.userOrganizations.listUserOrganizations(l,m.sub,u),"organizations")).some(u=>u.name===r))throw new b(403,{message:"Access denied to this tenant"})}if(!await a.env.data.tenants.get(r))throw new b(404,{message:"Tenant not found"});const o={adapters:a.env.data,ctx:a};return(s=e.tenants)!=null&&s.beforeDelete&&await e.tenants.beforeDelete(o,r),await a.env.data.tenants.remove(r),(c=e.tenants)!=null&&c.afterDelete&&await e.tenants.afterDelete(o,r),a.body(null,204)}),n}function oe(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 r=t.match(n);if(r&&r[1])return{type:a,id:r[1]}}return null}async function ie(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 ce(t){return{resource_server:"resource server",role:"role",connection:"connection"}[t]}function W(){return async(t,e)=>{if(!["PATCH","PUT","DELETE"].includes(t.req.method))return e();const n=oe(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 ie(t.env.data,a,n))throw new b(403,{message:`This ${ce(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return e()}}function O(t,e){const{controlPlaneTenantId:n,controlPlaneClientId:a}=e;return{...t,legacyClients:{...t.legacyClients,get:async r=>{var f;const i=await t.legacyClients.get(r);if(!i)return null;const o=a?await t.legacyClients.get(a):void 0,s=await t.connections.list(i.tenant.id),c=n?await t.connections.list(n):{connections:[]},m=s.connections.map(d=>{var g;const u=(g=c.connections)==null?void 0:g.find(h=>h.strategy===d.strategy);if(!(u!=null&&u.options))return d;const p=S.connectionSchema.parse({...u||{},...d});return p.options=S.connectionOptionsSchema.parse({...u.options||{},...d.options}),p}).filter(d=>d),l={...(o==null?void 0:o.tenant)||{},...i.tenant};return!i.tenant.audience&&((f=o==null?void 0:o.tenant)!=null&&f.audience)&&(l.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:m,tenant:l}}},connections:{...t.connections,get:async(r,i)=>{var l;const o=await t.connections.get(r,i);if(!o||!n||r===n)return o;const c=(l=(await t.connections.list(n)).connections)==null?void 0:l.find(f=>f.strategy===o.strategy);if(!(c!=null&&c.options))return o;const m=S.connectionSchema.parse({...c,...o});return m.options=S.connectionOptionsSchema.parse({...c.options||{},...o.options}),m},list:async(r,i)=>{const o=await t.connections.list(r,i);if(!n||r===n)return o;const s=await t.connections.list(n),c=o.connections.map(m=>{var d;const l=(d=s.connections)==null?void 0:d.find(u=>u.strategy===m.strategy);if(!(l!=null&&l.options))return m;const f=S.connectionSchema.parse({...l,...m});return f.options=S.connectionOptionsSchema.parse({...l.options||{},...m.options}),f});return{...o,connections:c}}}}}function Q(t,e){return O(t,e)}const le=O,de=Q;function V(t){return async(e,n)=>{if(!t.accessControl)return n();const{controlPlaneTenantId:a}=t.accessControl,r=e.var.org_name,i=e.var.organization_id,o=r||i;let s=e.var.tenant_id;const c=e.var.user,l=(c!=null&&c.aud?Array.isArray(c.aud)?c.aud:[c.aud]:[]).includes(I.MANAGEMENT_API_AUDIENCE);if(!s&&o&&l&&(e.set("tenant_id",o),s=o),!s)throw new b(400,{message:"Tenant ID not found in request"});if(!U(i,s,a,r))throw new b(403,{message:`Access denied to tenant ${s}`});return n()}}function J(t){return async(e,n)=>{if(!t.subdomainRouting)return n();const{baseDomain:a,reservedSubdomains:r=[],resolveSubdomain:i}=t.subdomainRouting,o=e.req.header("host")||"";let s=null;if(o.endsWith(a)){const m=o.slice(0,-(a.length+1));m&&!m.includes(".")&&(s=m)}if(s&&r.includes(s)&&(s=null),!s)return t.accessControl&&e.set("tenant_id",t.accessControl.controlPlaneTenantId),n();let c=null;if(i)c=await i(s);else if(t.subdomainRouting.useOrganizations!==!1&&t.accessControl)try{const m=await e.env.data.organizations.get(t.accessControl.controlPlaneTenantId,s);m&&(c=m.id)}catch{}if(!c)throw new b(404,{message:`Tenant not found for subdomain: ${s}`});return e.set("tenant_id",c),n()}}function X(t){return async(e,n)=>{if(!t.databaseIsolation)return n();const a=e.var.tenant_id;if(!a)throw new b(400,{message:"Tenant ID not found in request"});try{const r=await t.databaseIsolation.getAdapters(a);e.env.data=r}catch(r){throw console.error(`Failed to resolve database for tenant ${a}:`,r),new b(500,{message:"Failed to resolve tenant database"})}return n()}}function q(t){const e=J(t),n=V(t),a=X(t);return async(r,i)=>(await e(r,async()=>{}),await n(r,async()=>{}),await a(r,async()=>{}),i())}function ue(t){const{dataAdapter:e,controlPlaneTenantId:n="control_plane",sync:a={resourceServers:!0,roles:!0},defaultPermissions:r=["tenant:admin"],requireOrganizationMatch:i=!1,managementApiExtensions:o=[],entityHooks:s,getChildTenantIds:c,getAdapters:m,...l}=t,f=a!==!1,d=f?{resourceServers:a.resourceServers??!0,roles:a.roles??!0}:{resourceServers:!1,roles:!1},g={controlPlaneTenantId:n,getChildTenantIds:c??(async()=>(await I.fetchAll(A=>e.tenants.list(A),"tenants",{cursorField:"id",pageSize:100})).filter(A=>A.id!==n).map(A=>A.id)),getAdapters:m??(async()=>e),getControlPlaneAdapters:async()=>e,sync:d},{entityHooks:h,tenantHooks:w}=K(g),C={resourceServers:[h.resourceServers,...(s==null?void 0:s.resourceServers)??[]],roles:[h.roles,...(s==null?void 0:s.roles)??[]],connections:(s==null?void 0:s.connections)??[],tenants:(s==null?void 0:s.tenants)??[],rolePermissions:(s==null?void 0:s.rolePermissions)??[]},v=M({accessControl:{controlPlaneTenantId:n,requireOrganizationMatch:i,defaultPermissions:r}},{tenants:w}),{app:y}=I.init({dataAdapter:e,...l,entityHooks:C,managementApiExtensions:[...o,{path:"/tenants",router:v}]});return f&&y.use("/api/v2/*",W()),{app:y,controlPlaneTenantId:n}}function me(t){const e=R(t);return{name:"multi-tenancy",middleware:q(t),hooks:e,routes:[{path:"/management",handler:M(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 R(t){const e=t.accessControl?G(t.accessControl):{},n=t.databaseIsolation?L(t.databaseIsolation):{},a=B(t);return{...e,...n,tenants:a}}function Y(t){const e=new te.Hono,n=R(t);return e.route("/tenants",M(t,n)),e}function fe(t){return{hooks:R(t),middleware:q(t),app:Y(t),config:t}}exports.createAccessControlHooks=G;exports.createAccessControlMiddleware=V;exports.createDatabaseHooks=L;exports.createDatabaseMiddleware=X;exports.createMultiTenancy=Y;exports.createMultiTenancyHooks=R;exports.createMultiTenancyMiddleware=q;exports.createMultiTenancyPlugin=me;exports.createProtectSyncedMiddleware=W;exports.createProvisioningHooks=B;exports.createRuntimeFallbackAdapter=O;exports.createSettingsInheritanceAdapter=le;exports.createSubdomainMiddleware=J;exports.createSyncHooks=K;exports.createTenantsOpenAPIRouter=M;exports.initMultiTenant=ue;exports.setupMultiTenancy=fe;exports.validateTenantAccess=U;exports.withRuntimeFallback=Q;exports.withSettingsInheritance=de;
1
+ "use strict";var x=Object.defineProperty;var ee=(t,e,n)=>e in t?x(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var R=(t,e,n)=>ee(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const te=require("hono"),v=require("authhero"),b=require("@hono/zod-openapi");function H(t){const{controlPlaneTenantId:e,requireOrganizationMatch:n=!0}=t;return{async onTenantAccessValidation(a,r){if(r===e)return!0;if(n){const i=a.var.org_name,o=a.var.organization_id,s=i||o;return s?s.toLowerCase()===r.toLowerCase():!1}return!0}}}function G(t,e,n,a){if(e===n)return!0;const r=a||t;return r?r.toLowerCase()===e.toLowerCase():!1}function U(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 ne(t){return`urn:authhero:tenant:${t.toLowerCase()}`}function L(t){return{async beforeCreate(e,n){return!n.audience&&n.id?{...n,audience:ne(n.id)}:n},async afterCreate(e,n){const{accessControl:a,databaseIsolation:r}=t;a&&e.ctx&&await ae(e,n,a),r!=null&&r.onProvision&&await r.onProvision(n.id)},async beforeDelete(e,n){const{accessControl:a,databaseIsolation:r}=t;if(a)try{const o=(await e.adapters.organizations.list(a.controlPlaneTenantId)).organizations.find(s=>s.name===n);o&&await e.adapters.organizations.remove(a.controlPlaneTenantId,o.id)}catch(i){console.warn(`Failed to remove organization for tenant ${n}:`,i)}if(r!=null&&r.onDeprovision)try{await r.onDeprovision(n)}catch(i){console.warn(`Failed to deprovision database for tenant ${n}:`,i)}}}}async function ae(t,e,n){const{controlPlaneTenantId:a,defaultPermissions:r,defaultRoles:i,issuer:o,adminRoleName:s="Tenant Admin",adminRoleDescription:c="Full access to all tenant management operations",addCreatorToOrganization:m=!0}=n,l=await t.adapters.organizations.create(a,{name:e.id,display_name:e.friendly_name||e.id});let f;if(o&&(f=await re(t,a,s,c)),m&&t.ctx){const d=t.ctx.var.user;if(d!=null&&d.sub&&!await se(t,a,d.sub))try{await t.adapters.userOrganizations.create(a,{user_id:d.sub,organization_id:l.id}),f&&await t.adapters.userRoles.create(a,d.sub,f,l.id)}catch(p){console.warn(`Failed to add creator ${d.sub} to organization ${l.id}:`,p)}}i&&i.length>0&&console.log(`Would assign roles ${i.join(", ")} to organization ${l.id}`),r&&r.length>0&&console.log(`Would grant permissions ${r.join(", ")} to organization ${l.id}`)}async function se(t,e,n){const a=await t.adapters.userRoles.list(e,n,void 0,"");for(const r of a)if((await t.adapters.rolePermissions.list(e,r.id,{per_page:1e3})).some(s=>s.permission_name==="admin:organizations"))return!0;return!1}async function re(t,e,n,a){const i=(await t.adapters.roles.list(e,{})).roles.find(m=>m.name===n);if(i)return i.id;const o=await t.adapters.roles.create(e,{name:n,description:a}),s=v.MANAGEMENT_API_AUDIENCE,c=v.MANAGEMENT_API_SCOPES.map(m=>({role_id:o.id,resource_server_identifier:s,permission_name:m.value}));return await t.adapters.rolePermissions.assign(e,o.id,c),o.id}function k(t,e,n=()=>!0){const{controlPlaneTenantId:a,getChildTenantIds:r,getAdapters:i}=t,o=new Map;async function s(l,f,d){return(await e(l).list(f,{q:`name:${d}`,per_page:1}))[0]??null}async function c(l){const f=await r(),d=e(await i(a));await Promise.all(f.map(async u=>{try{const p=await i(u),g=e(p),w={...d.transform(l),is_system:!0},S=await s(p,u,l.name),T=S?g.getId(S):void 0;if(S&&T){const h=g.preserveOnUpdate?g.preserveOnUpdate(S,w):w;await g.update(u,T,h)}else await g.create(u,w)}catch(p){console.error(`Failed to sync ${d.listKey} "${l.name}" to tenant "${u}":`,p)}}))}async function m(l){const f=await r();await Promise.all(f.map(async d=>{try{const u=await i(d),p=e(u),g=await s(u,d,l),y=g?p.getId(g):void 0;g&&y&&await p.remove(d,y)}catch(u){console.error(`Failed to delete entity "${l}" from tenant "${d}":`,u)}}))}return{afterCreate:async(l,f)=>{l.tenantId===a&&n(f)&&await c(f)},afterUpdate:async(l,f,d)=>{l.tenantId===a&&n(d)&&await c(d)},beforeDelete:async(l,f)=>{if(l.tenantId!==a)return;const u=await e(l.adapters).get(l.tenantId,f);u&&n(u)&&o.set(f,u)},afterDelete:async(l,f)=>{if(l.tenantId!==a)return;const d=o.get(f);d&&(o.delete(f),await m(d.name))}}}function j(t,e,n=()=>!0){const{controlPlaneTenantId:a,getControlPlaneAdapters:r,getAdapters:i}=t;return{async afterCreate(o,s){if(s.id!==a)try{const c=await r(),m=await i(s.id),l=e(c),f=e(m),d=await v.fetchAll(u=>l.listPaginated(a,u),l.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(u=>n(u)).map(async u=>{try{const p=l.transform(u);await f.create(s.id,{...p,is_system:!0})}catch(p){console.error(`Failed to sync entity to new tenant "${s.id}":`,p)}}))}catch(c){console.error(`Failed to sync entities to new tenant "${s.id}":`,c)}}}}const E=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})}),N=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 B(t){const{sync:e={},filters:n={}}=t,a=e.resourceServers??!0,r=e.roles??!0,i=a?k(t,E,n.resourceServers):void 0,o=r?k(t,N,n.roles):void 0,s=a?j(t,E,n.resourceServers):void 0,c=r?j(t,N,n.roles):void 0,m=r?{async afterCreate(d,u){var p;if(u.id!==t.controlPlaneTenantId){await((p=c==null?void 0:c.afterCreate)==null?void 0:p.call(c,d,u));try{const g=await t.getControlPlaneAdapters(),y=await t.getAdapters(u.id),w=await v.fetchAll(T=>g.roles.list(t.controlPlaneTenantId,T),"roles",{cursorField:"id",pageSize:100}),S=new Map;for(const T of w.filter(h=>{var _;return((_=n.roles)==null?void 0:_.call(n,h))??!0})){const h=await l(y,u.id,T.name);h&&S.set(T.name,h.id)}for(const T of w.filter(h=>{var _;return((_=n.roles)==null?void 0:_.call(n,h))??!0})){const h=S.get(T.name);if(h)try{const _=await g.rolePermissions.list(t.controlPlaneTenantId,T.id,{});_.length>0&&await y.rolePermissions.assign(u.id,h,_.map(A=>({role_id:h,resource_server_identifier:A.resource_server_identifier,permission_name:A.permission_name})))}catch(_){console.error(`Failed to sync permissions for role "${T.name}" to tenant "${u.id}":`,_)}}}catch(g){console.error(`Failed to sync role permissions to tenant "${u.id}":`,g)}}}}:void 0;async function l(d,u,p){return(await d.roles.list(u,{q:`name:${p}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:i,roles:o},tenantHooks:{async afterCreate(d,u){const p=[s==null?void 0:s.afterCreate,(m==null?void 0:m.afterCreate)??(c==null?void 0:c.afterCreate)],g=[];for(const y of p)if(y)try{await y(d,u)}catch(w){g.push(w instanceof Error?w:new Error(String(w)))}if(g.length===1)throw g[0];if(g.length>1)throw new AggregateError(g,g.map(y=>y.message).join("; "))}}}}var C=class extends Error{constructor(e=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});R(this,"res");R(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 M(t,e){const n=new b.OpenAPIHono;return n.openapi(b.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:v.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:b.z.object({tenants:b.z.array(v.tenantSchema),start:b.z.number().optional(),limit:b.z.number().optional(),length:b.z.number().optional()})}},description:"List of tenants"}}}),async a=>{var u,p,g,y;const r=a.req.valid("query"),{page:i,per_page:o,include_totals:s,q:c}=r,m=a.var.user,l=(m==null?void 0:m.permissions)||[];if(l.includes("auth:read")||l.includes("admin:organizations")){const w=await a.env.data.tenants.list({page:i,per_page:o,include_totals:s,q:c});return s?a.json({tenants:w.tenants,start:((u=w.totals)==null?void 0:u.start)??0,limit:((p=w.totals)==null?void 0:p.limit)??o,length:w.tenants.length}):a.json({tenants:w.tenants})}if(t.accessControl&&(m!=null&&m.sub)){const w=t.accessControl.controlPlaneTenantId,T=(await v.fetchAll(P=>a.env.data.userOrganizations.listUserOrganizations(w,m.sub,P),"organizations")).map(P=>P.name);if(T.length===0)return s?a.json({tenants:[],start:0,limit:o??50,length:0}):a.json({tenants:[]});const h=T.length,_=i??0,A=o??50,I=_*A,q=T.slice(I,I+A);if(q.length===0)return s?a.json({tenants:[],start:I,limit:A,length:h}):a.json({tenants:[]});const D=q.map(P=>`id:${P}`).join(" OR "),Z=c?`(${D}) AND (${c})`:D,F=await a.env.data.tenants.list({q:Z,per_page:A,include_totals:!1});return s?a.json({tenants:F.tenants,start:I,limit:A,length:h}):a.json({tenants:F.tenants})}const d=await a.env.data.tenants.list({page:i,per_page:o,include_totals:s,q:c});return s?a.json({tenants:d.tenants,start:((g=d.totals)==null?void 0:g.start)??0,limit:((y=d.totals)==null?void 0:y.limit)??o,length:d.tenants.length}):a.json({tenants:d.tenants})}),n.openapi(b.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:v.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:v.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async a=>{var c,m;const r=a.var.user;if(!(r!=null&&r.sub))throw new C(401,{message:"Authentication required to create tenants"});let i=a.req.valid("json");const o={adapters:a.env.data,ctx:a};(c=e.tenants)!=null&&c.beforeCreate&&(i=await e.tenants.beforeCreate(o,i));const s=await a.env.data.tenants.create(i);return(m=e.tenants)!=null&&m.afterCreate&&await e.tenants.afterCreate(o,s),a.json(s,201)}),n.openapi(b.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:b.z.object({id:b.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 s,c;const{id:r}=a.req.valid("param");if(t.accessControl){const m=a.var.user,l=t.accessControl.controlPlaneTenantId;if(!(m!=null&&m.sub))throw new C(401,{message:"Authentication required"});if(r===l)throw new C(403,{message:"Cannot delete the control plane"});if(!(await v.fetchAll(u=>a.env.data.userOrganizations.listUserOrganizations(l,m.sub,u),"organizations")).some(u=>u.name===r))throw new C(403,{message:"Access denied to this tenant"})}if(!await a.env.data.tenants.get(r))throw new C(404,{message:"Tenant not found"});const o={adapters:a.env.data,ctx:a};return(s=e.tenants)!=null&&s.beforeDelete&&await e.tenants.beforeDelete(o,r),await a.env.data.tenants.remove(r),(c=e.tenants)!=null&&c.afterDelete&&await e.tenants.afterDelete(o,r),a.body(null,204)}),n}function oe(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 r=t.match(n);if(r&&r[1])return{type:a,id:r[1]}}return null}async function ie(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 ce(t){return{resource_server:"resource server",role:"role",connection:"connection"}[t]}function K(){return async(t,e)=>{if(!["PATCH","PUT","DELETE"].includes(t.req.method))return e();const n=oe(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 ie(t.env.data,a,n))throw new C(403,{message:`This ${ce(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return e()}}function $(t,e){const{controlPlaneTenantId:n,controlPlaneClientId:a}=e;return{...t,legacyClients:{...t.legacyClients,get:async r=>{var f;const i=await t.legacyClients.get(r);if(!i)return null;const o=a?await t.legacyClients.get(a):void 0,s=await t.connections.list(i.tenant.id),c=n?await t.connections.list(n):{connections:[]},m=s.connections.map(d=>{var g;const u=(g=c.connections)==null?void 0:g.find(y=>y.strategy===d.strategy);if(!(u!=null&&u.options))return d;const p=v.connectionSchema.parse({...u||{},...d});return p.options=v.connectionOptionsSchema.parse({...u.options||{},...d.options}),p}).filter(d=>d),l={...(o==null?void 0:o.tenant)||{},...i.tenant};return!i.tenant.audience&&((f=o==null?void 0:o.tenant)!=null&&f.audience)&&(l.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:m,tenant:l}}},connections:{...t.connections,get:async(r,i)=>{var l;const o=await t.connections.get(r,i);if(!o||!n||r===n)return o;const c=(l=(await t.connections.list(n)).connections)==null?void 0:l.find(f=>f.strategy===o.strategy);if(!(c!=null&&c.options))return o;const m=v.connectionSchema.parse({...c,...o});return m.options=v.connectionOptionsSchema.parse({...c.options||{},...o.options}),m},list:async(r,i)=>{const o=await t.connections.list(r,i);if(!n||r===n)return o;const s=await t.connections.list(n),c=o.connections.map(m=>{var d;const l=(d=s.connections)==null?void 0:d.find(u=>u.strategy===m.strategy);if(!(l!=null&&l.options))return m;const f=v.connectionSchema.parse({...l,...m});return f.options=v.connectionOptionsSchema.parse({...l.options||{},...m.options}),f});return{...o,connections:c}}}}}function W(t,e){return $(t,e)}const le=$,de=W;function Q(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 V(t){return async(e,n)=>{if(!t.accessControl)return n();const{controlPlaneTenantId:a}=t.accessControl,r=e.var.org_name,i=e.var.organization_id,o=r||i;let s=e.var.tenant_id;const c=e.var.user,l=(c!=null&&c.aud?Array.isArray(c.aud)?c.aud:[c.aud]:[]).includes(v.MANAGEMENT_API_AUDIENCE);if(!s&&o&&l&&(e.set("tenant_id",o),s=o),!s)throw new C(400,{message:"Tenant ID not found in request"});if(!G(i,s,a,r))throw new C(403,{message:`Access denied to tenant ${s}`});return n()}}function J(t){return async(e,n)=>{if(!t.subdomainRouting)return n();const{baseDomain:a,reservedSubdomains:r=[],resolveSubdomain:i}=t.subdomainRouting,o=e.req.header("host")||"";let s=null;if(o.endsWith(a)){const m=o.slice(0,-(a.length+1));m&&!m.includes(".")&&(s=m)}if(s&&r.includes(s)&&(s=null),!s)return t.accessControl&&e.set("tenant_id",t.accessControl.controlPlaneTenantId),n();let c=null;if(i)c=await i(s);else if(t.subdomainRouting.useOrganizations!==!1&&t.accessControl)try{const m=await e.env.data.organizations.get(t.accessControl.controlPlaneTenantId,s);m&&(c=m.id)}catch{}if(!c)throw new C(404,{message:`Tenant not found for subdomain: ${s}`});return e.set("tenant_id",c),n()}}function X(t){return async(e,n)=>{if(!t.databaseIsolation)return n();const a=e.var.tenant_id;if(!a)throw new C(400,{message:"Tenant ID not found in request"});try{const r=await t.databaseIsolation.getAdapters(a);e.env.data=r}catch(r){throw console.error(`Failed to resolve database for tenant ${a}:`,r),new C(500,{message:"Failed to resolve tenant database"})}return n()}}function O(t){const e=J(t),n=V(t),a=X(t);return async(r,i)=>(await e(r,async()=>{}),await n(r,async()=>{}),await a(r,async()=>{}),i())}function ue(t){const{dataAdapter:e,controlPlaneTenantId:n="control_plane",sync:a={resourceServers:!0,roles:!0},defaultPermissions:r=["tenant:admin"],requireOrganizationMatch:i=!1,managementApiExtensions:o=[],entityHooks:s,getChildTenantIds:c,getAdapters:m,...l}=t,f=a!==!1,d=f?{resourceServers:a.resourceServers??!0,roles:a.roles??!0}:{resourceServers:!1,roles:!1},g={controlPlaneTenantId:n,getChildTenantIds:c??(async()=>(await v.fetchAll(A=>e.tenants.list(A),"tenants",{cursorField:"id",pageSize:100})).filter(A=>A.id!==n).map(A=>A.id)),getAdapters:m??(async()=>e),getControlPlaneAdapters:async()=>e,sync:d},{entityHooks:y,tenantHooks:w}=B(g),S={resourceServers:[y.resourceServers,...(s==null?void 0:s.resourceServers)??[]],roles:[y.roles,...(s==null?void 0:s.roles)??[]],connections:(s==null?void 0:s.connections)??[],tenants:(s==null?void 0:s.tenants)??[],rolePermissions:(s==null?void 0:s.rolePermissions)??[]},T=M({accessControl:{controlPlaneTenantId:n,requireOrganizationMatch:i,defaultPermissions:r}},{tenants:w}),{app:h}=v.init({dataAdapter:e,...l,entityHooks:S,managementApiExtensions:[...o,{path:"/tenants",router:T}]});return h.use("/api/v2/*",Q(n)),f&&h.use("/api/v2/*",K()),{app:h,controlPlaneTenantId:n}}function me(t){const e=z(t);return{name:"multi-tenancy",middleware:O(t),hooks:e,routes:[{path:"/management",handler:M(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 z(t){const e=t.accessControl?H(t.accessControl):{},n=t.databaseIsolation?U(t.databaseIsolation):{},a=L(t);return{...e,...n,tenants:a}}function Y(t){const e=new te.Hono,n=z(t);return e.route("/tenants",M(t,n)),e}function fe(t){return{hooks:z(t),middleware:O(t),app:Y(t),config:t}}exports.createAccessControlHooks=H;exports.createAccessControlMiddleware=V;exports.createControlPlaneTenantMiddleware=Q;exports.createDatabaseHooks=U;exports.createDatabaseMiddleware=X;exports.createMultiTenancy=Y;exports.createMultiTenancyHooks=z;exports.createMultiTenancyMiddleware=O;exports.createMultiTenancyPlugin=me;exports.createProtectSyncedMiddleware=K;exports.createProvisioningHooks=L;exports.createRuntimeFallbackAdapter=$;exports.createSettingsInheritanceAdapter=le;exports.createSubdomainMiddleware=J;exports.createSyncHooks=B;exports.createTenantsOpenAPIRouter=M;exports.initMultiTenant=ue;exports.setupMultiTenancy=fe;exports.validateTenantAccess=G;exports.withRuntimeFallback=W;exports.withSettingsInheritance=de;
@@ -2,9 +2,8 @@ var W = Object.defineProperty;
2
2
  var Q = (t, e, n) => e in t ? W(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
3
3
  var $ = (t, e, n) => Q(t, typeof e != "symbol" ? e + "" : e, n);
4
4
  import { Hono as V } from "hono";
5
- import { MANAGEMENT_API_SCOPES as J, MANAGEMENT_API_AUDIENCE as L, fetchAll as P, init as X } from "authhero";
6
- import { OpenAPIHono as Y, createRoute as z, z as C } from "@hono/zod-openapi";
7
- import { auth0QuerySchema as Z, tenantSchema as k, tenantInsertSchema as x, connectionSchema as R, connectionOptionsSchema as O } from "@authhero/adapter-interfaces";
5
+ import { MANAGEMENT_API_SCOPES as J, MANAGEMENT_API_AUDIENCE as L, fetchAll as I, auth0QuerySchema as X, tenantSchema as k, tenantInsertSchema as Y, connectionSchema as z, connectionOptionsSchema as R, init as Z } from "authhero";
6
+ import { OpenAPIHono as x, createRoute as O, z as C } from "@hono/zod-openapi";
8
7
  function ee(t) {
9
8
  const { controlPlaneTenantId: e, requireOrganizationMatch: n = !0 } = t;
10
9
  return {
@@ -246,7 +245,7 @@ function N(t, e, n = () => !0) {
246
245
  async afterCreate(o, r) {
247
246
  if (r.id !== s)
248
247
  try {
249
- const c = await a(), m = await i(r.id), l = e(c), f = e(m), d = await P(
248
+ const c = await a(), m = await i(r.id), l = e(c), f = e(m), d = await I(
250
249
  (u) => l.listPaginated(s, u),
251
250
  l.listKey,
252
251
  { cursorField: "id", pageSize: 100 }
@@ -332,7 +331,7 @@ function ce(t) {
332
331
  if (u.id !== t.controlPlaneTenantId) {
333
332
  await ((p = c == null ? void 0 : c.afterCreate) == null ? void 0 : p.call(c, d, u));
334
333
  try {
335
- const g = await t.getControlPlaneAdapters(), y = await t.getAdapters(u.id), w = await P(
334
+ const g = await t.getControlPlaneAdapters(), y = await t.getAdapters(u.id), w = await I(
336
335
  (v) => g.roles.list(
337
336
  t.controlPlaneTenantId,
338
337
  v
@@ -453,14 +452,14 @@ var b = class extends Error {
453
452
  }
454
453
  };
455
454
  function M(t, e) {
456
- const n = new Y();
455
+ const n = new x();
457
456
  return n.openapi(
458
- z({
457
+ O({
459
458
  tags: ["tenants"],
460
459
  method: "get",
461
460
  path: "/",
462
461
  request: {
463
- query: Z
462
+ query: X
464
463
  },
465
464
  security: [
466
465
  {
@@ -501,14 +500,14 @@ function M(t, e) {
501
500
  }) : s.json({ tenants: w.tenants });
502
501
  }
503
502
  if (t.accessControl && (m != null && m.sub)) {
504
- const w = t.accessControl.controlPlaneTenantId, v = (await P(
505
- (I) => s.env.data.userOrganizations.listUserOrganizations(
503
+ const w = t.accessControl.controlPlaneTenantId, v = (await I(
504
+ (P) => s.env.data.userOrganizations.listUserOrganizations(
506
505
  w,
507
506
  m.sub,
508
- I
507
+ P
509
508
  ),
510
509
  "organizations"
511
- )).map((I) => I.name);
510
+ )).map((P) => P.name);
512
511
  if (v.length === 0)
513
512
  return r ? s.json({
514
513
  tenants: [],
@@ -524,7 +523,7 @@ function M(t, e) {
524
523
  limit: _,
525
524
  length: h
526
525
  }) : s.json({ tenants: [] });
527
- const F = D.map((I) => `id:${I}`).join(" OR "), K = c ? `(${F}) AND (${c})` : F, j = await s.env.data.tenants.list({
526
+ const F = D.map((P) => `id:${P}`).join(" OR "), K = c ? `(${F}) AND (${c})` : F, j = await s.env.data.tenants.list({
528
527
  q: K,
529
528
  per_page: _,
530
529
  include_totals: !1
@@ -551,7 +550,7 @@ function M(t, e) {
551
550
  }) : s.json({ tenants: d.tenants });
552
551
  }
553
552
  ), n.openapi(
554
- z({
553
+ O({
555
554
  tags: ["tenants"],
556
555
  method: "post",
557
556
  path: "/",
@@ -559,7 +558,7 @@ function M(t, e) {
559
558
  body: {
560
559
  content: {
561
560
  "application/json": {
562
- schema: x
561
+ schema: Y
563
562
  }
564
563
  }
565
564
  }
@@ -603,7 +602,7 @@ function M(t, e) {
603
602
  return (m = e.tenants) != null && m.afterCreate && await e.tenants.afterCreate(o, r), s.json(r, 201);
604
603
  }
605
604
  ), n.openapi(
606
- z({
605
+ O({
607
606
  tags: ["tenants"],
608
607
  method: "delete",
609
608
  path: "/{id}",
@@ -642,7 +641,7 @@ function M(t, e) {
642
641
  throw new b(403, {
643
642
  message: "Cannot delete the control plane"
644
643
  });
645
- if (!(await P(
644
+ if (!(await I(
646
645
  (u) => s.env.data.userOrganizations.listUserOrganizations(
647
646
  l,
648
647
  m.sub,
@@ -748,11 +747,11 @@ function U(t, e) {
748
747
  );
749
748
  if (!(u != null && u.options))
750
749
  return d;
751
- const p = R.parse({
750
+ const p = z.parse({
752
751
  ...u || {},
753
752
  ...d
754
753
  });
755
- return p.options = O.parse({
754
+ return p.options = R.parse({
756
755
  ...u.options || {},
757
756
  ...d.options
758
757
  }), p;
@@ -794,11 +793,11 @@ function U(t, e) {
794
793
  );
795
794
  if (!(c != null && c.options))
796
795
  return o;
797
- const m = R.parse({
796
+ const m = z.parse({
798
797
  ...c,
799
798
  ...o
800
799
  });
801
- return m.options = O.parse({
800
+ return m.options = R.parse({
802
801
  ...c.options || {},
803
802
  ...o.options
804
803
  }), m;
@@ -814,11 +813,11 @@ function U(t, e) {
814
813
  );
815
814
  if (!(l != null && l.options))
816
815
  return m;
817
- const f = R.parse({
816
+ const f = z.parse({
818
817
  ...l,
819
818
  ...m
820
819
  });
821
- return f.options = O.parse({
820
+ return f.options = R.parse({
822
821
  ...l.options || {},
823
822
  ...m.options
824
823
  }), f;
@@ -843,6 +842,12 @@ function fe(t, e) {
843
842
  }
844
843
  const Ae = U, Ce = fe;
845
844
  function ge(t) {
845
+ return async (e, n) => {
846
+ const s = e.var.user;
847
+ return (s == null ? void 0 : s.tenant_id) === t && s.org_name && e.set("tenant_id", s.org_name), n();
848
+ };
849
+ }
850
+ function pe(t) {
846
851
  return async (e, n) => {
847
852
  if (!t.accessControl)
848
853
  return n();
@@ -865,7 +870,7 @@ function ge(t) {
865
870
  return n();
866
871
  };
867
872
  }
868
- function pe(t) {
873
+ function we(t) {
869
874
  return async (e, n) => {
870
875
  if (!t.subdomainRouting)
871
876
  return n();
@@ -900,7 +905,7 @@ function pe(t) {
900
905
  return e.set("tenant_id", c), n();
901
906
  };
902
907
  }
903
- function we(t) {
908
+ function ye(t) {
904
909
  return async (e, n) => {
905
910
  if (!t.databaseIsolation)
906
911
  return n();
@@ -924,13 +929,13 @@ function we(t) {
924
929
  };
925
930
  }
926
931
  function B(t) {
927
- const e = pe(t), n = ge(t), s = we(t);
932
+ const e = we(t), n = pe(t), s = ye(t);
928
933
  return async (a, i) => (await e(a, async () => {
929
934
  }), await n(a, async () => {
930
935
  }), await s(a, async () => {
931
936
  }), i());
932
937
  }
933
- function Ie(t) {
938
+ function Pe(t) {
934
939
  const {
935
940
  dataAdapter: e,
936
941
  controlPlaneTenantId: n = "control_plane",
@@ -947,7 +952,7 @@ function Ie(t) {
947
952
  roles: s.roles ?? !0
948
953
  } : { resourceServers: !1, roles: !1 }, g = {
949
954
  controlPlaneTenantId: n,
950
- getChildTenantIds: c ?? (async () => (await P(
955
+ getChildTenantIds: c ?? (async () => (await I(
951
956
  (_) => e.tenants.list(_),
952
957
  "tenants",
953
958
  { cursorField: "id", pageSize: 100 }
@@ -973,7 +978,7 @@ function Ie(t) {
973
978
  }
974
979
  },
975
980
  { tenants: w }
976
- ), { app: h } = X({
981
+ ), { app: h } = Z({
977
982
  dataAdapter: e,
978
983
  ...l,
979
984
  entityHooks: A,
@@ -982,9 +987,9 @@ function Ie(t) {
982
987
  { path: "/tenants", router: v }
983
988
  ]
984
989
  });
985
- return f && h.use("/api/v2/*", me()), { app: h, controlPlaneTenantId: n };
990
+ return h.use("/api/v2/*", ge(n)), f && h.use("/api/v2/*", me()), { app: h, controlPlaneTenantId: n };
986
991
  }
987
- function Pe(t) {
992
+ function Ie(t) {
988
993
  const e = q(t);
989
994
  return {
990
995
  name: "multi-tenancy",
@@ -1017,7 +1022,7 @@ function q(t) {
1017
1022
  tenants: s
1018
1023
  };
1019
1024
  }
1020
- function ye(t) {
1025
+ function he(t) {
1021
1026
  const e = new V(), n = q(t);
1022
1027
  return e.route("/tenants", M(t, n)), e;
1023
1028
  }
@@ -1025,27 +1030,28 @@ function Se(t) {
1025
1030
  return {
1026
1031
  hooks: q(t),
1027
1032
  middleware: B(t),
1028
- app: ye(t),
1033
+ app: he(t),
1029
1034
  config: t
1030
1035
  };
1031
1036
  }
1032
1037
  export {
1033
1038
  ee as createAccessControlHooks,
1034
- ge as createAccessControlMiddleware,
1039
+ pe as createAccessControlMiddleware,
1040
+ ge as createControlPlaneTenantMiddleware,
1035
1041
  ne as createDatabaseHooks,
1036
- we as createDatabaseMiddleware,
1037
- ye as createMultiTenancy,
1042
+ ye as createDatabaseMiddleware,
1043
+ he as createMultiTenancy,
1038
1044
  q as createMultiTenancyHooks,
1039
1045
  B as createMultiTenancyMiddleware,
1040
- Pe as createMultiTenancyPlugin,
1046
+ Ie as createMultiTenancyPlugin,
1041
1047
  me as createProtectSyncedMiddleware,
1042
1048
  re as createProvisioningHooks,
1043
1049
  U as createRuntimeFallbackAdapter,
1044
1050
  Ae as createSettingsInheritanceAdapter,
1045
- pe as createSubdomainMiddleware,
1051
+ we as createSubdomainMiddleware,
1046
1052
  ce as createSyncHooks,
1047
1053
  M as createTenantsOpenAPIRouter,
1048
- Ie as initMultiTenant,
1054
+ Pe as initMultiTenant,
1049
1055
  Se as setupMultiTenancy,
1050
1056
  te as validateTenantAccess,
1051
1057
  fe as withRuntimeFallback,
@@ -0,0 +1,25 @@
1
+ import { AccessControlConfig, MultiTenancyHooks } from "../types";
2
+ /**
3
+ * Creates hooks for organization-based tenant access control.
4
+ *
5
+ * This implements the following access model:
6
+ * - Control plane: Accessible without an organization claim
7
+ * - Child tenants: Require an organization claim matching the tenant ID
8
+ * - org_name (organization name) takes precedence and should match tenant ID
9
+ * - org_id (organization ID) is checked as fallback
10
+ *
11
+ * @param config - Access control configuration
12
+ * @returns Hooks for access validation
13
+ */
14
+ export declare function createAccessControlHooks(config: AccessControlConfig): Pick<MultiTenancyHooks, "onTenantAccessValidation">;
15
+ /**
16
+ * Validates that a token can access a specific tenant based on its organization claim.
17
+ *
18
+ * @param organizationId - The organization ID from the token (may be undefined)
19
+ * @param orgName - The organization name from the token (may be undefined, takes precedence)
20
+ * @param targetTenantId - The tenant ID being accessed
21
+ * @param controlPlaneTenantId - The control plane/management tenant ID
22
+ * @returns true if access is allowed
23
+ */
24
+ export declare function validateTenantAccess(organizationId: string | undefined, targetTenantId: string, controlPlaneTenantId: string, orgName?: string): boolean;
25
+ //# sourceMappingURL=access-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-control.d.ts","sourceRoot":"","sources":["../../../src/hooks/access-control.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EAEnB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,GAC1B,IAAI,CAAC,iBAAiB,EAAE,0BAA0B,CAAC,CAuCrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,MAAM,EAC5B,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAiBT"}
@@ -0,0 +1,35 @@
1
+ import { DataAdapters } from "authhero";
2
+ import { DatabaseIsolationConfig, MultiTenancyHooks } from "../types";
3
+ /**
4
+ * Creates hooks for per-tenant database resolution.
5
+ *
6
+ * This enables scenarios where each tenant has its own database instance,
7
+ * providing complete data isolation.
8
+ *
9
+ * @param config - Database isolation configuration
10
+ * @returns Hooks for database resolution
11
+ */
12
+ export declare function createDatabaseHooks(config: DatabaseIsolationConfig): Pick<MultiTenancyHooks, "resolveDataAdapters">;
13
+ /**
14
+ * Database factory interface for creating tenant-specific database adapters.
15
+ *
16
+ * Implementations of this interface should live in the respective adapter packages:
17
+ * - D1: @authhero/cloudflare
18
+ * - Turso: @authhero/turso (or similar)
19
+ * - Custom: Implement your own
20
+ */
21
+ export interface DatabaseFactory {
22
+ /**
23
+ * Get or create a database adapter for a tenant.
24
+ */
25
+ getAdapters(tenantId: string): Promise<DataAdapters>;
26
+ /**
27
+ * Provision a new database for a tenant.
28
+ */
29
+ provision(tenantId: string): Promise<void>;
30
+ /**
31
+ * Deprovision (delete) a tenant's database.
32
+ */
33
+ deprovision(tenantId: string): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/hooks/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,uBAAuB,GAC9B,IAAI,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAgBhD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAErD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C"}
@@ -0,0 +1,5 @@
1
+ export { createAccessControlHooks, validateTenantAccess, } from "./access-control";
2
+ export { createDatabaseHooks, type DatabaseFactory } from "./database";
3
+ export { createProvisioningHooks } from "./provisioning";
4
+ export { createSyncHooks, type EntitySyncConfig, type SyncHooksResult, } from "./sync";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EACL,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { MultiTenancyConfig, TenantEntityHooks } from "../types";
2
+ /**
3
+ * Creates hooks for tenant provisioning and deprovisioning.
4
+ *
5
+ * This handles:
6
+ * - Setting the correct audience for new tenants (urn:authhero:tenant:{id})
7
+ * - Creating organizations on the control plane when a new tenant is created
8
+ * - Provisioning databases for new tenants
9
+ * - Cleaning up organizations and databases when tenants are deleted
10
+ *
11
+ * @param config - Multi-tenancy configuration
12
+ * @returns Tenant entity hooks for lifecycle events
13
+ */
14
+ export declare function createProvisioningHooks(config: MultiTenancyConfig): TenantEntityHooks;
15
+ //# sourceMappingURL=provisioning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../../src/hooks/provisioning.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,kBAAkB,GACzB,iBAAiB,CAyEnB"}
@@ -0,0 +1,140 @@
1
+ import { DataAdapters, ResourceServer, ResourceServerInsert } from "authhero";
2
+ import { TenantEntityHooks } from "../types";
3
+ /**
4
+ * Configuration for resource server synchronization
5
+ */
6
+ export interface ResourceServerSyncConfig {
7
+ /**
8
+ * The control plane tenant ID from which resource servers are synced
9
+ */
10
+ controlPlaneTenantId: string;
11
+ /**
12
+ * Function to get the list of all tenant IDs to sync to.
13
+ * Called when a resource server is created/updated/deleted on the control plane.
14
+ */
15
+ getChildTenantIds: () => Promise<string[]>;
16
+ /**
17
+ * Function to get adapters for a specific tenant.
18
+ * Used to write resource servers to child tenants.
19
+ */
20
+ getAdapters: (tenantId: string) => Promise<DataAdapters>;
21
+ /**
22
+ * Optional: Filter function to determine if a resource server should be synced.
23
+ * Return true to sync, false to skip.
24
+ * @default All resource servers are synced
25
+ */
26
+ shouldSync?: (resourceServer: ResourceServer) => boolean;
27
+ /**
28
+ * Optional: Transform the resource server before syncing to child tenants.
29
+ * Useful for modifying identifiers or removing sensitive data.
30
+ */
31
+ transformForSync?: (resourceServer: ResourceServer, targetTenantId: string) => ResourceServerInsert;
32
+ }
33
+ /**
34
+ * Context passed to entity hooks
35
+ */
36
+ interface EntityHookContext {
37
+ tenantId: string;
38
+ adapters: DataAdapters;
39
+ }
40
+ /**
41
+ * Entity hooks for resource server CRUD operations
42
+ */
43
+ export interface ResourceServerEntityHooks {
44
+ afterCreate?: (ctx: EntityHookContext, entity: ResourceServer) => Promise<void>;
45
+ afterUpdate?: (ctx: EntityHookContext, id: string, entity: ResourceServer) => Promise<void>;
46
+ afterDelete?: (ctx: EntityHookContext, id: string) => Promise<void>;
47
+ }
48
+ /**
49
+ * Creates entity hooks for syncing resource servers from the control plane to all child tenants.
50
+ *
51
+ * When a resource server is created, updated, or deleted on the control plane,
52
+ * the change is automatically propagated to all child tenants.
53
+ *
54
+ * @param config - Resource server sync configuration
55
+ * @returns Entity hooks for resource server synchronization
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * import { createResourceServerSyncHooks } from "@authhero/multi-tenancy";
60
+ *
61
+ * const resourceServerHooks = createResourceServerSyncHooks({
62
+ * controlPlaneTenantId: "main",
63
+ * getChildTenantIds: async () => {
64
+ * const tenants = await db.tenants.list();
65
+ * return tenants.filter(t => t.id !== "main").map(t => t.id);
66
+ * },
67
+ * getAdapters: async (tenantId) => {
68
+ * return createAdaptersForTenant(tenantId);
69
+ * },
70
+ * });
71
+ *
72
+ * // Use with AuthHero config
73
+ * const config: AuthHeroConfig = {
74
+ * dataAdapter,
75
+ * entityHooks: {
76
+ * resourceServers: resourceServerHooks,
77
+ * },
78
+ * };
79
+ * ```
80
+ */
81
+ export declare function createResourceServerSyncHooks(config: ResourceServerSyncConfig): ResourceServerEntityHooks;
82
+ /**
83
+ * Configuration for syncing resource servers to new tenants
84
+ */
85
+ export interface TenantResourceServerSyncConfig {
86
+ /**
87
+ * The control plane tenant ID from which resource servers are copied
88
+ */
89
+ controlPlaneTenantId: string;
90
+ /**
91
+ * Function to get adapters for the control plane.
92
+ * Used to read existing resource servers.
93
+ */
94
+ getControlPlaneAdapters: () => Promise<DataAdapters>;
95
+ /**
96
+ * Function to get adapters for the new tenant.
97
+ * Used to write resource servers to the new tenant.
98
+ */
99
+ getAdapters: (tenantId: string) => Promise<DataAdapters>;
100
+ /**
101
+ * Optional: Filter function to determine if a resource server should be synced.
102
+ * Return true to sync, false to skip.
103
+ * @default All resource servers are synced
104
+ */
105
+ shouldSync?: (resourceServer: ResourceServer) => boolean;
106
+ /**
107
+ * Optional: Transform the resource server before syncing to the new tenant.
108
+ * Useful for modifying identifiers or removing sensitive data.
109
+ */
110
+ transformForSync?: (resourceServer: ResourceServer, targetTenantId: string) => ResourceServerInsert;
111
+ }
112
+ /**
113
+ * Creates a tenant afterCreate hook that copies all resource servers from the control plane
114
+ * to a newly created tenant.
115
+ *
116
+ * This should be used with the MultiTenancyHooks.tenants.afterCreate hook.
117
+ *
118
+ * @param config - Configuration for tenant resource server sync
119
+ * @returns A TenantEntityHooks object with afterCreate implemented
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * import { createTenantResourceServerSyncHooks } from "@authhero/multi-tenancy";
124
+ *
125
+ * const resourceServerSyncHooks = createTenantResourceServerSyncHooks({
126
+ * controlPlaneTenantId: "main",
127
+ * getControlPlaneAdapters: async () => controlPlaneAdapters,
128
+ * getAdapters: async (tenantId) => createAdaptersForTenant(tenantId),
129
+ * });
130
+ *
131
+ * const multiTenancyHooks: MultiTenancyHooks = {
132
+ * tenants: {
133
+ * afterCreate: resourceServerSyncHooks.afterCreate,
134
+ * },
135
+ * };
136
+ * ```
137
+ */
138
+ export declare function createTenantResourceServerSyncHooks(config: TenantResourceServerSyncConfig): TenantEntityHooks;
139
+ export {};
140
+ //# sourceMappingURL=resource-server-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-server-sync.d.ts","sourceRoot":"","sources":["../../../src/hooks/resource-server-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,cAAc,EACd,oBAAoB,EAErB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,iBAAiB,EAAqB,MAAM,UAAU,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAE7B;;;OAGG;IACH,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE3C;;;OAGG;IACH,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzD;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,OAAO,CAAC;IAEzD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CACjB,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,MAAM,KACnB,oBAAoB,CAAC;CAC3B;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,CACZ,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,WAAW,CAAC,EAAE,CACZ,GAAG,EAAE,iBAAiB,EACtB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,wBAAwB,GAC/B,yBAAyB,CA2L3B;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAE7B;;;OAGG;IACH,uBAAuB,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAErD;;;OAGG;IACH,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzD;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,OAAO,CAAC;IAEzD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CACjB,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,MAAM,KACnB,oBAAoB,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,8BAA8B,GACrC,iBAAiB,CAiFnB"}