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