@authhero/multi-tenancy 14.9.0 → 14.10.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
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var se=Object.defineProperty;var oe=(e,t,n)=>t in e?se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var k=(e,t,n)=>oe(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ie=require("hono"),_=require("authhero"),S=require("@hono/zod-openapi");function K(e){const{controlPlaneTenantId:t,requireOrganizationMatch:n=!0}=e;return{async onTenantAccessValidation(r,s){if(s===t)return!0;if(n){const o=r.var.org_name,i=r.var.organization_id,a=o||i;return a?a.toLowerCase()===s.toLowerCase():!1}return!0}}}function V(e,t,n,r){if(t===n)return!0;const s=r||e;return s?s.toLowerCase()===t.toLowerCase():!1}function Q(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(n){console.error(`Failed to resolve data adapters for tenant ${t}:`,n);return}}}}function ce(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function J(e){return{async beforeCreate(t,n){return!n.audience&&n.id?{...n,audience:ce(n.id)}:n},async afterCreate(t,n){const{accessControl:r,databaseIsolation:s}=e;r&&t.ctx&&await le(t,n,r),s!=null&&s.onProvision&&await s.onProvision(n.id)},async beforeDelete(t,n){const{accessControl:r,databaseIsolation:s}=e;if(r)try{const i=(await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(a=>a.name===n);i&&await t.adapters.organizations.remove(r.controlPlaneTenantId,i.id)}catch(o){console.warn(`Failed to remove organization for tenant ${n}:`,o)}if(s!=null&&s.onDeprovision)try{await s.onDeprovision(n)}catch(o){console.warn(`Failed to deprovision database for tenant ${n}:`,o)}}}}async function le(e,t,n){const{controlPlaneTenantId:r,defaultPermissions:s,defaultRoles:o,issuer:i,adminRoleName:a="Tenant Admin",adminRoleDescription:u="Full access to all tenant management operations",addCreatorToOrganization:c=!0}=n,l=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id});let g;if(i&&(g=await de(e,r,a,u)),c&&e.ctx){const d=e.ctx.var.user;if(d!=null&&d.sub&&!await ue(e,r,d.sub))try{await e.adapters.userOrganizations.create(r,{user_id:d.sub,organization_id:l.id}),g&&await e.adapters.userRoles.create(r,d.sub,g,l.id)}catch(m){console.warn(`Failed to add creator ${d.sub} to organization ${l.id}:`,m)}}o&&o.length>0&&console.log(`Would assign roles ${o.join(", ")} to organization ${l.id}`),s&&s.length>0&&console.log(`Would grant permissions ${s.join(", ")} to organization ${l.id}`)}async function ue(e,t,n){const r=await e.adapters.userRoles.list(t,n,void 0,"");for(const s of r)if((await e.adapters.rolePermissions.list(t,s.id,{per_page:1e3})).some(a=>a.permission_name==="admin:organizations"))return!0;return!1}async function de(e,t,n,r){const o=(await e.adapters.roles.list(t,{})).roles.find(c=>c.name===n);if(o)return o.id;const i=await e.adapters.roles.create(t,{name:n,description:r}),a=_.MANAGEMENT_API_AUDIENCE,u=_.MANAGEMENT_API_SCOPES.map(c=>({role_id:i.id,resource_server_identifier:a,permission_name:c.value}));return await e.adapters.rolePermissions.assign(t,i.id,u),i.id}function H(e,t,n=()=>!0){const{controlPlaneTenantId:r,getChildTenantIds:s,getAdapters:o}=e,i=new Map;async function a(l,g,d){return(await t(l).list(g,{q:`name:${d}`,per_page:1}))[0]??null}async function u(l){const g=await s(),d=t(await o(r));await Promise.all(g.map(async f=>{try{const m=await o(f),w=t(m),p={...d.transform(l),is_system:!0},y=await a(m,f,l.name),T=y?w.getId(y):void 0;if(y&&T){const C=w.preserveOnUpdate?w.preserveOnUpdate(y,p):p;await w.update(f,T,C)}else await w.create(f,p)}catch(m){console.error(`Failed to sync ${d.listKey} "${l.name}" to tenant "${f}":`,m)}}))}async function c(l){const g=await s();await Promise.all(g.map(async d=>{try{const f=await o(d),m=t(f),w=await a(f,d,l),h=w?m.getId(w):void 0;w&&h&&await m.remove(d,h)}catch(f){console.error(`Failed to delete entity "${l}" from tenant "${d}":`,f)}}))}return{afterCreate:async(l,g)=>{l.tenantId===r&&n(g)&&await u(g)},afterUpdate:async(l,g,d)=>{l.tenantId===r&&n(d)&&await u(d)},beforeDelete:async(l,g)=>{if(l.tenantId!==r)return;const f=await t(l.adapters).get(l.tenantId,g);f&&n(f)&&i.set(g,f)},afterDelete:async(l,g)=>{if(l.tenantId!==r)return;const d=i.get(g);d&&(i.delete(g),await c(d.name))}}}function G(e,t,n=()=>!0){const{controlPlaneTenantId:r,getControlPlaneAdapters:s,getAdapters:o}=e;return{async afterCreate(i,a){if(a.id!==r)try{const u=await s(),c=await o(a.id),l=t(u),g=t(c),d=await _.fetchAll(f=>l.listPaginated(r,f),l.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(f=>n(f)).map(async f=>{try{const m=l.transform(f);await g.create(a.id,{...m,is_system:!0})}catch(m){console.error(`Failed to sync entity to new tenant "${a.id}":`,m)}}))}catch(u){console.error(`Failed to sync entities to new tenant "${a.id}":`,u)}}}}const B=e=>({list:async(t,n)=>(await e.resourceServers.list(t,n)).resource_servers,listPaginated:(t,n)=>e.resourceServers.list(t,n),get:(t,n)=>e.resourceServers.get(t,n),create:(t,n)=>e.resourceServers.create(t,n),update:(t,n,r)=>e.resourceServers.update(t,n,r),remove:(t,n)=>e.resourceServers.remove(t,n),listKey:"resource_servers",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,identifier:t.identifier,scopes:t.scopes,signing_alg:t.signing_alg,token_lifetime:t.token_lifetime,token_lifetime_for_web:t.token_lifetime_for_web})}),U=e=>({list:async(t,n)=>(await e.roles.list(t,n)).roles,listPaginated:(t,n)=>e.roles.list(t,n),get:(t,n)=>e.roles.get(t,n),create:(t,n)=>e.roles.create(t,n),update:(t,n,r)=>e.roles.update(t,n,r),remove:(t,n)=>e.roles.remove(t,n),listKey:"roles",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,description:t.description})});function L(e){var t;return((t=e.metadata)==null?void 0:t.sync)!==!1}function X(e){const{sync:t={},filters:n={}}=e,r=t.resourceServers??!0,s=t.roles??!0,o=m=>L(m)?n.resourceServers?n.resourceServers(m):!0:!1,i=m=>L(m)?n.roles?n.roles(m):!0:!1,a=r?H(e,B,o):void 0,u=s?H(e,U,i):void 0,c=r?G(e,B,o):void 0,l=s?G(e,U,i):void 0,g=s?{async afterCreate(m,w){var h;if(w.id!==e.controlPlaneTenantId){await((h=l==null?void 0:l.afterCreate)==null?void 0:h.call(l,m,w));try{const p=await e.getControlPlaneAdapters(),y=await e.getAdapters(w.id),T=await _.fetchAll(P=>p.roles.list(e.controlPlaneTenantId,P),"roles",{cursorField:"id",pageSize:100}),C=new Map;for(const P of T.filter(v=>{var A;return((A=n.roles)==null?void 0:A.call(n,v))??!0})){const v=await d(y,w.id,P.name);v&&C.set(P.name,v.id)}for(const P of T.filter(v=>{var A;return((A=n.roles)==null?void 0:A.call(n,v))??!0})){const v=C.get(P.name);if(v)try{const A=await p.rolePermissions.list(e.controlPlaneTenantId,P.id,{});A.length>0&&await y.rolePermissions.assign(w.id,v,A.map(b=>({role_id:v,resource_server_identifier:b.resource_server_identifier,permission_name:b.permission_name})))}catch(A){console.error(`Failed to sync permissions for role "${P.name}" to tenant "${w.id}":`,A)}}}catch(p){console.error(`Failed to sync role permissions to tenant "${w.id}":`,p)}}}}:void 0;async function d(m,w,h){return(await m.roles.list(w,{q:`name:${h}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:a,roles:u},tenantHooks:{async afterCreate(m,w){const h=[c==null?void 0:c.afterCreate,(g==null?void 0:g.afterCreate)??(l==null?void 0:l.afterCreate)],p=[];for(const y of h)if(y)try{await y(m,w)}catch(T){p.push(T instanceof Error?T:new Error(String(T)))}if(p.length===1)throw p[0];if(p.length>1)throw new AggregateError(p,p.map(y=>y.message).join("; "))}}}}var I=class extends Error{constructor(t=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});k(this,"res");k(this,"status");this.res=n==null?void 0:n.res,this.status=t}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function O(e,t){const n=new S.OpenAPIHono;return n.openapi(S.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:_.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:S.z.object({tenants:S.z.array(_.tenantSchema),start:S.z.number().optional(),limit:S.z.number().optional(),length:S.z.number().optional()})}},description:"List of tenants"}}}),async r=>{var m,w,h,p,y,T;const s=r.req.valid("query"),{page:o,per_page:i,include_totals:a,q:u}=s,c=r.var.user,l=(c==null?void 0:c.permissions)||[];if(l.includes("auth:read")||l.includes("admin:organizations")){const C=await r.env.data.tenants.list({page:o,per_page:i,include_totals:a,q:u});return a?r.json({tenants:C.tenants,start:((m=C.totals)==null?void 0:m.start)??0,limit:((w=C.totals)==null?void 0:w.limit)??i,length:C.tenants.length}):r.json({tenants:C.tenants})}const d=((h=e.accessControl)==null?void 0:h.controlPlaneTenantId)??((p=r.env.data.multiTenancyConfig)==null?void 0:p.controlPlaneTenantId);if(d&&(c!=null&&c.sub)){const P=(await _.fetchAll(F=>r.env.data.userOrganizations.listUserOrganizations(d,c.sub,F),"organizations")).map(F=>F.name);if(P.length===0)return a?r.json({tenants:[],start:0,limit:i??50,length:0}):r.json({tenants:[]});const v=P.length,A=o??0,b=i??50,z=A*b,M=P.slice(z,z+b);if(M.length===0)return a?r.json({tenants:[],start:z,limit:b,length:v}):r.json({tenants:[]});const j=M.map(F=>`id:${F}`).join(" OR "),ae=u?`(${j}) AND (${u})`:j,N=await r.env.data.tenants.list({q:ae,per_page:b,include_totals:!1});return a?r.json({tenants:N.tenants,start:z,limit:b,length:v}):r.json({tenants:N.tenants})}const f=await r.env.data.tenants.list({page:o,per_page:i,include_totals:a,q:u});return a?r.json({tenants:f.tenants,start:((y=f.totals)==null?void 0:y.start)??0,limit:((T=f.totals)==null?void 0:T.limit)??i,length:f.tenants.length}):r.json({tenants:f.tenants})}),n.openapi(S.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:_.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:_.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async r=>{var u,c;const s=r.var.user;if(!(s!=null&&s.sub))throw new I(401,{message:"Authentication required to create tenants"});let o=r.req.valid("json");const i={adapters:r.env.data,ctx:r};(u=t.tenants)!=null&&u.beforeCreate&&(o=await t.tenants.beforeCreate(i,o));const a=await r.env.data.tenants.create(o);return(c=t.tenants)!=null&&c.afterCreate&&await t.tenants.afterCreate(i,a),r.json(a,201)}),n.openapi(S.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:S.z.object({id:S.z.string()})},security:[{Bearer:["delete:tenants"]}],responses:{204:{description:"Tenant deleted"},403:{description:"Access denied or cannot delete the control plane"},404:{description:"Tenant not found"}}}),async r=>{var u,c,l,g;const{id:s}=r.req.valid("param"),o=((u=e.accessControl)==null?void 0:u.controlPlaneTenantId)??((c=r.env.data.multiTenancyConfig)==null?void 0:c.controlPlaneTenantId);if(o){const d=r.var.user;if(!(d!=null&&d.sub))throw new I(401,{message:"Authentication required"});if(s===o)throw new I(403,{message:"Cannot delete the control plane"});if(!(await _.fetchAll(w=>r.env.data.userOrganizations.listUserOrganizations(o,d.sub,w),"organizations")).some(w=>w.name===s))throw new I(403,{message:"Access denied to this tenant"})}if(!await r.env.data.tenants.get(s))throw new I(404,{message:"Tenant not found"});const a={adapters:r.env.data,ctx:r};return(l=t.tenants)!=null&&l.beforeDelete&&await t.tenants.beforeDelete(a,s),await r.env.data.tenants.remove(s),(g=t.tenants)!=null&&g.afterDelete&&await t.tenants.afterDelete(a,s),r.body(null,204)}),n}function fe(e){const t=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:n,type:r}of t){const s=e.match(n);if(s&&s[1])return{type:r,id:s[1]}}return null}async function me(e,t,n){try{switch(n.type){case"resource_server":{const r=await e.resourceServers.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"role":{const r=await e.roles.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"connection":{const r=await e.connections.get(t,n.id);return(r==null?void 0:r.is_system)===!0}default:return!1}}catch{return!1}}function ge(e){return{resource_server:"resource server",role:"role",connection:"connection"}[e]}function Y(){return async(e,t)=>{if(!["PATCH","PUT","DELETE"].includes(e.req.method))return t();const n=fe(e.req.path);if(!n)return t();const r=e.var.tenant_id||e.req.header("x-tenant-id")||e.req.header("tenant-id");if(!r)return t();if(await me(e.env.data,r,n))throw new I(403,{message:`This ${ge(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}const we=["client_secret","app_secret","twilio_token"];function pe(e){if(!e)return e;const t={...e};for(const n of we)delete t[n];return t}function q(e,t,n){const r=t.find(i=>i.strategy===e.strategy);if(!(r!=null&&r.options))return e;const s=_.connectionSchema.passthrough().parse({...r,...e}),o=n?pe(r.options):r.options;return s.options=_.connectionOptionsSchema.passthrough().parse({...o||{},...e.options}),s}function R(e,t){const n=[...t||[],...e||[]];return[...new Set(n)]}function W(e,t){return t?{...e,callbacks:R(e.callbacks,t.callbacks),web_origins:R(e.web_origins,t.web_origins),allowed_logout_urls:R(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:R(e.allowed_origins,t.allowed_origins)}:e}function Z(e,t){const{controlPlaneTenantId:n,controlPlaneClientId:r,excludeSensitiveFields:s=!1}=t;return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r},connections:{...e.connections,get:async(o,i)=>{const a=await e.connections.get(o,i);if(!a||!n||o===n)return a;const u=await e.connections.list(n);return q(a,u.connections||[],s)},list:async(o,i)=>{const a=await e.connections.list(o,i);if(!n||o===n)return a;const u=await e.connections.list(n),c=a.connections.map(l=>q(l,u.connections||[],s));return{...a,connections:c}}},clientConnections:{...e.clientConnections,listByClient:async(o,i)=>{let a=await e.clientConnections.listByClient(o,i);if(a.length===0&&(a=(await e.connections.list(o)).connections||[]),!n||o===n)return a;const u=await e.connections.list(n);return a.map(c=>q(c,u.connections||[],s))}},clients:{...e.clients,get:async(o,i)=>{const a=await e.clients.get(o,i);if(!a)return null;if(!n||!r||o===n&&i===r)return a;const u=await e.clients.get(n,r);return W(a,u)},getByClientId:async o=>{const i=await e.clients.getByClientId(o);if(!i)return null;if(!n||!r||i.tenant_id===n&&i.client_id===r)return i;const a=await e.clients.get(n,r);return{...W(i,a),tenant_id:i.tenant_id}}},emailProviders:{...e.emailProviders,get:async o=>{const i=await e.emailProviders.get(o);return i||(!n||o===n?null:e.emailProviders.get(n))}}}}function $(e,t){return Z(e,t)}function x(e){return async(t,n)=>{const r=t.var.user;return(r==null?void 0:r.tenant_id)===e&&r.org_name&&t.set("tenant_id",r.org_name),n()}}function ee(e){return async(t,n)=>{if(!e.accessControl)return n();const{controlPlaneTenantId:r}=e.accessControl,s=t.var.org_name,o=t.var.organization_id,i=s||o;let a=t.var.tenant_id;const u=t.var.user,l=(u!=null&&u.aud?Array.isArray(u.aud)?u.aud:[u.aud]:[]).includes(_.MANAGEMENT_API_AUDIENCE);if(!a&&i&&l&&(t.set("tenant_id",i),a=i),!a)throw new I(400,{message:"Tenant ID not found in request"});if(!V(o,a,r,s))throw new I(403,{message:`Access denied to tenant ${a}`});return n()}}function te(e){return async(t,n)=>{if(!e.subdomainRouting)return n();const{baseDomain:r,reservedSubdomains:s=[],resolveSubdomain:o}=e.subdomainRouting,i=t.req.header("host")||"";let a=null;if(i.endsWith(r)){const c=i.slice(0,-(r.length+1));c&&!c.includes(".")&&(a=c)}if(a&&s.includes(a)&&(a=null),!a)return e.accessControl&&t.set("tenant_id",e.accessControl.controlPlaneTenantId),n();let u=null;if(o)u=await o(a);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{const c=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,a);c&&(u=c.id)}catch{}if(!u)throw new I(404,{message:`Tenant not found for subdomain: ${a}`});return t.set("tenant_id",u),n()}}function ne(e){return async(t,n)=>{if(!e.databaseIsolation)return n();const r=t.var.tenant_id;if(!r)throw new I(400,{message:"Tenant ID not found in request"});try{const s=await e.databaseIsolation.getAdapters(r);t.env.data=s}catch(s){throw console.error(`Failed to resolve database for tenant ${r}:`,s),new I(500,{message:"Failed to resolve tenant database"})}return n()}}function E(e){const t=te(e),n=ee(e),r=ne(e);return async(s,o)=>(await t(s,async()=>{}),await n(s,async()=>{}),await r(s,async()=>{}),o())}function ye(e){const{dataAdapter:t,controlPlane:n,controlPlane:{tenantId:r="control_plane",clientId:s}={},sync:o={resourceServers:!0,roles:!0},defaultPermissions:i=["tenant:admin"],requireOrganizationMatch:a=!1,managementApiExtensions:u=[],entityHooks:c,getChildTenantIds:l,getAdapters:g,...d}=e;let f=t,m=t;n&&(f=$(t,{controlPlaneTenantId:r,controlPlaneClientId:s}),m=$(t,{controlPlaneTenantId:r,controlPlaneClientId:s,excludeSensitiveFields:!0}));const w=o!==!1,h=w?{resourceServers:o.resourceServers??!0,roles:o.roles??!0}:{resourceServers:!1,roles:!1},T={controlPlaneTenantId:r,getChildTenantIds:l??(async()=>(await _.fetchAll(M=>f.tenants.list(M),"tenants",{cursorField:"id",pageSize:100})).filter(M=>M.id!==r).map(M=>M.id)),getAdapters:g??(async()=>f),getControlPlaneAdapters:async()=>f,sync:h},{entityHooks:C,tenantHooks:P}=X(T),v={resourceServers:[C.resourceServers,...(c==null?void 0:c.resourceServers)??[]],roles:[C.roles,...(c==null?void 0:c.roles)??[]],connections:(c==null?void 0:c.connections)??[],tenants:(c==null?void 0:c.tenants)??[],rolePermissions:(c==null?void 0:c.rolePermissions)??[]},A=O({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:a,defaultPermissions:i}},{tenants:P}),{app:b}=_.init({dataAdapter:f,managementDataAdapter:m,...d,entityHooks:v,managementApiExtensions:[...u,{path:"/tenants",router:A}]});return b.use("/api/v2/*",x(r)),w&&b.use("/api/v2/*",Y()),{app:b,controlPlaneTenantId:r}}function he(e){const t=D(e);return{name:"multi-tenancy",middleware:E(e),hooks:t,routes:[{path:"/management",handler:O(e,t)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),e.accessControl&&console.log(` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`),e.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`),e.databaseIsolation&&console.log(" - Database isolation enabled")}}}function D(e){const t=e.accessControl?K(e.accessControl):{},n=e.databaseIsolation?Q(e.databaseIsolation):{},r=J(e);return{...t,...n,tenants:r}}function re(e){const t=new ie.Hono,n=D(e);return t.route("/tenants",O(e,n)),t}function ve(e){return{hooks:D(e),middleware:E(e),app:re(e),config:e,wrapAdapters:(t,n)=>{var r;return $(t,{controlPlaneTenantId:(r=e.accessControl)==null?void 0:r.controlPlaneTenantId,controlPlaneClientId:n==null?void 0:n.controlPlaneClientId})}}}exports.createAccessControlHooks=K;exports.createAccessControlMiddleware=ee;exports.createControlPlaneTenantMiddleware=x;exports.createDatabaseHooks=Q;exports.createDatabaseMiddleware=ne;exports.createMultiTenancy=re;exports.createMultiTenancyHooks=D;exports.createMultiTenancyMiddleware=E;exports.createMultiTenancyPlugin=he;exports.createProtectSyncedMiddleware=Y;exports.createProvisioningHooks=J;exports.createRuntimeFallbackAdapter=Z;exports.createSubdomainMiddleware=te;exports.createSyncHooks=X;exports.createTenantsOpenAPIRouter=O;exports.initMultiTenant=ye;exports.setupMultiTenancy=ve;exports.validateTenantAccess=V;exports.withRuntimeFallback=$;
|
|
1
|
+
"use strict";var se=Object.defineProperty;var oe=(e,t,n)=>t in e?se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var D=(e,t,n)=>oe(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ie=require("hono"),T=require("authhero"),I=require("@hono/zod-openapi");function K(e){const{controlPlaneTenantId:t,requireOrganizationMatch:n=!0}=e;return{async onTenantAccessValidation(r,a){if(a===t)return!0;if(n){const s=r.var.org_name,o=r.var.organization_id,i=s||o;return i?i.toLowerCase()===a.toLowerCase():!1}return!0}}}function Q(e,t,n,r){if(t===n)return!0;const a=r||e;return a?a.toLowerCase()===t.toLowerCase():!1}function V(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(n){console.error(`Failed to resolve data adapters for tenant ${t}:`,n);return}}}}function ce(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function J(e){return{async beforeCreate(t,n){return!n.audience&&n.id?{...n,audience:ce(n.id)}:n},async afterCreate(t,n){const{accessControl:r,databaseIsolation:a}=e;r&&t.ctx&&await le(t,n,r),a!=null&&a.onProvision&&await a.onProvision(n.id)},async beforeDelete(t,n){const{accessControl:r,databaseIsolation:a}=e;if(r)try{const o=(await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(i=>i.name===n);o&&await t.adapters.organizations.remove(r.controlPlaneTenantId,o.id)}catch(s){console.warn(`Failed to remove organization for tenant ${n}:`,s)}if(a!=null&&a.onDeprovision)try{await a.onDeprovision(n)}catch(s){console.warn(`Failed to deprovision database for tenant ${n}:`,s)}}}}async function le(e,t,n){const{controlPlaneTenantId:r,defaultPermissions:a,defaultRoles:s,issuer:o,adminRoleName:i="Tenant Admin",adminRoleDescription:u="Full access to all tenant management operations",addCreatorToOrganization:c=!0}=n,l=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id});let g;if(o&&(g=await de(e,r,i,u)),c&&e.ctx){const d=e.ctx.var.user;if(d!=null&&d.sub&&!await ue(e,r,d.sub))try{await e.adapters.userOrganizations.create(r,{user_id:d.sub,organization_id:l.id}),g&&await e.adapters.userRoles.create(r,d.sub,g,l.id)}catch(m){console.warn(`Failed to add creator ${d.sub} to organization ${l.id}:`,m)}}s&&s.length>0&&console.log(`Would assign roles ${s.join(", ")} to organization ${l.id}`),a&&a.length>0&&console.log(`Would grant permissions ${a.join(", ")} to organization ${l.id}`)}async function ue(e,t,n){const r=await e.adapters.userRoles.list(t,n,void 0,"");for(const a of r)if((await e.adapters.rolePermissions.list(t,a.id,{per_page:1e3})).some(i=>i.permission_name==="admin:organizations"))return!0;return!1}async function de(e,t,n,r){const s=(await e.adapters.roles.list(t,{})).roles.find(c=>c.name===n);if(s)return s.id;const o=await e.adapters.roles.create(t,{name:n,description:r}),i=T.MANAGEMENT_API_AUDIENCE,u=T.MANAGEMENT_API_SCOPES.map(c=>({role_id:o.id,resource_server_identifier:i,permission_name:c.value}));return await e.adapters.rolePermissions.assign(t,o.id,u),o.id}function H(e,t,n=()=>!0){const{controlPlaneTenantId:r,getChildTenantIds:a,getAdapters:s}=e,o=new Map;async function i(l,g,d){return(await t(l).list(g,{q:`name:${d}`,per_page:1}))[0]??null}async function u(l){const g=await a(),d=t(await s(r));await Promise.all(g.map(async f=>{try{const m=await s(f),w=t(m),p={...d.transform(l),is_system:!0},y=await i(m,f,l.name),_=y?w.getId(y):void 0;if(y&&_){const C=w.preserveOnUpdate?w.preserveOnUpdate(y,p):p;await w.update(f,_,C)}else await w.create(f,p)}catch(m){console.error(`Failed to sync ${d.listKey} "${l.name}" to tenant "${f}":`,m)}}))}async function c(l){const g=await a();await Promise.all(g.map(async d=>{try{const f=await s(d),m=t(f),w=await i(f,d,l),h=w?m.getId(w):void 0;w&&h&&await m.remove(d,h)}catch(f){console.error(`Failed to delete entity "${l}" from tenant "${d}":`,f)}}))}return{afterCreate:async(l,g)=>{l.tenantId===r&&n(g)&&await u(g)},afterUpdate:async(l,g,d)=>{l.tenantId===r&&n(d)&&await u(d)},beforeDelete:async(l,g)=>{if(l.tenantId!==r)return;const f=await t(l.adapters).get(l.tenantId,g);f&&n(f)&&o.set(g,f)},afterDelete:async(l,g)=>{if(l.tenantId!==r)return;const d=o.get(g);d&&(o.delete(g),await c(d.name))}}}function G(e,t,n=()=>!0){const{controlPlaneTenantId:r,getControlPlaneAdapters:a,getAdapters:s}=e;return{async afterCreate(o,i){if(i.id!==r)try{const u=await a(),c=await s(i.id),l=t(u),g=t(c),d=await T.fetchAll(f=>l.listPaginated(r,f),l.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(f=>n(f)).map(async f=>{try{const m=l.transform(f);await g.create(i.id,{...m,is_system:!0})}catch(m){console.error(`Failed to sync entity to new tenant "${i.id}":`,m)}}))}catch(u){console.error(`Failed to sync entities to new tenant "${i.id}":`,u)}}}}const B=e=>({list:async(t,n)=>(await e.resourceServers.list(t,n)).resource_servers,listPaginated:(t,n)=>e.resourceServers.list(t,n),get:(t,n)=>e.resourceServers.get(t,n),create:(t,n)=>e.resourceServers.create(t,n),update:(t,n,r)=>e.resourceServers.update(t,n,r),remove:(t,n)=>e.resourceServers.remove(t,n),listKey:"resource_servers",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,identifier:t.identifier,scopes:t.scopes,signing_alg:t.signing_alg,token_lifetime:t.token_lifetime,token_lifetime_for_web:t.token_lifetime_for_web})}),U=e=>({list:async(t,n)=>(await e.roles.list(t,n)).roles,listPaginated:(t,n)=>e.roles.list(t,n),get:(t,n)=>e.roles.get(t,n),create:(t,n)=>e.roles.create(t,n),update:(t,n,r)=>e.roles.update(t,n,r),remove:(t,n)=>e.roles.remove(t,n),listKey:"roles",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,description:t.description})});function L(e){var t;return((t=e.metadata)==null?void 0:t.sync)!==!1}function X(e){const{sync:t={},filters:n={}}=e,r=t.resourceServers??!0,a=t.roles??!0,s=m=>L(m)?n.resourceServers?n.resourceServers(m):!0:!1,o=m=>L(m)?n.roles?n.roles(m):!0:!1,i=r?H(e,B,s):void 0,u=a?H(e,U,o):void 0,c=r?G(e,B,s):void 0,l=a?G(e,U,o):void 0,g=a?{async afterCreate(m,w){var h;if(w.id!==e.controlPlaneTenantId){await((h=l==null?void 0:l.afterCreate)==null?void 0:h.call(l,m,w));try{const p=await e.getControlPlaneAdapters(),y=await e.getAdapters(w.id),_=await T.fetchAll(P=>p.roles.list(e.controlPlaneTenantId,P),"roles",{cursorField:"id",pageSize:100}),C=new Map;for(const P of _.filter(v=>{var A;return((A=n.roles)==null?void 0:A.call(n,v))??!0})){const v=await d(y,w.id,P.name);v&&C.set(P.name,v.id)}for(const P of _.filter(v=>{var A;return((A=n.roles)==null?void 0:A.call(n,v))??!0})){const v=C.get(P.name);if(v)try{const A=await p.rolePermissions.list(e.controlPlaneTenantId,P.id,{});A.length>0&&await y.rolePermissions.assign(w.id,v,A.map(b=>({role_id:v,resource_server_identifier:b.resource_server_identifier,permission_name:b.permission_name})))}catch(A){console.error(`Failed to sync permissions for role "${P.name}" to tenant "${w.id}":`,A)}}}catch(p){console.error(`Failed to sync role permissions to tenant "${w.id}":`,p)}}}}:void 0;async function d(m,w,h){return(await m.roles.list(w,{q:`name:${h}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:i,roles:u},tenantHooks:{async afterCreate(m,w){const h=[c==null?void 0:c.afterCreate,(g==null?void 0:g.afterCreate)??(l==null?void 0:l.afterCreate)],p=[];for(const y of h)if(y)try{await y(m,w)}catch(_){p.push(_ instanceof Error?_:new Error(String(_)))}if(p.length===1)throw p[0];if(p.length>1)throw new AggregateError(p,p.map(y=>y.message).join("; "))}}}}var S=class extends Error{constructor(t=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});D(this,"res");D(this,"status");this.res=n==null?void 0:n.res,this.status=t}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function F(e,t){const n=new I.OpenAPIHono;return n.openapi(I.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:T.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:I.z.object({tenants:I.z.array(T.tenantSchema),start:I.z.number().optional(),limit:I.z.number().optional(),length:I.z.number().optional()})}},description:"List of tenants"}}}),async r=>{var m,w,h,p,y,_;const a=r.req.valid("query"),{page:s,per_page:o,include_totals:i,q:u}=a,c=r.var.user,l=(c==null?void 0:c.permissions)||[];if(l.includes("auth:read")||l.includes("admin:organizations")){const C=await r.env.data.tenants.list({page:s,per_page:o,include_totals:i,q:u});return i?r.json({tenants:C.tenants,start:((m=C.totals)==null?void 0:m.start)??0,limit:((w=C.totals)==null?void 0:w.limit)??o,length:C.tenants.length}):r.json({tenants:C.tenants})}const d=((h=e.accessControl)==null?void 0:h.controlPlaneTenantId)??((p=r.env.data.multiTenancyConfig)==null?void 0:p.controlPlaneTenantId);if(d&&(c!=null&&c.sub)){const P=(await T.fetchAll(R=>r.env.data.userOrganizations.listUserOrganizations(d,c.sub,R),"organizations")).map(R=>R.name);if(P.length===0)return i?r.json({tenants:[],start:0,limit:o??50,length:0}):r.json({tenants:[]});const v=P.length,A=s??0,b=o??50,z=A*b,M=P.slice(z,z+b);if(M.length===0)return i?r.json({tenants:[],start:z,limit:b,length:v}):r.json({tenants:[]});const E=M.map(R=>`id:${R}`).join(" OR "),ae=u?`(${E}) AND (${u})`:E,N=await r.env.data.tenants.list({q:ae,per_page:b,include_totals:!1});return i?r.json({tenants:N.tenants,start:z,limit:b,length:v}):r.json({tenants:N.tenants})}const f=await r.env.data.tenants.list({page:s,per_page:o,include_totals:i,q:u});return i?r.json({tenants:f.tenants,start:((y=f.totals)==null?void 0:y.start)??0,limit:((_=f.totals)==null?void 0:_.limit)??o,length:f.tenants.length}):r.json({tenants:f.tenants})}),n.openapi(I.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:T.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:T.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async r=>{var u,c;const a=r.var.user;if(!(a!=null&&a.sub))throw new S(401,{message:"Authentication required to create tenants"});let s=r.req.valid("json");const o={adapters:r.env.data,ctx:r};(u=t.tenants)!=null&&u.beforeCreate&&(s=await t.tenants.beforeCreate(o,s));const i=await r.env.data.tenants.create(s);return(c=t.tenants)!=null&&c.afterCreate&&await t.tenants.afterCreate(o,i),r.json(i,201)}),n.openapi(I.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:I.z.object({id:I.z.string()})},security:[{Bearer:["delete:tenants"]}],responses:{204:{description:"Tenant deleted"},403:{description:"Access denied or cannot delete the control plane"},404:{description:"Tenant not found"}}}),async r=>{var u,c,l,g;const{id:a}=r.req.valid("param"),s=((u=e.accessControl)==null?void 0:u.controlPlaneTenantId)??((c=r.env.data.multiTenancyConfig)==null?void 0:c.controlPlaneTenantId);if(s){const d=r.var.user;if(!(d!=null&&d.sub))throw new S(401,{message:"Authentication required"});if(a===s)throw new S(403,{message:"Cannot delete the control plane"});if(!(await T.fetchAll(w=>r.env.data.userOrganizations.listUserOrganizations(s,d.sub,w),"organizations")).some(w=>w.name===a))throw new S(403,{message:"Access denied to this tenant"})}if(!await r.env.data.tenants.get(a))throw new S(404,{message:"Tenant not found"});const i={adapters:r.env.data,ctx:r};return(l=t.tenants)!=null&&l.beforeDelete&&await t.tenants.beforeDelete(i,a),await r.env.data.tenants.remove(a),(g=t.tenants)!=null&&g.afterDelete&&await t.tenants.afterDelete(i,a),r.body(null,204)}),n}function fe(e){const t=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:n,type:r}of t){const a=e.match(n);if(a&&a[1])return{type:r,id:a[1]}}return null}async function me(e,t,n){try{switch(n.type){case"resource_server":{const r=await e.resourceServers.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"role":{const r=await e.roles.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"connection":{const r=await e.connections.get(t,n.id);return(r==null?void 0:r.is_system)===!0}default:return!1}}catch{return!1}}function ge(e){return{resource_server:"resource server",role:"role",connection:"connection"}[e]}function Y(){return async(e,t)=>{if(!["PATCH","PUT","DELETE"].includes(e.req.method))return t();const n=fe(e.req.path);if(!n)return t();const r=e.var.tenant_id||e.req.header("x-tenant-id")||e.req.header("tenant-id");if(!r)return t();if(await me(e.env.data,r,n))throw new S(403,{message:`This ${ge(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function q(e,t){const n=t.find(a=>a.strategy===e.strategy);if(!(n!=null&&n.options))return e;const r=T.connectionSchema.passthrough().parse({...n,...e});return r.options=T.connectionOptionsSchema.passthrough().parse({...n.options||{},...e.options}),r}function $(e,t){const n=[...t||[],...e||[]];return[...new Set(n)]}function W(e,t){return t?{...e,callbacks:$(e.callbacks,t.callbacks),web_origins:$(e.web_origins,t.web_origins),allowed_logout_urls:$(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:$(e.allowed_origins,t.allowed_origins)}:e}function Z(e,t){const{controlPlaneTenantId:n,controlPlaneClientId:r}=t;return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r},connections:{...e.connections,get:async(a,s)=>{const o=await e.connections.get(a,s);if(!o||!n||a===n)return o;const i=await e.connections.list(n);return q(o,i.connections||[])},list:async(a,s)=>{const o=await e.connections.list(a,s);if(!n||a===n)return o;const i=await e.connections.list(n),u=o.connections.map(c=>q(c,i.connections||[]));return{...o,connections:u}}},clientConnections:{...e.clientConnections,listByClient:async(a,s)=>{let o=await e.clientConnections.listByClient(a,s);if(o.length===0&&(o=(await e.connections.list(a)).connections||[]),!n||a===n)return o;const i=await e.connections.list(n);return o.map(u=>q(u,i.connections||[]))}},clients:{...e.clients,get:async(a,s)=>{const o=await e.clients.get(a,s);if(!o)return null;if(!n||!r||a===n&&s===r)return o;const i=await e.clients.get(n,r);return W(o,i)},getByClientId:async a=>{const s=await e.clients.getByClientId(a);if(!s)return null;if(!n||!r||s.tenant_id===n&&s.client_id===r)return s;const o=await e.clients.get(n,r);return{...W(s,o),tenant_id:s.tenant_id}}},emailProviders:{...e.emailProviders,get:async a=>{const s=await e.emailProviders.get(a);return s||(!n||a===n?null:e.emailProviders.get(n))}}}}function k(e,t){return Z(e,t)}function x(e){return async(t,n)=>{const r=t.var.user;return(r==null?void 0:r.tenant_id)===e&&r.org_name&&t.set("tenant_id",r.org_name),n()}}function ee(e){return async(t,n)=>{if(!e.accessControl)return n();const{controlPlaneTenantId:r}=e.accessControl,a=t.var.org_name,s=t.var.organization_id,o=a||s;let i=t.var.tenant_id;const u=t.var.user,l=(u!=null&&u.aud?Array.isArray(u.aud)?u.aud:[u.aud]:[]).includes(T.MANAGEMENT_API_AUDIENCE);if(!i&&o&&l&&(t.set("tenant_id",o),i=o),!i)throw new S(400,{message:"Tenant ID not found in request"});if(!Q(s,i,r,a))throw new S(403,{message:`Access denied to tenant ${i}`});return n()}}function te(e){return async(t,n)=>{if(!e.subdomainRouting)return n();const{baseDomain:r,reservedSubdomains:a=[],resolveSubdomain:s}=e.subdomainRouting,o=t.req.header("host")||"";let i=null;if(o.endsWith(r)){const c=o.slice(0,-(r.length+1));c&&!c.includes(".")&&(i=c)}if(i&&a.includes(i)&&(i=null),!i)return e.accessControl&&t.set("tenant_id",e.accessControl.controlPlaneTenantId),n();let u=null;if(s)u=await s(i);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{const c=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,i);c&&(u=c.id)}catch{}if(!u)throw new S(404,{message:`Tenant not found for subdomain: ${i}`});return t.set("tenant_id",u),n()}}function ne(e){return async(t,n)=>{if(!e.databaseIsolation)return n();const r=t.var.tenant_id;if(!r)throw new S(400,{message:"Tenant ID not found in request"});try{const a=await e.databaseIsolation.getAdapters(r);t.env.data=a}catch(a){throw console.error(`Failed to resolve database for tenant ${r}:`,a),new S(500,{message:"Failed to resolve tenant database"})}return n()}}function j(e){const t=te(e),n=ee(e),r=ne(e);return async(a,s)=>(await t(a,async()=>{}),await n(a,async()=>{}),await r(a,async()=>{}),s())}function we(e){const{dataAdapter:t,controlPlane:n,controlPlane:{tenantId:r="control_plane",clientId:a}={},sync:s={resourceServers:!0,roles:!0},defaultPermissions:o=["tenant:admin"],requireOrganizationMatch:i=!1,managementApiExtensions:u=[],entityHooks:c,getChildTenantIds:l,getAdapters:g,...d}=e;let f=t,m=t;n&&(f=k(t,{controlPlaneTenantId:r,controlPlaneClientId:a}),m={...t,multiTenancyConfig:{controlPlaneTenantId:r,controlPlaneClientId:a}});const w=s!==!1,h=w?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},_={controlPlaneTenantId:r,getChildTenantIds:l??(async()=>(await T.fetchAll(M=>f.tenants.list(M),"tenants",{cursorField:"id",pageSize:100})).filter(M=>M.id!==r).map(M=>M.id)),getAdapters:g??(async()=>f),getControlPlaneAdapters:async()=>f,sync:h},{entityHooks:C,tenantHooks:P}=X(_),v={resourceServers:[C.resourceServers,...(c==null?void 0:c.resourceServers)??[]],roles:[C.roles,...(c==null?void 0:c.roles)??[]],connections:(c==null?void 0:c.connections)??[],tenants:(c==null?void 0:c.tenants)??[],rolePermissions:(c==null?void 0:c.rolePermissions)??[]},A=F({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:i,defaultPermissions:o}},{tenants:P}),{app:b}=T.init({dataAdapter:f,managementDataAdapter:m,...d,entityHooks:v,managementApiExtensions:[...u,{path:"/tenants",router:A}]});return b.use("/api/v2/*",x(r)),w&&b.use("/api/v2/*",Y()),{app:b,controlPlaneTenantId:r}}function pe(e){const t=O(e);return{name:"multi-tenancy",middleware:j(e),hooks:t,routes:[{path:"/management",handler:F(e,t)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),e.accessControl&&console.log(` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`),e.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`),e.databaseIsolation&&console.log(" - Database isolation enabled")}}}function O(e){const t=e.accessControl?K(e.accessControl):{},n=e.databaseIsolation?V(e.databaseIsolation):{},r=J(e);return{...t,...n,tenants:r}}function re(e){const t=new ie.Hono,n=O(e);return t.route("/tenants",F(e,n)),t}function ye(e){return{hooks:O(e),middleware:j(e),app:re(e),config:e,wrapAdapters:(t,n)=>{var r;return k(t,{controlPlaneTenantId:(r=e.accessControl)==null?void 0:r.controlPlaneTenantId,controlPlaneClientId:n==null?void 0:n.controlPlaneClientId})}}}exports.createAccessControlHooks=K;exports.createAccessControlMiddleware=ee;exports.createControlPlaneTenantMiddleware=x;exports.createDatabaseHooks=V;exports.createDatabaseMiddleware=ne;exports.createMultiTenancy=re;exports.createMultiTenancyHooks=O;exports.createMultiTenancyMiddleware=j;exports.createMultiTenancyPlugin=pe;exports.createProtectSyncedMiddleware=Y;exports.createProvisioningHooks=J;exports.createRuntimeFallbackAdapter=Z;exports.createSubdomainMiddleware=te;exports.createSyncHooks=X;exports.createTenantsOpenAPIRouter=F;exports.initMultiTenant=we;exports.setupMultiTenancy=ye;exports.validateTenantAccess=Q;exports.withRuntimeFallback=k;
|
package/dist/multi-tenancy.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
var X = Object.defineProperty;
|
|
2
2
|
var Y = (e, t, n) => t in e ? X(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
3
|
-
var
|
|
3
|
+
var O = (e, t, n) => Y(e, typeof t != "symbol" ? t + "" : t, n);
|
|
4
4
|
import { Hono as Z } from "hono";
|
|
5
|
-
import { MANAGEMENT_API_SCOPES as x, MANAGEMENT_API_AUDIENCE as
|
|
5
|
+
import { MANAGEMENT_API_SCOPES as x, MANAGEMENT_API_AUDIENCE as K, fetchAll as R, auth0QuerySchema as ee, tenantSchema as N, tenantInsertSchema as te, connectionSchema as ne, connectionOptionsSchema as re, init as ae } from "authhero";
|
|
6
6
|
import { OpenAPIHono as se, createRoute as D, z as S } from "@hono/zod-openapi";
|
|
7
7
|
function oe(e) {
|
|
8
8
|
const { controlPlaneTenantId: t, requireOrganizationMatch: n = !0 } = e;
|
|
9
9
|
return {
|
|
10
|
-
async onTenantAccessValidation(r,
|
|
11
|
-
if (
|
|
10
|
+
async onTenantAccessValidation(r, a) {
|
|
11
|
+
if (a === t)
|
|
12
12
|
return !0;
|
|
13
13
|
if (n) {
|
|
14
|
-
const
|
|
15
|
-
return
|
|
14
|
+
const s = r.var.org_name, o = r.var.organization_id, i = s || o;
|
|
15
|
+
return i ? i.toLowerCase() === a.toLowerCase() : !1;
|
|
16
16
|
}
|
|
17
17
|
return !0;
|
|
18
18
|
}
|
|
@@ -21,8 +21,8 @@ function oe(e) {
|
|
|
21
21
|
function ie(e, t, n, r) {
|
|
22
22
|
if (t === n)
|
|
23
23
|
return !0;
|
|
24
|
-
const
|
|
25
|
-
return
|
|
24
|
+
const a = r || e;
|
|
25
|
+
return a ? a.toLowerCase() === t.toLowerCase() : !1;
|
|
26
26
|
}
|
|
27
27
|
function ce(e) {
|
|
28
28
|
return {
|
|
@@ -51,33 +51,33 @@ function ue(e) {
|
|
|
51
51
|
} : n;
|
|
52
52
|
},
|
|
53
53
|
async afterCreate(t, n) {
|
|
54
|
-
const { accessControl: r, databaseIsolation:
|
|
55
|
-
r && t.ctx && await de(t, n, r),
|
|
54
|
+
const { accessControl: r, databaseIsolation: a } = e;
|
|
55
|
+
r && t.ctx && await de(t, n, r), a != null && a.onProvision && await a.onProvision(n.id);
|
|
56
56
|
},
|
|
57
57
|
async beforeDelete(t, n) {
|
|
58
|
-
const { accessControl: r, databaseIsolation:
|
|
58
|
+
const { accessControl: r, databaseIsolation: a } = e;
|
|
59
59
|
if (r)
|
|
60
60
|
try {
|
|
61
|
-
const
|
|
61
|
+
const o = (await t.adapters.organizations.list(
|
|
62
62
|
r.controlPlaneTenantId
|
|
63
|
-
)).organizations.find((
|
|
64
|
-
|
|
63
|
+
)).organizations.find((i) => i.name === n);
|
|
64
|
+
o && await t.adapters.organizations.remove(
|
|
65
65
|
r.controlPlaneTenantId,
|
|
66
|
-
|
|
66
|
+
o.id
|
|
67
67
|
);
|
|
68
|
-
} catch (
|
|
68
|
+
} catch (s) {
|
|
69
69
|
console.warn(
|
|
70
70
|
`Failed to remove organization for tenant ${n}:`,
|
|
71
|
-
|
|
71
|
+
s
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
|
-
if (
|
|
74
|
+
if (a != null && a.onDeprovision)
|
|
75
75
|
try {
|
|
76
|
-
await
|
|
77
|
-
} catch (
|
|
76
|
+
await a.onDeprovision(n);
|
|
77
|
+
} catch (s) {
|
|
78
78
|
console.warn(
|
|
79
79
|
`Failed to deprovision database for tenant ${n}:`,
|
|
80
|
-
|
|
80
|
+
s
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -86,10 +86,10 @@ function ue(e) {
|
|
|
86
86
|
async function de(e, t, n) {
|
|
87
87
|
const {
|
|
88
88
|
controlPlaneTenantId: r,
|
|
89
|
-
defaultPermissions:
|
|
90
|
-
defaultRoles:
|
|
91
|
-
issuer:
|
|
92
|
-
adminRoleName:
|
|
89
|
+
defaultPermissions: a,
|
|
90
|
+
defaultRoles: s,
|
|
91
|
+
issuer: o,
|
|
92
|
+
adminRoleName: i = "Tenant Admin",
|
|
93
93
|
adminRoleDescription: u = "Full access to all tenant management operations",
|
|
94
94
|
addCreatorToOrganization: c = !0
|
|
95
95
|
} = n, l = await e.adapters.organizations.create(
|
|
@@ -100,10 +100,10 @@ async function de(e, t, n) {
|
|
|
100
100
|
}
|
|
101
101
|
);
|
|
102
102
|
let g;
|
|
103
|
-
if (
|
|
103
|
+
if (o && (g = await me(
|
|
104
104
|
e,
|
|
105
105
|
r,
|
|
106
|
-
|
|
106
|
+
i,
|
|
107
107
|
u
|
|
108
108
|
)), c && e.ctx) {
|
|
109
109
|
const d = e.ctx.var.user;
|
|
@@ -130,10 +130,10 @@ async function de(e, t, n) {
|
|
|
130
130
|
);
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
|
|
134
|
-
`Would assign roles ${
|
|
135
|
-
),
|
|
136
|
-
`Would grant permissions ${
|
|
133
|
+
s && s.length > 0 && console.log(
|
|
134
|
+
`Would assign roles ${s.join(", ")} to organization ${l.id}`
|
|
135
|
+
), a && a.length > 0 && console.log(
|
|
136
|
+
`Would grant permissions ${a.join(", ")} to organization ${l.id}`
|
|
137
137
|
);
|
|
138
138
|
}
|
|
139
139
|
async function fe(e, t, n) {
|
|
@@ -144,52 +144,52 @@ async function fe(e, t, n) {
|
|
|
144
144
|
""
|
|
145
145
|
// Empty string for global roles
|
|
146
146
|
);
|
|
147
|
-
for (const
|
|
147
|
+
for (const a of r)
|
|
148
148
|
if ((await e.adapters.rolePermissions.list(
|
|
149
149
|
t,
|
|
150
|
-
|
|
150
|
+
a.id,
|
|
151
151
|
{ per_page: 1e3 }
|
|
152
152
|
)).some(
|
|
153
|
-
(
|
|
153
|
+
(i) => i.permission_name === "admin:organizations"
|
|
154
154
|
))
|
|
155
155
|
return !0;
|
|
156
156
|
return !1;
|
|
157
157
|
}
|
|
158
158
|
async function me(e, t, n, r) {
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
161
|
-
return
|
|
162
|
-
const
|
|
159
|
+
const s = (await e.adapters.roles.list(t, {})).roles.find((c) => c.name === n);
|
|
160
|
+
if (s)
|
|
161
|
+
return s.id;
|
|
162
|
+
const o = await e.adapters.roles.create(t, {
|
|
163
163
|
name: n,
|
|
164
164
|
description: r
|
|
165
|
-
}),
|
|
166
|
-
role_id:
|
|
167
|
-
resource_server_identifier:
|
|
165
|
+
}), i = K, u = x.map((c) => ({
|
|
166
|
+
role_id: o.id,
|
|
167
|
+
resource_server_identifier: i,
|
|
168
168
|
permission_name: c.value
|
|
169
169
|
}));
|
|
170
170
|
return await e.adapters.rolePermissions.assign(
|
|
171
171
|
t,
|
|
172
|
-
|
|
172
|
+
o.id,
|
|
173
173
|
u
|
|
174
|
-
),
|
|
174
|
+
), o.id;
|
|
175
175
|
}
|
|
176
|
-
function
|
|
177
|
-
const { controlPlaneTenantId: r, getChildTenantIds:
|
|
178
|
-
async function
|
|
176
|
+
function H(e, t, n = () => !0) {
|
|
177
|
+
const { controlPlaneTenantId: r, getChildTenantIds: a, getAdapters: s } = e, o = /* @__PURE__ */ new Map();
|
|
178
|
+
async function i(l, g, d) {
|
|
179
179
|
return (await t(l).list(g, {
|
|
180
180
|
q: `name:${d}`,
|
|
181
181
|
per_page: 1
|
|
182
182
|
}))[0] ?? null;
|
|
183
183
|
}
|
|
184
184
|
async function u(l) {
|
|
185
|
-
const g = await
|
|
185
|
+
const g = await a(), d = t(await s(r));
|
|
186
186
|
await Promise.all(
|
|
187
187
|
g.map(async (f) => {
|
|
188
188
|
try {
|
|
189
|
-
const m = await
|
|
189
|
+
const m = await s(f), w = t(m), p = {
|
|
190
190
|
...d.transform(l),
|
|
191
191
|
is_system: !0
|
|
192
|
-
}, y = await
|
|
192
|
+
}, y = await i(m, f, l.name), _ = y ? w.getId(y) : void 0;
|
|
193
193
|
if (y && _) {
|
|
194
194
|
const T = w.preserveOnUpdate ? w.preserveOnUpdate(y, p) : p;
|
|
195
195
|
await w.update(f, _, T);
|
|
@@ -205,11 +205,11 @@ function B(e, t, n = () => !0) {
|
|
|
205
205
|
);
|
|
206
206
|
}
|
|
207
207
|
async function c(l) {
|
|
208
|
-
const g = await
|
|
208
|
+
const g = await a();
|
|
209
209
|
await Promise.all(
|
|
210
210
|
g.map(async (d) => {
|
|
211
211
|
try {
|
|
212
|
-
const f = await
|
|
212
|
+
const f = await s(d), m = t(f), w = await i(f, d, l), h = w ? m.getId(w) : void 0;
|
|
213
213
|
w && h && await m.remove(d, h);
|
|
214
214
|
} catch (f) {
|
|
215
215
|
console.error(
|
|
@@ -230,22 +230,22 @@ function B(e, t, n = () => !0) {
|
|
|
230
230
|
beforeDelete: async (l, g) => {
|
|
231
231
|
if (l.tenantId !== r) return;
|
|
232
232
|
const f = await t(l.adapters).get(l.tenantId, g);
|
|
233
|
-
f && n(f) &&
|
|
233
|
+
f && n(f) && o.set(g, f);
|
|
234
234
|
},
|
|
235
235
|
afterDelete: async (l, g) => {
|
|
236
236
|
if (l.tenantId !== r) return;
|
|
237
|
-
const d =
|
|
238
|
-
d && (
|
|
237
|
+
const d = o.get(g);
|
|
238
|
+
d && (o.delete(g), await c(d.name));
|
|
239
239
|
}
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
|
-
function
|
|
243
|
-
const { controlPlaneTenantId: r, getControlPlaneAdapters:
|
|
242
|
+
function B(e, t, n = () => !0) {
|
|
243
|
+
const { controlPlaneTenantId: r, getControlPlaneAdapters: a, getAdapters: s } = e;
|
|
244
244
|
return {
|
|
245
|
-
async afterCreate(
|
|
246
|
-
if (
|
|
245
|
+
async afterCreate(o, i) {
|
|
246
|
+
if (i.id !== r)
|
|
247
247
|
try {
|
|
248
|
-
const u = await
|
|
248
|
+
const u = await a(), c = await s(i.id), l = t(u), g = t(c), d = await R(
|
|
249
249
|
(f) => l.listPaginated(r, f),
|
|
250
250
|
l.listKey,
|
|
251
251
|
{ cursorField: "id", pageSize: 100 }
|
|
@@ -254,13 +254,13 @@ function G(e, t, n = () => !0) {
|
|
|
254
254
|
d.filter((f) => n(f)).map(async (f) => {
|
|
255
255
|
try {
|
|
256
256
|
const m = l.transform(f);
|
|
257
|
-
await g.create(
|
|
257
|
+
await g.create(i.id, {
|
|
258
258
|
...m,
|
|
259
259
|
is_system: !0
|
|
260
260
|
});
|
|
261
261
|
} catch (m) {
|
|
262
262
|
console.error(
|
|
263
|
-
`Failed to sync entity to new tenant "${
|
|
263
|
+
`Failed to sync entity to new tenant "${i.id}":`,
|
|
264
264
|
m
|
|
265
265
|
);
|
|
266
266
|
}
|
|
@@ -268,14 +268,14 @@ function G(e, t, n = () => !0) {
|
|
|
268
268
|
);
|
|
269
269
|
} catch (u) {
|
|
270
270
|
console.error(
|
|
271
|
-
`Failed to sync entities to new tenant "${
|
|
271
|
+
`Failed to sync entities to new tenant "${i.id}":`,
|
|
272
272
|
u
|
|
273
273
|
);
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
|
-
const
|
|
278
|
+
const G = (e) => ({
|
|
279
279
|
list: async (t, n) => (await e.resourceServers.list(t, n)).resource_servers,
|
|
280
280
|
listPaginated: (t, n) => e.resourceServers.list(t, n),
|
|
281
281
|
get: (t, n) => e.resourceServers.get(t, n),
|
|
@@ -308,34 +308,34 @@ const L = (e) => ({
|
|
|
308
308
|
description: t.description
|
|
309
309
|
})
|
|
310
310
|
});
|
|
311
|
-
function
|
|
311
|
+
function L(e) {
|
|
312
312
|
var t;
|
|
313
313
|
return ((t = e.metadata) == null ? void 0 : t.sync) !== !1;
|
|
314
314
|
}
|
|
315
315
|
function ge(e) {
|
|
316
|
-
const { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0,
|
|
316
|
+
const { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, a = t.roles ?? !0, s = (m) => L(m) ? n.resourceServers ? n.resourceServers(m) : !0 : !1, o = (m) => L(m) ? n.roles ? n.roles(m) : !0 : !1, i = r ? H(
|
|
317
317
|
e,
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
) : void 0, u =
|
|
318
|
+
G,
|
|
319
|
+
s
|
|
320
|
+
) : void 0, u = a ? H(
|
|
321
321
|
e,
|
|
322
322
|
U,
|
|
323
|
-
i
|
|
324
|
-
) : void 0, c = r ? G(
|
|
325
|
-
e,
|
|
326
|
-
L,
|
|
327
323
|
o
|
|
328
|
-
) : void 0,
|
|
324
|
+
) : void 0, c = r ? B(
|
|
325
|
+
e,
|
|
326
|
+
G,
|
|
327
|
+
s
|
|
328
|
+
) : void 0, l = a ? B(
|
|
329
329
|
e,
|
|
330
330
|
U,
|
|
331
|
-
|
|
332
|
-
) : void 0, g =
|
|
331
|
+
o
|
|
332
|
+
) : void 0, g = a ? {
|
|
333
333
|
async afterCreate(m, w) {
|
|
334
334
|
var h;
|
|
335
335
|
if (w.id !== e.controlPlaneTenantId) {
|
|
336
336
|
await ((h = l == null ? void 0 : l.afterCreate) == null ? void 0 : h.call(l, m, w));
|
|
337
337
|
try {
|
|
338
|
-
const p = await e.getControlPlaneAdapters(), y = await e.getAdapters(w.id), _ = await
|
|
338
|
+
const p = await e.getControlPlaneAdapters(), y = await e.getAdapters(w.id), _ = await R(
|
|
339
339
|
(C) => p.roles.list(
|
|
340
340
|
e.controlPlaneTenantId,
|
|
341
341
|
C
|
|
@@ -403,7 +403,7 @@ function ge(e) {
|
|
|
403
403
|
}
|
|
404
404
|
return {
|
|
405
405
|
entityHooks: {
|
|
406
|
-
resourceServers:
|
|
406
|
+
resourceServers: i,
|
|
407
407
|
roles: u
|
|
408
408
|
},
|
|
409
409
|
tenantHooks: {
|
|
@@ -437,8 +437,8 @@ var b = class extends Error {
|
|
|
437
437
|
*/
|
|
438
438
|
constructor(t = 500, n) {
|
|
439
439
|
super(n == null ? void 0 : n.message, { cause: n == null ? void 0 : n.cause });
|
|
440
|
-
|
|
441
|
-
|
|
440
|
+
O(this, "res");
|
|
441
|
+
O(this, "status");
|
|
442
442
|
this.res = n == null ? void 0 : n.res, this.status = t;
|
|
443
443
|
}
|
|
444
444
|
/**
|
|
@@ -455,7 +455,7 @@ var b = class extends Error {
|
|
|
455
455
|
});
|
|
456
456
|
}
|
|
457
457
|
};
|
|
458
|
-
function
|
|
458
|
+
function q(e, t) {
|
|
459
459
|
const n = new se();
|
|
460
460
|
return n.openapi(
|
|
461
461
|
D({
|
|
@@ -475,7 +475,7 @@ function j(e, t) {
|
|
|
475
475
|
content: {
|
|
476
476
|
"application/json": {
|
|
477
477
|
schema: S.object({
|
|
478
|
-
tenants: S.array(
|
|
478
|
+
tenants: S.array(N),
|
|
479
479
|
start: S.number().optional(),
|
|
480
480
|
limit: S.number().optional(),
|
|
481
481
|
length: S.number().optional()
|
|
@@ -488,24 +488,24 @@ function j(e, t) {
|
|
|
488
488
|
}),
|
|
489
489
|
async (r) => {
|
|
490
490
|
var m, w, h, p, y, _;
|
|
491
|
-
const
|
|
491
|
+
const a = r.req.valid("query"), { page: s, per_page: o, include_totals: i, q: u } = a, c = r.var.user, l = (c == null ? void 0 : c.permissions) || [];
|
|
492
492
|
if (l.includes("auth:read") || l.includes("admin:organizations")) {
|
|
493
493
|
const T = await r.env.data.tenants.list({
|
|
494
|
-
page:
|
|
495
|
-
per_page:
|
|
496
|
-
include_totals:
|
|
494
|
+
page: s,
|
|
495
|
+
per_page: o,
|
|
496
|
+
include_totals: i,
|
|
497
497
|
q: u
|
|
498
498
|
});
|
|
499
|
-
return
|
|
499
|
+
return i ? r.json({
|
|
500
500
|
tenants: T.tenants,
|
|
501
501
|
start: ((m = T.totals) == null ? void 0 : m.start) ?? 0,
|
|
502
|
-
limit: ((w = T.totals) == null ? void 0 : w.limit) ??
|
|
502
|
+
limit: ((w = T.totals) == null ? void 0 : w.limit) ?? o,
|
|
503
503
|
length: T.tenants.length
|
|
504
504
|
}) : r.json({ tenants: T.tenants });
|
|
505
505
|
}
|
|
506
506
|
const d = ((h = e.accessControl) == null ? void 0 : h.controlPlaneTenantId) ?? ((p = r.env.data.multiTenancyConfig) == null ? void 0 : p.controlPlaneTenantId);
|
|
507
507
|
if (d && (c != null && c.sub)) {
|
|
508
|
-
const C = (await
|
|
508
|
+
const C = (await R(
|
|
509
509
|
(z) => r.env.data.userOrganizations.listUserOrganizations(
|
|
510
510
|
d,
|
|
511
511
|
c.sub,
|
|
@@ -514,43 +514,43 @@ function j(e, t) {
|
|
|
514
514
|
"organizations"
|
|
515
515
|
)).map((z) => z.name);
|
|
516
516
|
if (C.length === 0)
|
|
517
|
-
return
|
|
517
|
+
return i ? r.json({
|
|
518
518
|
tenants: [],
|
|
519
519
|
start: 0,
|
|
520
|
-
limit:
|
|
520
|
+
limit: o ?? 50,
|
|
521
521
|
length: 0
|
|
522
522
|
}) : r.json({ tenants: [] });
|
|
523
|
-
const v = C.length, P =
|
|
523
|
+
const v = C.length, P = s ?? 0, A = o ?? 50, $ = P * A, I = C.slice($, $ + A);
|
|
524
524
|
if (I.length === 0)
|
|
525
|
-
return
|
|
525
|
+
return i ? r.json({
|
|
526
526
|
tenants: [],
|
|
527
527
|
start: $,
|
|
528
528
|
limit: A,
|
|
529
529
|
length: v
|
|
530
530
|
}) : r.json({ tenants: [] });
|
|
531
|
-
const
|
|
531
|
+
const k = I.map((z) => `id:${z}`).join(" OR "), J = u ? `(${k}) AND (${u})` : k, E = await r.env.data.tenants.list({
|
|
532
532
|
q: J,
|
|
533
533
|
per_page: A,
|
|
534
534
|
include_totals: !1
|
|
535
535
|
// We calculate totals from accessibleTenantIds
|
|
536
536
|
});
|
|
537
|
-
return
|
|
538
|
-
tenants:
|
|
537
|
+
return i ? r.json({
|
|
538
|
+
tenants: E.tenants,
|
|
539
539
|
start: $,
|
|
540
540
|
limit: A,
|
|
541
541
|
length: v
|
|
542
|
-
}) : r.json({ tenants:
|
|
542
|
+
}) : r.json({ tenants: E.tenants });
|
|
543
543
|
}
|
|
544
544
|
const f = await r.env.data.tenants.list({
|
|
545
|
-
page:
|
|
546
|
-
per_page:
|
|
547
|
-
include_totals:
|
|
545
|
+
page: s,
|
|
546
|
+
per_page: o,
|
|
547
|
+
include_totals: i,
|
|
548
548
|
q: u
|
|
549
549
|
});
|
|
550
|
-
return
|
|
550
|
+
return i ? r.json({
|
|
551
551
|
tenants: f.tenants,
|
|
552
552
|
start: ((y = f.totals) == null ? void 0 : y.start) ?? 0,
|
|
553
|
-
limit: ((_ = f.totals) == null ? void 0 : _.limit) ??
|
|
553
|
+
limit: ((_ = f.totals) == null ? void 0 : _.limit) ?? o,
|
|
554
554
|
length: f.tenants.length
|
|
555
555
|
}) : r.json({ tenants: f.tenants });
|
|
556
556
|
}
|
|
@@ -577,7 +577,7 @@ function j(e, t) {
|
|
|
577
577
|
201: {
|
|
578
578
|
content: {
|
|
579
579
|
"application/json": {
|
|
580
|
-
schema:
|
|
580
|
+
schema: N
|
|
581
581
|
}
|
|
582
582
|
},
|
|
583
583
|
description: "Tenant created"
|
|
@@ -592,19 +592,19 @@ function j(e, t) {
|
|
|
592
592
|
}),
|
|
593
593
|
async (r) => {
|
|
594
594
|
var u, c;
|
|
595
|
-
const
|
|
596
|
-
if (!(
|
|
595
|
+
const a = r.var.user;
|
|
596
|
+
if (!(a != null && a.sub))
|
|
597
597
|
throw new b(401, {
|
|
598
598
|
message: "Authentication required to create tenants"
|
|
599
599
|
});
|
|
600
|
-
let
|
|
601
|
-
const
|
|
600
|
+
let s = r.req.valid("json");
|
|
601
|
+
const o = {
|
|
602
602
|
adapters: r.env.data,
|
|
603
603
|
ctx: r
|
|
604
604
|
};
|
|
605
|
-
(u = t.tenants) != null && u.beforeCreate && (
|
|
606
|
-
const
|
|
607
|
-
return (c = t.tenants) != null && c.afterCreate && await t.tenants.afterCreate(
|
|
605
|
+
(u = t.tenants) != null && u.beforeCreate && (s = await t.tenants.beforeCreate(o, s));
|
|
606
|
+
const i = await r.env.data.tenants.create(s);
|
|
607
|
+
return (c = t.tenants) != null && c.afterCreate && await t.tenants.afterCreate(o, i), r.json(i, 201);
|
|
608
608
|
}
|
|
609
609
|
), n.openapi(
|
|
610
610
|
D({
|
|
@@ -635,38 +635,38 @@ function j(e, t) {
|
|
|
635
635
|
}),
|
|
636
636
|
async (r) => {
|
|
637
637
|
var u, c, l, g;
|
|
638
|
-
const { id:
|
|
639
|
-
if (
|
|
638
|
+
const { id: a } = r.req.valid("param"), s = ((u = e.accessControl) == null ? void 0 : u.controlPlaneTenantId) ?? ((c = r.env.data.multiTenancyConfig) == null ? void 0 : c.controlPlaneTenantId);
|
|
639
|
+
if (s) {
|
|
640
640
|
const d = r.var.user;
|
|
641
641
|
if (!(d != null && d.sub))
|
|
642
642
|
throw new b(401, {
|
|
643
643
|
message: "Authentication required"
|
|
644
644
|
});
|
|
645
|
-
if (
|
|
645
|
+
if (a === s)
|
|
646
646
|
throw new b(403, {
|
|
647
647
|
message: "Cannot delete the control plane"
|
|
648
648
|
});
|
|
649
|
-
if (!(await
|
|
649
|
+
if (!(await R(
|
|
650
650
|
(w) => r.env.data.userOrganizations.listUserOrganizations(
|
|
651
|
-
|
|
651
|
+
s,
|
|
652
652
|
d.sub,
|
|
653
653
|
w
|
|
654
654
|
),
|
|
655
655
|
"organizations"
|
|
656
|
-
)).some((w) => w.name ===
|
|
656
|
+
)).some((w) => w.name === a))
|
|
657
657
|
throw new b(403, {
|
|
658
658
|
message: "Access denied to this tenant"
|
|
659
659
|
});
|
|
660
660
|
}
|
|
661
|
-
if (!await r.env.data.tenants.get(
|
|
661
|
+
if (!await r.env.data.tenants.get(a))
|
|
662
662
|
throw new b(404, {
|
|
663
663
|
message: "Tenant not found"
|
|
664
664
|
});
|
|
665
|
-
const
|
|
665
|
+
const i = {
|
|
666
666
|
adapters: r.env.data,
|
|
667
667
|
ctx: r
|
|
668
668
|
};
|
|
669
|
-
return (l = t.tenants) != null && l.beforeDelete && await t.tenants.beforeDelete(
|
|
669
|
+
return (l = t.tenants) != null && l.beforeDelete && await t.tenants.beforeDelete(i, a), await r.env.data.tenants.remove(a), (g = t.tenants) != null && g.afterDelete && await t.tenants.afterDelete(i, a), r.body(null, 204);
|
|
670
670
|
}
|
|
671
671
|
), n;
|
|
672
672
|
}
|
|
@@ -680,9 +680,9 @@ function we(e) {
|
|
|
680
680
|
{ pattern: /\/api\/v2\/connections\/([^/]+)$/, type: "connection" }
|
|
681
681
|
];
|
|
682
682
|
for (const { pattern: n, type: r } of t) {
|
|
683
|
-
const
|
|
684
|
-
if (
|
|
685
|
-
return { type: r, id:
|
|
683
|
+
const a = e.match(n);
|
|
684
|
+
if (a && a[1])
|
|
685
|
+
return { type: r, id: a[1] };
|
|
686
686
|
}
|
|
687
687
|
return null;
|
|
688
688
|
}
|
|
@@ -732,64 +732,48 @@ function he() {
|
|
|
732
732
|
return t();
|
|
733
733
|
};
|
|
734
734
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
"twilio_token"
|
|
739
|
-
];
|
|
740
|
-
function _e(e) {
|
|
741
|
-
if (!e) return e;
|
|
742
|
-
const t = { ...e };
|
|
743
|
-
for (const n of ve)
|
|
744
|
-
delete t[n];
|
|
745
|
-
return t;
|
|
746
|
-
}
|
|
747
|
-
function M(e, t, n) {
|
|
748
|
-
const r = t.find(
|
|
749
|
-
(i) => i.strategy === e.strategy
|
|
735
|
+
function M(e, t) {
|
|
736
|
+
const n = t.find(
|
|
737
|
+
(a) => a.strategy === e.strategy
|
|
750
738
|
);
|
|
751
|
-
if (!(
|
|
739
|
+
if (!(n != null && n.options))
|
|
752
740
|
return e;
|
|
753
|
-
const
|
|
754
|
-
...
|
|
741
|
+
const r = ne.passthrough().parse({
|
|
742
|
+
...n,
|
|
755
743
|
...e
|
|
756
|
-
})
|
|
757
|
-
return
|
|
758
|
-
...
|
|
744
|
+
});
|
|
745
|
+
return r.options = re.passthrough().parse({
|
|
746
|
+
...n.options || {},
|
|
759
747
|
...e.options
|
|
760
|
-
}),
|
|
748
|
+
}), r;
|
|
761
749
|
}
|
|
762
|
-
function
|
|
750
|
+
function F(e, t) {
|
|
763
751
|
const n = [
|
|
764
752
|
...t || [],
|
|
765
753
|
...e || []
|
|
766
754
|
];
|
|
767
755
|
return [...new Set(n)];
|
|
768
756
|
}
|
|
769
|
-
function
|
|
757
|
+
function W(e, t) {
|
|
770
758
|
return t ? {
|
|
771
759
|
...e,
|
|
772
|
-
callbacks:
|
|
773
|
-
web_origins:
|
|
760
|
+
callbacks: F(e.callbacks, t.callbacks),
|
|
761
|
+
web_origins: F(
|
|
774
762
|
e.web_origins,
|
|
775
763
|
t.web_origins
|
|
776
764
|
),
|
|
777
|
-
allowed_logout_urls:
|
|
765
|
+
allowed_logout_urls: F(
|
|
778
766
|
e.allowed_logout_urls,
|
|
779
767
|
t.allowed_logout_urls
|
|
780
768
|
),
|
|
781
|
-
allowed_origins:
|
|
769
|
+
allowed_origins: F(
|
|
782
770
|
e.allowed_origins,
|
|
783
771
|
t.allowed_origins
|
|
784
772
|
)
|
|
785
773
|
} : e;
|
|
786
774
|
}
|
|
787
|
-
function
|
|
788
|
-
const {
|
|
789
|
-
controlPlaneTenantId: n,
|
|
790
|
-
controlPlaneClientId: r,
|
|
791
|
-
excludeSensitiveFields: s = !1
|
|
792
|
-
} = t;
|
|
775
|
+
function ve(e, t) {
|
|
776
|
+
const { controlPlaneTenantId: n, controlPlaneClientId: r } = t;
|
|
793
777
|
return {
|
|
794
778
|
...e,
|
|
795
779
|
// Store config for use by tenants route access control
|
|
@@ -799,91 +783,88 @@ function Te(e, t) {
|
|
|
799
783
|
},
|
|
800
784
|
connections: {
|
|
801
785
|
...e.connections,
|
|
802
|
-
get: async (
|
|
803
|
-
const
|
|
804
|
-
o,
|
|
805
|
-
i
|
|
806
|
-
);
|
|
807
|
-
if (!a || !n || o === n)
|
|
808
|
-
return a;
|
|
809
|
-
const u = await e.connections.list(n);
|
|
810
|
-
return M(
|
|
786
|
+
get: async (a, s) => {
|
|
787
|
+
const o = await e.connections.get(
|
|
811
788
|
a,
|
|
812
|
-
u.connections || [],
|
|
813
789
|
s
|
|
814
790
|
);
|
|
791
|
+
if (!o || !n || a === n)
|
|
792
|
+
return o;
|
|
793
|
+
const i = await e.connections.list(n);
|
|
794
|
+
return M(
|
|
795
|
+
o,
|
|
796
|
+
i.connections || []
|
|
797
|
+
);
|
|
815
798
|
},
|
|
816
|
-
list: async (
|
|
817
|
-
const
|
|
818
|
-
if (!n ||
|
|
819
|
-
return
|
|
820
|
-
const
|
|
821
|
-
(
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
s
|
|
799
|
+
list: async (a, s) => {
|
|
800
|
+
const o = await e.connections.list(a, s);
|
|
801
|
+
if (!n || a === n)
|
|
802
|
+
return o;
|
|
803
|
+
const i = await e.connections.list(n), u = o.connections.map(
|
|
804
|
+
(c) => M(
|
|
805
|
+
c,
|
|
806
|
+
i.connections || []
|
|
825
807
|
)
|
|
826
808
|
);
|
|
827
809
|
return {
|
|
828
|
-
...
|
|
829
|
-
connections:
|
|
810
|
+
...o,
|
|
811
|
+
connections: u
|
|
830
812
|
};
|
|
831
813
|
}
|
|
832
814
|
},
|
|
833
815
|
clientConnections: {
|
|
834
816
|
...e.clientConnections,
|
|
835
|
-
listByClient: async (
|
|
836
|
-
let
|
|
837
|
-
|
|
838
|
-
|
|
817
|
+
listByClient: async (a, s) => {
|
|
818
|
+
let o = await e.clientConnections.listByClient(
|
|
819
|
+
a,
|
|
820
|
+
s
|
|
839
821
|
);
|
|
840
|
-
if (
|
|
841
|
-
return
|
|
842
|
-
const
|
|
843
|
-
return
|
|
844
|
-
(
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
s
|
|
822
|
+
if (o.length === 0 && (o = (await e.connections.list(a)).connections || []), !n || a === n)
|
|
823
|
+
return o;
|
|
824
|
+
const i = await e.connections.list(n);
|
|
825
|
+
return o.map(
|
|
826
|
+
(u) => M(
|
|
827
|
+
u,
|
|
828
|
+
i.connections || []
|
|
848
829
|
)
|
|
849
830
|
);
|
|
850
831
|
}
|
|
851
832
|
},
|
|
852
833
|
clients: {
|
|
853
834
|
...e.clients,
|
|
854
|
-
get: async (
|
|
855
|
-
const
|
|
856
|
-
if (!
|
|
835
|
+
get: async (a, s) => {
|
|
836
|
+
const o = await e.clients.get(a, s);
|
|
837
|
+
if (!o)
|
|
857
838
|
return null;
|
|
858
|
-
if (!n || !r ||
|
|
859
|
-
return
|
|
860
|
-
const
|
|
839
|
+
if (!n || !r || a === n && s === r)
|
|
840
|
+
return o;
|
|
841
|
+
const i = await e.clients.get(
|
|
861
842
|
n,
|
|
862
843
|
r
|
|
863
844
|
);
|
|
864
|
-
return
|
|
845
|
+
return W(o, i);
|
|
865
846
|
},
|
|
866
|
-
getByClientId: async (
|
|
867
|
-
const
|
|
868
|
-
if (!
|
|
847
|
+
getByClientId: async (a) => {
|
|
848
|
+
const s = await e.clients.getByClientId(a);
|
|
849
|
+
if (!s)
|
|
869
850
|
return null;
|
|
870
|
-
if (!n || !r ||
|
|
871
|
-
return
|
|
872
|
-
const
|
|
851
|
+
if (!n || !r || s.tenant_id === n && s.client_id === r)
|
|
852
|
+
return s;
|
|
853
|
+
const o = await e.clients.get(
|
|
873
854
|
n,
|
|
874
855
|
r
|
|
875
856
|
);
|
|
876
857
|
return {
|
|
877
|
-
...
|
|
878
|
-
tenant_id:
|
|
858
|
+
...W(s, o),
|
|
859
|
+
tenant_id: s.tenant_id
|
|
879
860
|
};
|
|
880
861
|
}
|
|
881
862
|
},
|
|
882
863
|
emailProviders: {
|
|
883
864
|
...e.emailProviders,
|
|
884
|
-
get: async (
|
|
885
|
-
const
|
|
886
|
-
return
|
|
865
|
+
get: async (a) => {
|
|
866
|
+
const s = await e.emailProviders.get(a);
|
|
867
|
+
return s || (!n || a === n ? null : e.emailProviders.get(n));
|
|
887
868
|
}
|
|
888
869
|
}
|
|
889
870
|
// Note: Additional adapters can be extended here for runtime fallback:
|
|
@@ -891,74 +872,74 @@ function Te(e, t) {
|
|
|
891
872
|
// - branding: Fall back to control plane branding/themes
|
|
892
873
|
};
|
|
893
874
|
}
|
|
894
|
-
function
|
|
895
|
-
return
|
|
875
|
+
function Q(e, t) {
|
|
876
|
+
return ve(e, t);
|
|
896
877
|
}
|
|
897
|
-
function
|
|
878
|
+
function _e(e) {
|
|
898
879
|
return async (t, n) => {
|
|
899
880
|
const r = t.var.user;
|
|
900
881
|
return (r == null ? void 0 : r.tenant_id) === e && r.org_name && t.set("tenant_id", r.org_name), n();
|
|
901
882
|
};
|
|
902
883
|
}
|
|
903
|
-
function
|
|
884
|
+
function Te(e) {
|
|
904
885
|
return async (t, n) => {
|
|
905
886
|
if (!e.accessControl)
|
|
906
887
|
return n();
|
|
907
|
-
const { controlPlaneTenantId: r } = e.accessControl,
|
|
908
|
-
let
|
|
909
|
-
const u = t.var.user, l = (u != null && u.aud ? Array.isArray(u.aud) ? u.aud : [u.aud] : []).includes(
|
|
910
|
-
if (!
|
|
888
|
+
const { controlPlaneTenantId: r } = e.accessControl, a = t.var.org_name, s = t.var.organization_id, o = a || s;
|
|
889
|
+
let i = t.var.tenant_id;
|
|
890
|
+
const u = t.var.user, l = (u != null && u.aud ? Array.isArray(u.aud) ? u.aud : [u.aud] : []).includes(K);
|
|
891
|
+
if (!i && o && l && (t.set("tenant_id", o), i = o), !i)
|
|
911
892
|
throw new b(400, {
|
|
912
893
|
message: "Tenant ID not found in request"
|
|
913
894
|
});
|
|
914
895
|
if (!ie(
|
|
915
|
-
|
|
916
|
-
|
|
896
|
+
s,
|
|
897
|
+
i,
|
|
917
898
|
r,
|
|
918
|
-
|
|
899
|
+
a
|
|
919
900
|
))
|
|
920
901
|
throw new b(403, {
|
|
921
|
-
message: `Access denied to tenant ${
|
|
902
|
+
message: `Access denied to tenant ${i}`
|
|
922
903
|
});
|
|
923
904
|
return n();
|
|
924
905
|
};
|
|
925
906
|
}
|
|
926
|
-
function
|
|
907
|
+
function Ce(e) {
|
|
927
908
|
return async (t, n) => {
|
|
928
909
|
if (!e.subdomainRouting)
|
|
929
910
|
return n();
|
|
930
911
|
const {
|
|
931
912
|
baseDomain: r,
|
|
932
|
-
reservedSubdomains:
|
|
933
|
-
resolveSubdomain:
|
|
934
|
-
} = e.subdomainRouting,
|
|
935
|
-
let
|
|
936
|
-
if (
|
|
937
|
-
const c =
|
|
938
|
-
c && !c.includes(".") && (
|
|
913
|
+
reservedSubdomains: a = [],
|
|
914
|
+
resolveSubdomain: s
|
|
915
|
+
} = e.subdomainRouting, o = t.req.header("host") || "";
|
|
916
|
+
let i = null;
|
|
917
|
+
if (o.endsWith(r)) {
|
|
918
|
+
const c = o.slice(0, -(r.length + 1));
|
|
919
|
+
c && !c.includes(".") && (i = c);
|
|
939
920
|
}
|
|
940
|
-
if (
|
|
921
|
+
if (i && a.includes(i) && (i = null), !i)
|
|
941
922
|
return e.accessControl && t.set("tenant_id", e.accessControl.controlPlaneTenantId), n();
|
|
942
923
|
let u = null;
|
|
943
|
-
if (
|
|
944
|
-
u = await
|
|
924
|
+
if (s)
|
|
925
|
+
u = await s(i);
|
|
945
926
|
else if (e.subdomainRouting.useOrganizations !== !1 && e.accessControl)
|
|
946
927
|
try {
|
|
947
928
|
const c = await t.env.data.organizations.get(
|
|
948
929
|
e.accessControl.controlPlaneTenantId,
|
|
949
|
-
|
|
930
|
+
i
|
|
950
931
|
);
|
|
951
932
|
c && (u = c.id);
|
|
952
933
|
} catch {
|
|
953
934
|
}
|
|
954
935
|
if (!u)
|
|
955
936
|
throw new b(404, {
|
|
956
|
-
message: `Tenant not found for subdomain: ${
|
|
937
|
+
message: `Tenant not found for subdomain: ${i}`
|
|
957
938
|
});
|
|
958
939
|
return t.set("tenant_id", u), n();
|
|
959
940
|
};
|
|
960
941
|
}
|
|
961
|
-
function
|
|
942
|
+
function Pe(e) {
|
|
962
943
|
return async (t, n) => {
|
|
963
944
|
if (!e.databaseIsolation)
|
|
964
945
|
return n();
|
|
@@ -968,12 +949,12 @@ function be(e) {
|
|
|
968
949
|
message: "Tenant ID not found in request"
|
|
969
950
|
});
|
|
970
951
|
try {
|
|
971
|
-
const
|
|
972
|
-
t.env.data =
|
|
973
|
-
} catch (
|
|
952
|
+
const a = await e.databaseIsolation.getAdapters(r);
|
|
953
|
+
t.env.data = a;
|
|
954
|
+
} catch (a) {
|
|
974
955
|
throw console.error(
|
|
975
956
|
`Failed to resolve database for tenant ${r}:`,
|
|
976
|
-
|
|
957
|
+
a
|
|
977
958
|
), new b(500, {
|
|
978
959
|
message: "Failed to resolve tenant database"
|
|
979
960
|
});
|
|
@@ -981,24 +962,24 @@ function be(e) {
|
|
|
981
962
|
return n();
|
|
982
963
|
};
|
|
983
964
|
}
|
|
984
|
-
function
|
|
985
|
-
const t =
|
|
986
|
-
return async (
|
|
987
|
-
}), await n(
|
|
988
|
-
}), await r(
|
|
989
|
-
}),
|
|
965
|
+
function V(e) {
|
|
966
|
+
const t = Ce(e), n = Te(e), r = Pe(e);
|
|
967
|
+
return async (a, s) => (await t(a, async () => {
|
|
968
|
+
}), await n(a, async () => {
|
|
969
|
+
}), await r(a, async () => {
|
|
970
|
+
}), s());
|
|
990
971
|
}
|
|
991
|
-
function
|
|
972
|
+
function ze(e) {
|
|
992
973
|
const {
|
|
993
974
|
dataAdapter: t,
|
|
994
975
|
controlPlane: n,
|
|
995
976
|
controlPlane: {
|
|
996
977
|
tenantId: r = "control_plane",
|
|
997
|
-
clientId:
|
|
978
|
+
clientId: a
|
|
998
979
|
} = {},
|
|
999
|
-
sync:
|
|
1000
|
-
defaultPermissions:
|
|
1001
|
-
requireOrganizationMatch:
|
|
980
|
+
sync: s = { resourceServers: !0, roles: !0 },
|
|
981
|
+
defaultPermissions: o = ["tenant:admin"],
|
|
982
|
+
requireOrganizationMatch: i = !1,
|
|
1002
983
|
managementApiExtensions: u = [],
|
|
1003
984
|
entityHooks: c,
|
|
1004
985
|
getChildTenantIds: l,
|
|
@@ -1006,20 +987,22 @@ function Oe(e) {
|
|
|
1006
987
|
...d
|
|
1007
988
|
} = e;
|
|
1008
989
|
let f = t, m = t;
|
|
1009
|
-
n && (f =
|
|
1010
|
-
controlPlaneTenantId: r,
|
|
1011
|
-
controlPlaneClientId: s
|
|
1012
|
-
}), m = q(t, {
|
|
990
|
+
n && (f = Q(t, {
|
|
1013
991
|
controlPlaneTenantId: r,
|
|
1014
|
-
controlPlaneClientId:
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
992
|
+
controlPlaneClientId: a
|
|
993
|
+
}), m = {
|
|
994
|
+
...t,
|
|
995
|
+
multiTenancyConfig: {
|
|
996
|
+
controlPlaneTenantId: r,
|
|
997
|
+
controlPlaneClientId: a
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
const w = s !== !1, h = w ? {
|
|
1001
|
+
resourceServers: s.resourceServers ?? !0,
|
|
1002
|
+
roles: s.roles ?? !0
|
|
1020
1003
|
} : { resourceServers: !1, roles: !1 }, _ = {
|
|
1021
1004
|
controlPlaneTenantId: r,
|
|
1022
|
-
getChildTenantIds: l ?? (async () => (await
|
|
1005
|
+
getChildTenantIds: l ?? (async () => (await R(
|
|
1023
1006
|
(I) => f.tenants.list(I),
|
|
1024
1007
|
"tenants",
|
|
1025
1008
|
{ cursorField: "id", pageSize: 100 }
|
|
@@ -1036,12 +1019,12 @@ function Oe(e) {
|
|
|
1036
1019
|
connections: (c == null ? void 0 : c.connections) ?? [],
|
|
1037
1020
|
tenants: (c == null ? void 0 : c.tenants) ?? [],
|
|
1038
1021
|
rolePermissions: (c == null ? void 0 : c.rolePermissions) ?? []
|
|
1039
|
-
}, P =
|
|
1022
|
+
}, P = q(
|
|
1040
1023
|
{
|
|
1041
1024
|
accessControl: {
|
|
1042
1025
|
controlPlaneTenantId: r,
|
|
1043
|
-
requireOrganizationMatch:
|
|
1044
|
-
defaultPermissions:
|
|
1026
|
+
requireOrganizationMatch: i,
|
|
1027
|
+
defaultPermissions: o
|
|
1045
1028
|
}
|
|
1046
1029
|
},
|
|
1047
1030
|
{ tenants: C }
|
|
@@ -1055,21 +1038,21 @@ function Oe(e) {
|
|
|
1055
1038
|
{ path: "/tenants", router: P }
|
|
1056
1039
|
]
|
|
1057
1040
|
});
|
|
1058
|
-
return A.use("/api/v2/*",
|
|
1041
|
+
return A.use("/api/v2/*", _e(r)), w && A.use("/api/v2/*", he()), { app: A, controlPlaneTenantId: r };
|
|
1059
1042
|
}
|
|
1060
1043
|
function Re(e) {
|
|
1061
|
-
const t =
|
|
1044
|
+
const t = j(e);
|
|
1062
1045
|
return {
|
|
1063
1046
|
name: "multi-tenancy",
|
|
1064
1047
|
// Apply multi-tenancy middleware for subdomain routing, database resolution, etc.
|
|
1065
|
-
middleware:
|
|
1048
|
+
middleware: V(e),
|
|
1066
1049
|
// Provide lifecycle hooks
|
|
1067
1050
|
hooks: t,
|
|
1068
1051
|
// Mount tenant management routes
|
|
1069
1052
|
routes: [
|
|
1070
1053
|
{
|
|
1071
1054
|
path: "/management",
|
|
1072
|
-
handler:
|
|
1055
|
+
handler: q(e, t)
|
|
1073
1056
|
}
|
|
1074
1057
|
],
|
|
1075
1058
|
// Called when plugin is registered
|
|
@@ -1082,7 +1065,7 @@ function Re(e) {
|
|
|
1082
1065
|
}
|
|
1083
1066
|
};
|
|
1084
1067
|
}
|
|
1085
|
-
function
|
|
1068
|
+
function j(e) {
|
|
1086
1069
|
const t = e.accessControl ? oe(e.accessControl) : {}, n = e.databaseIsolation ? ce(e.databaseIsolation) : {}, r = ue(e);
|
|
1087
1070
|
return {
|
|
1088
1071
|
...t,
|
|
@@ -1090,15 +1073,15 @@ function k(e) {
|
|
|
1090
1073
|
tenants: r
|
|
1091
1074
|
};
|
|
1092
1075
|
}
|
|
1093
|
-
function
|
|
1094
|
-
const t = new Z(), n =
|
|
1095
|
-
return t.route("/tenants",
|
|
1076
|
+
function Ae(e) {
|
|
1077
|
+
const t = new Z(), n = j(e);
|
|
1078
|
+
return t.route("/tenants", q(e, n)), t;
|
|
1096
1079
|
}
|
|
1097
|
-
function
|
|
1080
|
+
function Fe(e) {
|
|
1098
1081
|
return {
|
|
1099
|
-
hooks:
|
|
1100
|
-
middleware:
|
|
1101
|
-
app:
|
|
1082
|
+
hooks: j(e),
|
|
1083
|
+
middleware: V(e),
|
|
1084
|
+
app: Ae(e),
|
|
1102
1085
|
config: e,
|
|
1103
1086
|
/**
|
|
1104
1087
|
* Wraps data adapters with runtime fallback from the control plane.
|
|
@@ -1110,7 +1093,7 @@ function De(e) {
|
|
|
1110
1093
|
*/
|
|
1111
1094
|
wrapAdapters: (t, n) => {
|
|
1112
1095
|
var r;
|
|
1113
|
-
return
|
|
1096
|
+
return Q(t, {
|
|
1114
1097
|
controlPlaneTenantId: (r = e.accessControl) == null ? void 0 : r.controlPlaneTenantId,
|
|
1115
1098
|
controlPlaneClientId: n == null ? void 0 : n.controlPlaneClientId
|
|
1116
1099
|
});
|
|
@@ -1119,22 +1102,22 @@ function De(e) {
|
|
|
1119
1102
|
}
|
|
1120
1103
|
export {
|
|
1121
1104
|
oe as createAccessControlHooks,
|
|
1122
|
-
|
|
1123
|
-
|
|
1105
|
+
Te as createAccessControlMiddleware,
|
|
1106
|
+
_e as createControlPlaneTenantMiddleware,
|
|
1124
1107
|
ce as createDatabaseHooks,
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1108
|
+
Pe as createDatabaseMiddleware,
|
|
1109
|
+
Ae as createMultiTenancy,
|
|
1110
|
+
j as createMultiTenancyHooks,
|
|
1111
|
+
V as createMultiTenancyMiddleware,
|
|
1129
1112
|
Re as createMultiTenancyPlugin,
|
|
1130
1113
|
he as createProtectSyncedMiddleware,
|
|
1131
1114
|
ue as createProvisioningHooks,
|
|
1132
|
-
|
|
1133
|
-
|
|
1115
|
+
ve as createRuntimeFallbackAdapter,
|
|
1116
|
+
Ce as createSubdomainMiddleware,
|
|
1134
1117
|
ge as createSyncHooks,
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1118
|
+
q as createTenantsOpenAPIRouter,
|
|
1119
|
+
ze as initMultiTenant,
|
|
1120
|
+
Fe as setupMultiTenancy,
|
|
1138
1121
|
ie as validateTenantAccess,
|
|
1139
|
-
|
|
1122
|
+
Q as withRuntimeFallback
|
|
1140
1123
|
};
|
package/dist/types/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAY,YAAY,EAAU,MAAM,UAAU,CAAC;AAShF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,cAAc,EACd,aAAa,GAAG,yBAAyB,CAC1C;IACC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC;;;;OAIG;IACH,IAAI,CAAC,EACD;QACE,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GACD,KAAK,CAAC;IAEV;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE9B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;OAGG;IACH,uBAAuB,CAAC,EAAE,cAAc,CAAC,yBAAyB,CAAC,CAAC;IAEpE;;;OAGG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;IAE5C;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE5C;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CAC3D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,GAAG,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;IACpC,kCAAkC;IAClC,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAY,YAAY,EAAU,MAAM,UAAU,CAAC;AAShF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,cAAc,EACd,aAAa,GAAG,yBAAyB,CAC1C;IACC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC;;;;OAIG;IACH,IAAI,CAAC,EACD;QACE,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GACD,KAAK,CAAC;IAEV;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE9B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;OAGG;IACH,uBAAuB,CAAC,EAAE,cAAc,CAAC,yBAAyB,CAAC,CAAC;IAEpE;;;OAGG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;IAE5C;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE5C;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CAC3D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,GAAG,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;IACpC,kCAAkC;IAClC,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CA8H5E"}
|
|
@@ -3,6 +3,8 @@ import { DataAdapters } from "authhero";
|
|
|
3
3
|
* Configuration for runtime settings fallback from a control plane tenant.
|
|
4
4
|
*
|
|
5
5
|
* Runtime fallback provides default values at query time without copying sensitive data.
|
|
6
|
+
* This should only be used for auth flows, not for management API which should return
|
|
7
|
+
* raw tenant data without any merging.
|
|
6
8
|
*/
|
|
7
9
|
export interface RuntimeFallbackConfig {
|
|
8
10
|
/**
|
|
@@ -17,14 +19,6 @@ export interface RuntimeFallbackConfig {
|
|
|
17
19
|
* be merged with child tenant clients at runtime.
|
|
18
20
|
*/
|
|
19
21
|
controlPlaneClientId?: string;
|
|
20
|
-
/**
|
|
21
|
-
* When true, excludes sensitive fields (client_secret, app_secret, twilio_token)
|
|
22
|
-
* from the control plane fallback. Use this for management API adapters to prevent
|
|
23
|
-
* tenants from accessing control plane secrets.
|
|
24
|
-
*
|
|
25
|
-
* @default false
|
|
26
|
-
*/
|
|
27
|
-
excludeSensitiveFields?: boolean;
|
|
28
22
|
}
|
|
29
23
|
/**
|
|
30
24
|
* Creates a data adapter wrapper that provides runtime settings fallback from a control plane tenant.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-inheritance.d.ts","sourceRoot":"","sources":["../../../src/middleware/settings-inheritance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAKb,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"settings-inheritance.d.ts","sourceRoot":"","sources":["../../../src/middleware/settings-inheritance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAKb,MAAM,UAAU,CAAC;AA8ElB;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CAgMd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CAEd"}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/markusahlstrand/authhero"
|
|
13
13
|
},
|
|
14
|
-
"version": "14.
|
|
14
|
+
"version": "14.10.0",
|
|
15
15
|
"description": "Multi-tenancy support for AuthHero with organization-based access control and per-tenant database isolation",
|
|
16
16
|
"files": [
|
|
17
17
|
"dist"
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"typescript": "^5.6.0",
|
|
37
37
|
"vite": "^6.0.0",
|
|
38
38
|
"vitest": "^2.1.0",
|
|
39
|
-
"authhero": "4.
|
|
40
|
-
"@authhero/
|
|
41
|
-
"@authhero/adapter
|
|
39
|
+
"authhero": "4.29.0",
|
|
40
|
+
"@authhero/adapter-interfaces": "0.130.0",
|
|
41
|
+
"@authhero/kysely-adapter": "10.93.0"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"zod": "^3.24.0"
|