@authhero/multi-tenancy 14.25.0 → 14.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("hono"),t=require("authhero"),n=require("@hono/zod-openapi"),r=require("hono/http-exception");function i(e){let{controlPlaneTenantId:t,requireOrganizationMatch:n=!0}=e;return{async onTenantAccessValidation(e,r){if(r===t)return!0;if(n){let t=e.var.org_name,n=e.var.organization_id,i=t||n;return i?i.toLowerCase()===r.toLowerCase():!1}return!0}}}function a(e,t,n,r){if(t===n)return!0;let i=r||e;return i?i.toLowerCase()===t.toLowerCase():!1}function o(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(e){console.error(`Failed to resolve data adapters for tenant ${t}:`,e);return}}}}function s(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function c(e){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:s(t.id)}:t},async afterCreate(t,n){let{accessControl:r,databaseIsolation:i}=e;r&&t.ctx&&await l(t,n,r),i?.onProvision&&await i.onProvision(n.id)},async beforeDelete(t,n){let{accessControl:r,databaseIsolation:i}=e;if(r)try{let e=(await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(e=>e.name===n);e&&await t.adapters.organizations.remove(r.controlPlaneTenantId,e.id)}catch(e){console.warn(`Failed to remove organization for tenant ${n}:`,e)}if(i?.onDeprovision)try{await i.onDeprovision(n)}catch(e){console.warn(`Failed to deprovision database for tenant ${n}:`,e)}}}}async function l(e,t,n){let{controlPlaneTenantId:r,defaultPermissions:i,defaultRoles:a,issuer:o,adminRoleName:s=`Tenant Admin`,adminRoleDescription:c=`Full access to all tenant management operations`,addCreatorToOrganization:l=!0}=n,f=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id}),p;if(o&&(p=await d(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await u(e,r,t.sub))try{await e.adapters.userOrganizations.create(r,{user_id:t.sub,organization_id:f.id}),p&&await e.adapters.userRoles.create(r,t.sub,p,f.id)}catch(e){console.warn(`Failed to add creator ${t.sub} to organization ${f.id}:`,e)}}a&&a.length>0&&console.log(`Would assign roles ${a.join(`, `)} to organization ${f.id}`),i&&i.length>0&&console.log(`Would grant permissions ${i.join(`, `)} to organization ${f.id}`)}async function u(e,t,n){let r=await e.adapters.userRoles.list(t,n,void 0,``);for(let n of r)if((await e.adapters.rolePermissions.list(t,n.id,{per_page:1e3})).some(e=>e.permission_name===`admin:organizations`))return!0;return!1}async function d(e,n,r,i){let a=(await e.adapters.roles.list(n,{})).roles.find(e=>e.name===r);if(a)return a.id;let o=await e.adapters.roles.create(n,{name:r,description:i}),s=t.MANAGEMENT_API_AUDIENCE,c=t.MANAGEMENT_API_SCOPES.map(e=>({role_id:o.id,resource_server_identifier:s,permission_name:e.value}));return await e.adapters.rolePermissions.assign(n,o.id,c),o.id}function f(e,t,n=()=>!0){let{controlPlaneTenantId:r,getChildTenantIds:i,getAdapters:a}=e,o=new Map;async function s(e,n,r){return(await t(e).list(n,{q:`name:${r}`,per_page:1}))[0]??null}async function c(e){let n=await i(),o=t(await a(r));await Promise.all(n.map(async n=>{try{let r=await a(n),i=t(r),c={...o.transform(e),is_system:!0},l=await s(r,n,e.name),u=l?i.getId(l):void 0;if(l&&u){let e=i.preserveOnUpdate?i.preserveOnUpdate(l,c):c;await i.update(n,u,e)}else await i.create(n,c)}catch(t){console.error(`Failed to sync ${o.listKey} "${e.name}" to tenant "${n}":`,t)}}))}async function l(e){let n=await i();await Promise.all(n.map(async n=>{try{let r=await a(n),i=t(r),o=await s(r,n,e),c=o?i.getId(o):void 0;o&&c&&await i.remove(n,c)}catch(t){console.error(`Failed to delete entity "${e}" from tenant "${n}":`,t)}}))}return{afterCreate:async(e,t)=>{e.tenantId===r&&n(t)&&await c(t)},afterUpdate:async(e,t,i)=>{e.tenantId===r&&n(i)&&await c(i)},beforeDelete:async(e,i)=>{if(e.tenantId!==r)return;let a=await t(e.adapters).get(e.tenantId,i);a&&n(a)&&o.set(i,a)},afterDelete:async(e,t)=>{if(e.tenantId!==r)return;let n=o.get(t);n&&(o.delete(t),await l(n.name))}}}function p(e,n,r=()=>!0){let{controlPlaneTenantId:i,getControlPlaneAdapters:a,getAdapters:o}=e;return{async afterCreate(e,s){if(s.id!==i)try{let e=await a(),c=await o(s.id),l=n(e),u=n(c),d=await(0,t.fetchAll)(e=>l.listPaginated(i,e),l.listKey,{cursorField:`id`,pageSize:100});await Promise.all(d.filter(e=>r(e)).map(async e=>{try{let t=l.transform(e);await u.create(s.id,{...t,is_system:!0})}catch(e){console.error(`Failed to sync entity to new tenant "${s.id}":`,e)}}))}catch(e){console.error(`Failed to sync entities to new tenant "${s.id}":`,e)}}}}var m=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:e=>e.id,transform:e=>({id:e.id,name:e.name,identifier:e.identifier,scopes:e.scopes,signing_alg:e.signing_alg,token_lifetime:e.token_lifetime,token_lifetime_for_web:e.token_lifetime_for_web})}),h=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:e=>e.id,transform:e=>({id:e.id,name:e.name,description:e.description})});function g(e){return e.metadata?.sync!==!1}function _(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>g(e)?r.resourceServers?r.resourceServers(e):!0:!1,s=e=>g(e)?r.roles?r.roles(e):!0:!1,c=i?f(e,m,o):void 0,l=a?f(e,h,s):void 0,u=i?p(e,m,o):void 0,d=a?p(e,h,s):void 0,_=a?{async afterCreate(n,i){if(i.id!==e.controlPlaneTenantId){await d?.afterCreate?.(n,i);try{let n=await e.getControlPlaneAdapters(),a=await e.getAdapters(i.id),o=await(0,t.fetchAll)(t=>n.roles.list(e.controlPlaneTenantId,t),`roles`,{cursorField:`id`,pageSize:100}),s=new Map;for(let e of o.filter(e=>r.roles?.(e)??!0)){let t=await v(a,i.id,e.name);t&&s.set(e.name,t.id)}for(let t of o.filter(e=>r.roles?.(e)??!0)){let r=s.get(t.name);if(r)try{let o=await n.rolePermissions.list(e.controlPlaneTenantId,t.id,{});o.length>0&&await a.rolePermissions.assign(i.id,r,o.map(e=>({role_id:r,resource_server_identifier:e.resource_server_identifier,permission_name:e.permission_name})))}catch(e){console.error(`Failed to sync permissions for role "${t.name}" to tenant "${i.id}":`,e)}}}catch(e){console.error(`Failed to sync role permissions to tenant "${i.id}":`,e)}}}}:void 0;async function v(e,t,n){return(await e.roles.list(t,{q:`name:${n}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:c,roles:l},tenantHooks:{async afterCreate(e,t){let n=[u?.afterCreate,_?.afterCreate??d?.afterCreate],r=[];for(let i of n)if(i)try{await i(e,t)}catch(e){r.push(e instanceof Error?e:Error(String(e)))}if(r.length===1)throw r[0];if(r.length>1)throw AggregateError(r,r.map(e=>e.message).join(`; `))}}}}var v=n.z.object({sub:n.z.string(),tenant_id:n.z.string().optional(),org_id:n.z.string().optional(),scope:n.z.string().optional(),permissions:n.z.array(n.z.string()).optional()}).passthrough();function y(e){let t=v.safeParse(e);return t.success?t.data:void 0}function b(e){let t=e.permissions??[],n=e.scope?e.scope.split(` `).filter(Boolean):[],r=new Set([...t,...n]);return r.has(`delete:tenants`)||r.has(`admin:organizations`)}function x(e,i){let a=new n.OpenAPIHono;return a.openapi((0,n.createRoute)({tags:[`tenants`],method:`get`,path:`/`,request:{query:t.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:n.z.object({tenants:n.z.array(t.tenantSchema),start:n.z.number().optional(),limit:n.z.number().optional(),length:n.z.number().optional()})}},description:`List of tenants`}}}),async n=>{let{page:i,per_page:a,include_totals:o,q:s}=n.req.valid(`query`),c=n.var.user,l=c?.permissions||[];if(!(c?.org_id??n.var.organization_id)&&l.includes(`admin:organizations`)){let e=await n.env.data.tenants.list({page:i,per_page:a,include_totals:o,q:s});return o?n.json({tenants:e.tenants,start:e.totals?.start??0,limit:e.totals?.limit??a,length:e.tenants.length}):n.json({tenants:e.tenants})}let u=e.accessControl?.controlPlaneTenantId??n.env.data.multiTenancyConfig?.controlPlaneTenantId;if(u&&!c?.sub)throw new r.HTTPException(403,{message:`Access denied: token has no subject`});if(u&&c?.sub){let e=(await(0,t.fetchAll)(e=>n.env.data.userOrganizations.listUserOrganizations(u,c.sub,e),`organizations`)).map(e=>e.name);if(e.length===0)return o?n.json({tenants:[],start:0,limit:a??50,length:0}):n.json({tenants:[]});let r=e.length,l=i??0,d=a??50,f=l*d,p=e.slice(f,f+d);if(p.length===0)return o?n.json({tenants:[],start:f,limit:d,length:r}):n.json({tenants:[]});let m=p.map(e=>`id:${e}`).join(` OR `),h=s?`(${m}) AND (${s})`:m,g=await n.env.data.tenants.list({q:h,per_page:d,include_totals:!1});return o?n.json({tenants:g.tenants,start:f,limit:d,length:r}):n.json({tenants:g.tenants})}let d=await n.env.data.tenants.list({page:i,per_page:a,include_totals:o,q:s});return o?n.json({tenants:d.tenants,start:d.totals?.start??0,limit:d.totals?.limit??a,length:d.tenants.length}):n.json({tenants:d.tenants})}),a.openapi((0,n.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 e=>{if(!e.var.user?.sub)throw new r.HTTPException(401,{message:`Authentication required to create tenants`});let t=e.req.valid(`json`),n={adapters:e.env.data,ctx:e};i.tenants?.beforeCreate&&(t=await i.tenants.beforeCreate(n,t));let a=await e.env.data.tenants.create(t);return i.tenants?.afterCreate&&await i.tenants.afterCreate(n,a),e.json(a,201)}),a.openapi((0,n.createRoute)({tags:[`tenants`],method:`delete`,path:`/{id}`,request:{params:n.z.object({id:n.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 n=>{let{id:a}=n.req.valid(`param`),o=e.accessControl?.controlPlaneTenantId??n.env.data.multiTenancyConfig?.controlPlaneTenantId;if(o){let e=y(n.var.user);if(!e?.sub)throw new r.HTTPException(401,{message:`Authentication required`});if(a===o)throw new r.HTTPException(403,{message:`Cannot delete the control plane`});let i=n.var.org_name,s=a.toLowerCase(),c=!!i&&i.toLowerCase()===s;if(!c){let t=!!(e.org_id??n.var.organization_id??i),r=!e.tenant_id||e.tenant_id===o;!t&&r&&b(e)&&(c=!0)}if(c||=(await(0,t.fetchAll)(t=>n.env.data.userOrganizations.listUserOrganizations(o,e.sub,t),`organizations`)).some(e=>e.name?.toLowerCase()===s),!c)throw new r.HTTPException(403,{message:`Access denied to this tenant`})}if(!await n.env.data.tenants.get(a))throw new r.HTTPException(404,{message:`Tenant not found`});let s={adapters:n.env.data,ctx:n};return i.tenants?.beforeDelete&&await i.tenants.beforeDelete(s,a),await n.env.data.tenants.remove(a),i.tenants?.afterDelete&&await i.tenants.afterDelete(s,a),n.body(null,204)}),a.openapi((0,n.createRoute)({tags:[`tenants`,`settings`],method:`get`,path:`/settings`,request:{headers:n.z.object({"tenant-id":n.z.string().optional()})},security:[{Bearer:[`read:tenants`]}],responses:{200:{content:{"application/json":{schema:t.tenantSchema}},description:`Current tenant settings`}}}),async e=>{let t=await e.env.data.tenants.get(e.var.tenant_id);if(!t)throw new r.HTTPException(404,{message:`Tenant not found`});return e.json(t)}),a.openapi((0,n.createRoute)({tags:[`tenants`,`settings`],method:`patch`,path:`/settings`,request:{headers:n.z.object({"tenant-id":n.z.string().optional()}),body:{content:{"application/json":{schema:n.z.object(t.tenantInsertSchema.shape).partial()}}}},security:[{Bearer:[`update:tenants`]}],responses:{200:{content:{"application/json":{schema:t.tenantSchema}},description:`Updated tenant settings`}}}),async e=>{let{id:n,...i}=e.req.valid(`json`),a=await e.env.data.tenants.get(e.var.tenant_id);if(!a)throw new r.HTTPException(404,{message:`Tenant not found`});let o=(0,t.deepMergePatch)(a,i);await e.env.data.tenants.update(e.var.tenant_id,o);let s=await e.env.data.tenants.get(e.var.tenant_id);if(!s)throw new r.HTTPException(500,{message:`Failed to retrieve updated tenant`});return e.json(s)}),a}function S(e){for(let{pattern:t,type:n}of[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:`resource_server`},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:`role`},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:`connection`}]){let r=e.match(t);if(r&&r[1])return{type:n,id:r[1]}}return null}async function C(e,t,n){try{switch(n.type){case`resource_server`:return(await e.resourceServers.get(t,n.id))?.is_system===!0;case`role`:return(await e.roles.get(t,n.id))?.is_system===!0;case`connection`:return(await e.connections.get(t,n.id))?.is_system===!0;default:return!1}}catch{return!1}}function w(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function T(){return async(e,t)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return t();let n=S(e.req.path);if(!n)return t();let i=e.var.tenant_id||e.req.header(`x-tenant-id`)||e.req.header(`tenant-id`);if(!i)return t();if(await C(e.env.data,i,n))throw new r.HTTPException(403,{message:`This ${w(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function E(e,n){let r=n.find(t=>t.strategy===e.strategy);if(!r?.options)return e;let i=t.connectionSchema.passthrough().parse({...r,...e});return i.options=t.connectionOptionsSchema.passthrough().parse({...r.options||{},...e.options}),i}function D(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function O(e,t){if(!t?.length)return e||[];if(!e?.length)return t;let n=new Map;for(let e of t)n.set(e.value,e);for(let t of e)n.set(t.value,t);return Array.from(n.values())}function k(e,t){return t?{...e,scopes:O(e.scopes,t.scopes)}:e}function ee(e,t){return t?{...e,callbacks:D(e.callbacks,t.callbacks),web_origins:D(e.web_origins,t.web_origins),allowed_logout_urls:D(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:D(e.allowed_origins,t.allowed_origins)}:e}function A(e){let{controlPlaneTenantId:t,controlPlaneClientId:n,resolveControlPlane:r}=e;if(r)return async e=>r({tenant_id:e});if(!t)return async()=>void 0;let i={tenantId:t,clientId:n};return async()=>i}function j(e,t){return{...e.resourceServers,get:async(n,r)=>{let i=await e.resourceServers.get(n,r);if(!i)return i;let a=await t(n);return!a||n===a.tenantId||!i.is_system?i:k(i,await e.resourceServers.get(a.tenantId,r))},list:async(n,r)=>{let i=await e.resourceServers.list(n,r),a=await t(n);if(!a||n===a.tenantId)return i;let o=a.tenantId,s=i.resource_servers.filter(e=>!!(e.is_system&&e.id)).map(e=>e.id);if(s.length===0)return i;let c=new Map;await Promise.all(s.map(async t=>{let n=await e.resourceServers.get(o,t);n&&c.set(t,n)}));let l=i.resource_servers.map(e=>e.is_system&&e.id?k(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function M(e,t){let n=A({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:j(e,n)}}function N(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i}=t,a=A({controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i});return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i},connections:{...e.connections,get:async(t,n)=>{let r=await e.connections.get(t,n);if(!r)return r;let i=await a(t);return!i||t===i.tenantId?r:E(r,(await e.connections.list(i.tenantId)).connections||[])},list:async(t,n)=>{let r=await e.connections.list(t,n),i=await a(t);if(!i||t===i.tenantId)return r;let o=await e.connections.list(i.tenantId),s=r.connections.map(e=>E(e,o.connections||[]));return{...r,connections:s}}},clientConnections:{...e.clientConnections,listByClient:async(t,n)=>{let r=await e.clientConnections.listByClient(t,n);r.length===0&&(r=(await e.connections.list(t)).connections||[]);let i=await a(t);if(!i||t===i.tenantId)return r;let o=await e.connections.list(i.tenantId);return r.map(e=>E(e,o.connections||[]))}},emailProviders:{...e.emailProviders,get:async t=>{let n=await e.emailProviders.get(t);if(n)return n;let r=await a(t);return!r||t===r.tenantId?null:e.emailProviders.get(r.tenantId)}},resourceServers:j(e,a),hooks:F(e,a)}}function P(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function F(e,t){return{...e.hooks,list:async(n,r)=>{let i=await e.hooks.list(n,r),a=await t(n);if(!a||n===a.tenantId)return i;let o=((await e.hooks.list(a.tenantId,r)).hooks||[]).filter(P);if(o.length===0)return i;let s=new Set((i.hooks||[]).map(e=>e.hook_id)),c=o.filter(e=>!s.has(e.hook_id));return{...i,hooks:[...i.hooks||[],...c],length:typeof i.length==`number`?i.length+c.length:i.length}},get:async(n,r)=>{let i=await e.hooks.get(n,r);if(i)return i;let a=await t(n);if(!a||n===a.tenantId)return i;let o=await e.hooks.get(a.tenantId,r);return o&&P(o)?o:null}}}function I(e,t){return N(e,t)}function L(e){return async(t,n)=>{let r=t.var.user;return r?.tenant_id===e&&r.org_name&&t.set(`tenant_id`,r.org_name),n()}}function R(e){return async(n,i)=>{if(!e.accessControl)return i();let{controlPlaneTenantId:o}=e.accessControl,s=n.var.org_name,c=n.var.organization_id,l=s||c,u=n.var.tenant_id,d=n.var.user,f=(d?.aud?Array.isArray(d.aud)?d.aud:[d.aud]:[]).includes(t.MANAGEMENT_API_AUDIENCE);if(!u&&l&&f&&(n.set(`tenant_id`,l),u=l),!u)throw new r.HTTPException(400,{message:`Tenant ID not found in request`});if(!a(c,u,o,s))throw new r.HTTPException(403,{message:`Access denied to tenant ${u}`});return i()}}function z(e){return async(t,n)=>{if(!e.subdomainRouting)return n();let{baseDomain:i,reservedSubdomains:a=[],resolveSubdomain:o}=e.subdomainRouting,s=t.req.header(`x-forwarded-host`)||t.req.header(`host`)||``,c=null;if(s.endsWith(i)){let e=s.slice(0,-(i.length+1));e&&!e.includes(`.`)&&(c=e)}if(c&&a.includes(c)&&(c=null),!c)return e.accessControl&&t.set(`tenant_id`,e.accessControl.controlPlaneTenantId),n();let l=null;if(o)l=await o(c);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{let n=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,c);n&&(l=n.id)}catch{}if(!l)throw new r.HTTPException(404,{message:`Tenant not found for subdomain: ${c}`});return t.set(`tenant_id`,l),n()}}function B(e){return async(t,n)=>{if(!e.databaseIsolation)return n();let i=t.var.tenant_id;if(!i)throw new r.HTTPException(400,{message:`Tenant ID not found in request`});try{let n=await e.databaseIsolation.getAdapters(i);t.env.data=n}catch(e){throw console.error(`Failed to resolve database for tenant ${i}:`,e),new r.HTTPException(500,{message:`Failed to resolve tenant database`})}return n()}}function V(e){let t=z(e),n=R(e),r=B(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}function H(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,sync:s={resourceServers:!0,roles:!0},defaultPermissions:l=[`tenant:admin`],requireOrganizationMatch:u=!1,managementApiExtensions:d=[],entityHooks:f,getChildTenantIds:p,getAdapters:m,...h}=e;if(o&&!r)throw Error("initMultiTenant: `resolveControlPlane` requires `controlPlane` to be set. The static `controlPlane.tenantId` is used for access control, sync direction, and tenant management routing; the resolver only overrides per-tenant runtime inheritance lookups on top of it.");let g=n,v=n;r&&(g=I(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),v={...M(n,{controlPlaneTenantId:i,resolveControlPlane:o}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}});let y=s!==!1,b=y?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:S,tenantHooks:C}=_({controlPlaneTenantId:i,getChildTenantIds:p??(async()=>(await(0,t.fetchAll)(e=>g.tenants.list(e),`tenants`,{cursorField:`id`,pageSize:100})).filter(e=>e.id!==i).map(e=>e.id)),getAdapters:m??(async()=>g),getControlPlaneAdapters:async()=>g,sync:b}),w={resourceServers:[S.resourceServers,...f?.resourceServers??[]],roles:[S.roles,...f?.roles??[]],connections:f?.connections??[],tenants:f?.tenants??[],rolePermissions:f?.rolePermissions??[]},E=c({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:u,defaultPermissions:l}}),D=x({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:u,defaultPermissions:l}},{tenants:{async beforeCreate(e,t){return E.beforeCreate&&(t=await E.beforeCreate(e,t)),C.beforeCreate&&(t=await C.beforeCreate(e,t)),t},async afterCreate(e,t){await E.afterCreate?.(e,t),await C.afterCreate?.(e,t)},async beforeDelete(e,t){await E.beforeDelete?.(e,t),await C.beforeDelete?.(e,t)}}}),{app:O}=(0,t.init)({dataAdapter:g,managementDataAdapter:v,...h,entityHooks:w,managementApiExtensions:[...d,{path:`/tenants`,router:D}]});return O.use(`/api/v2/*`,L(i)),y&&O.use(`/api/v2/*`,T()),{app:O,controlPlaneTenantId:i}}function U(e={}){return{connections:e.connections??!0,resourceServers:e.resourceServers??!0,hooks:e.hooks??!0,emailProvider:e.emailProvider??!0,branding:e.branding??!0,promptSettings:e.promptSettings??!0}}function W(){return{upserted:0,errors:[]}}function G(e){return{tenantId:e,connections:W(),resourceServers:W(),hooks:W(),emailProvider:W(),branding:W(),promptSettings:W()}}function K(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function q(e,t,n,r){try{await r()}catch(r){let i=`${t}: ${r instanceof Error?r.message:String(r)}`;if(!n)throw Error(i,{cause:r});e.errors.push(i)}}async function J(e,n,r){return{connections:r.connections?await(0,t.fetchAll)(t=>e.connections.list(n,t),`connections`,{cursorField:`id`,pageSize:100}):[],resourceServers:r.resourceServers?await(0,t.fetchAll)(t=>e.resourceServers.list(n,t),`resource_servers`,{cursorField:`id`,pageSize:100}):[],hooks:r.hooks?await(0,t.fetchAll)(t=>e.hooks.list(n,t),`hooks`,{cursorField:`hook_id`,pageSize:100}):[],emailProvider:r.emailProvider?await e.emailProviders.get(n)??null:null,branding:r.branding?await e.branding.get(n)??null:null,promptSettings:r.promptSettings?await e.promptSettings.get(n)??null:null}}async function Y(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await q(o.connections,`connection ${e}`,a,async()=>{let a=t.connectionInsertSchema.parse(i);await n.connections.get(r,e)?await n.connections.update(r,e,a):await n.connections.create(r,a),o.connections.upserted+=1})}if(i.resourceServers)for(let i of e.resourceServers)!i.is_system||!i.id||await q(o.resourceServers,`resource_server ${i.id}`,a,async()=>{let e=t.resourceServerInsertSchema.parse(i);await n.resourceServers.get(r,i.id)?await n.resourceServers.update(r,i.id,e):await n.resourceServers.create(r,e),o.resourceServers.upserted+=1});if(i.hooks)for(let i of e.hooks)!K(i)||!i.hook_id||await q(o.hooks,`hook ${i.hook_id}`,a,async()=>{let e=t.hookInsertSchema.parse(i);await n.hooks.get(r,i.hook_id)?await n.hooks.update(r,i.hook_id,e):await n.hooks.create(r,e),o.hooks.upserted+=1});i.emailProvider&&e.emailProvider&&await q(o.emailProvider,`email_provider`,a,async()=>{let t=e.emailProvider;await n.emailProviders.get(r)?await n.emailProviders.update(r,t):await n.emailProviders.create(r,t),o.emailProvider.upserted+=1}),i.branding&&e.branding&&await q(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await q(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function X(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=U(a),c=await J(await r(),n,s),l=await i(t),u=G(t);return await Y(c,l,n,s,o,u),u}function Z(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function te(e,n,r={}){let i=U(r),a=r.signingKeys??!0,o=await J(e,n,i),s=a?(await(0,t.listControlPlaneKeys)(e.keys)).map(Z):[];return{connections:o.connections,resourceServers:o.resourceServers.filter(e=>e.is_system),hooks:o.hooks.filter(K),emailProvider:o.emailProvider,branding:o.branding,promptSettings:o.promptSettings,signingKeys:s}}async function ne(e,n,r){let i=W();if(e.length===0)return i;let a=await(0,t.listControlPlaneKeys)(n.keys),o=new Set(a.map(e=>e.kid));for(let t of e)await q(i,`signing_key ${t.kid}`,r,async()=>{let e=Z(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function re(e,n,r,i={}){let a=i.continueOnError??!1,o=U(i.entities),s=i.entities?.signingKeys??!0,c={connections:e.connections,resourceServers:e.resourceServers,hooks:e.hooks,emailProvider:e.emailProvider?t.emailProviderSchema.parse(e.emailProvider):null,branding:e.branding?t.brandingSchema.parse(e.branding):null,promptSettings:e.promptSettings?t.promptSettingSchema.parse(e.promptSettings):null},l=G(r);await Y(c,n,r,o,a,l);let u=s?await ne(e.signingKeys,n,a):W();return{...l,signingKeys:u}}function ie(e){return{syncDefaults:t=>X(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await X(e,r));return n}}}function ae(e){let t=Q(e);return{name:`multi-tenancy`,middleware:V(e),hooks:t,routes:[{path:`/management`,handler:x(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 Q(e){let t=e.accessControl?i(e.accessControl):{},n=e.databaseIsolation?o(e.databaseIsolation):{},r=c(e);return{...t,...n,tenants:r}}function $(t){let n=new e.Hono,r=Q(t);return n.route(`/tenants`,x(t,r)),n}function oe(e){return{hooks:Q(e),middleware:V(e),app:$(e),config:e,wrapAdapters:(t,n)=>I(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.applyControlPlaneDefaultsPayload=re,exports.buildControlPlaneDefaultsPayload=te,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=R,exports.createControlPlaneTenantMiddleware=L,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=B,exports.createDirectRolloutAdapter=ie,exports.createMultiTenancy=$,exports.createMultiTenancyHooks=Q,exports.createMultiTenancyMiddleware=V,exports.createMultiTenancyPlugin=ae,exports.createProtectSyncedMiddleware=T,exports.createProvisioningHooks=c,exports.createRuntimeFallbackAdapter=N,exports.createSubdomainMiddleware=z,exports.createSyncHooks=_,exports.createTenantsOpenAPIRouter=x,exports.initMultiTenant=H,exports.mergeClientWithFallback=ee,exports.projectControlPlaneDefaults=X,exports.setupMultiTenancy=oe,exports.validateTenantAccess=a,exports.withRuntimeFallback=I,exports.withSystemResourceServerInheritance=M;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("hono"),t=require("authhero"),n=require("@hono/zod-openapi"),r=require("hono/http-exception");function i(e){let{controlPlaneTenantId:t,requireOrganizationMatch:n=!0}=e;return{async onTenantAccessValidation(e,r){if(r===t)return!0;if(n){let t=e.var.org_name,n=e.var.organization_id,i=t||n;return i?i.toLowerCase()===r.toLowerCase():!1}return!0}}}function a(e,t,n,r){if(t===n)return!0;let i=r||e;return i?i.toLowerCase()===t.toLowerCase():!1}function o(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(e){console.error(`Failed to resolve data adapters for tenant ${t}:`,e);return}}}}function s(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function c(e){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:s(t.id)}:t},async afterCreate(t,n){let{accessControl:r,databaseIsolation:i}=e;r&&t.ctx&&await l(t,n,r),i?.onProvision&&await i.onProvision(n.id)},async beforeDelete(t,n){let{accessControl:r,databaseIsolation:i}=e;if(r)try{let e=(await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(e=>e.name===n);e&&await t.adapters.organizations.remove(r.controlPlaneTenantId,e.id)}catch(e){console.warn(`Failed to remove organization for tenant ${n}:`,e)}if(i?.onDeprovision)try{await i.onDeprovision(n)}catch(e){console.warn(`Failed to deprovision database for tenant ${n}:`,e)}}}}async function l(e,t,n){let{controlPlaneTenantId:r,defaultPermissions:i,defaultRoles:a,issuer:o,adminRoleName:s=`Tenant Admin`,adminRoleDescription:c=`Full access to all tenant management operations`,addCreatorToOrganization:l=!0}=n,f=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id}),p;if(o&&(p=await d(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await u(e,r,t.sub))try{await e.adapters.userOrganizations.create(r,{user_id:t.sub,organization_id:f.id}),p&&await e.adapters.userRoles.create(r,t.sub,p,f.id)}catch(e){console.warn(`Failed to add creator ${t.sub} to organization ${f.id}:`,e)}}a&&a.length>0&&console.log(`Would assign roles ${a.join(`, `)} to organization ${f.id}`),i&&i.length>0&&console.log(`Would grant permissions ${i.join(`, `)} to organization ${f.id}`)}async function u(e,t,n){let r=await e.adapters.userRoles.list(t,n,void 0,``);for(let n of r)if((await e.adapters.rolePermissions.list(t,n.id,{per_page:1e3})).some(e=>e.permission_name===`admin:organizations`))return!0;return!1}async function d(e,n,r,i){let a=(await e.adapters.roles.list(n,{})).roles.find(e=>e.name===r);if(a)return a.id;let o=await e.adapters.roles.create(n,{name:r,description:i}),s=t.MANAGEMENT_API_AUDIENCE,c=t.MANAGEMENT_API_SCOPES.map(e=>({role_id:o.id,resource_server_identifier:s,permission_name:e.value}));return await e.adapters.rolePermissions.assign(n,o.id,c),o.id}function f(e,t,n=()=>!0){let{controlPlaneTenantId:r,getChildTenantIds:i,getAdapters:a}=e,o=new Map;async function s(e,n,r){return(await t(e).list(n,{q:`name:${r}`,per_page:1}))[0]??null}async function c(e){let n=await i(),o=t(await a(r));await Promise.all(n.map(async n=>{try{let r=await a(n),i=t(r),c={...o.transform(e),is_system:!0},l=await s(r,n,e.name),u=l?i.getId(l):void 0;if(l&&u){let e=i.preserveOnUpdate?i.preserveOnUpdate(l,c):c;await i.update(n,u,e)}else await i.create(n,c)}catch(t){console.error(`Failed to sync ${o.listKey} "${e.name}" to tenant "${n}":`,t)}}))}async function l(e){let n=await i();await Promise.all(n.map(async n=>{try{let r=await a(n),i=t(r),o=await s(r,n,e),c=o?i.getId(o):void 0;o&&c&&await i.remove(n,c)}catch(t){console.error(`Failed to delete entity "${e}" from tenant "${n}":`,t)}}))}return{afterCreate:async(e,t)=>{e.tenantId===r&&n(t)&&await c(t)},afterUpdate:async(e,t,i)=>{e.tenantId===r&&n(i)&&await c(i)},beforeDelete:async(e,i)=>{if(e.tenantId!==r)return;let a=await t(e.adapters).get(e.tenantId,i);a&&n(a)&&o.set(i,a)},afterDelete:async(e,t)=>{if(e.tenantId!==r)return;let n=o.get(t);n&&(o.delete(t),await l(n.name))}}}function p(e,n,r=()=>!0){let{controlPlaneTenantId:i,getControlPlaneAdapters:a,getAdapters:o}=e;return{async afterCreate(e,s){if(s.id!==i)try{let e=await a(),c=await o(s.id),l=n(e),u=n(c),d=await(0,t.fetchAll)(e=>l.listPaginated(i,e),l.listKey,{cursorField:`id`,pageSize:100});await Promise.all(d.filter(e=>r(e)).map(async e=>{try{let t=l.transform(e);await u.create(s.id,{...t,is_system:!0})}catch(e){console.error(`Failed to sync entity to new tenant "${s.id}":`,e)}}))}catch(e){console.error(`Failed to sync entities to new tenant "${s.id}":`,e)}}}}var m=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:e=>e.id,transform:e=>({id:e.id,name:e.name,identifier:e.identifier,scopes:e.scopes,signing_alg:e.signing_alg,token_lifetime:e.token_lifetime,token_lifetime_for_web:e.token_lifetime_for_web})}),h=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:e=>e.id,transform:e=>({id:e.id,name:e.name,description:e.description})});function g(e){return e.metadata?.sync!==!1}function _(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>g(e)?r.resourceServers?r.resourceServers(e):!0:!1,s=e=>g(e)?r.roles?r.roles(e):!0:!1,c=i?f(e,m,o):void 0,l=a?f(e,h,s):void 0,u=i?p(e,m,o):void 0,d=a?p(e,h,s):void 0,_=a?{async afterCreate(n,i){if(i.id!==e.controlPlaneTenantId){await d?.afterCreate?.(n,i);try{let n=await e.getControlPlaneAdapters(),a=await e.getAdapters(i.id),o=await(0,t.fetchAll)(t=>n.roles.list(e.controlPlaneTenantId,t),`roles`,{cursorField:`id`,pageSize:100}),s=new Map;for(let e of o.filter(e=>r.roles?.(e)??!0)){let t=await v(a,i.id,e.name);t&&s.set(e.name,t.id)}for(let t of o.filter(e=>r.roles?.(e)??!0)){let r=s.get(t.name);if(r)try{let o=await n.rolePermissions.list(e.controlPlaneTenantId,t.id,{});o.length>0&&await a.rolePermissions.assign(i.id,r,o.map(e=>({role_id:r,resource_server_identifier:e.resource_server_identifier,permission_name:e.permission_name})))}catch(e){console.error(`Failed to sync permissions for role "${t.name}" to tenant "${i.id}":`,e)}}}catch(e){console.error(`Failed to sync role permissions to tenant "${i.id}":`,e)}}}}:void 0;async function v(e,t,n){return(await e.roles.list(t,{q:`name:${n}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:c,roles:l},tenantHooks:{async afterCreate(e,t){let n=[u?.afterCreate,_?.afterCreate??d?.afterCreate],r=[];for(let i of n)if(i)try{await i(e,t)}catch(e){r.push(e instanceof Error?e:Error(String(e)))}if(r.length===1)throw r[0];if(r.length>1)throw AggregateError(r,r.map(e=>e.message).join(`; `))}}}}var v=n.z.object({sub:n.z.string(),tenant_id:n.z.string().optional(),org_id:n.z.string().optional(),scope:n.z.string().optional(),permissions:n.z.array(n.z.string()).optional()}).passthrough();function y(e){let t=v.safeParse(e);return t.success?t.data:void 0}function b(e){let t=e.permissions??[],n=e.scope?e.scope.split(` `).filter(Boolean):[],r=new Set([...t,...n]);return r.has(`delete:tenants`)||r.has(`admin:organizations`)}function x(e,i){let a=new n.OpenAPIHono;return a.openapi((0,n.createRoute)({tags:[`tenants`],method:`get`,path:`/`,request:{query:t.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:n.z.object({tenants:n.z.array(t.tenantSchema),start:n.z.number().optional(),limit:n.z.number().optional(),length:n.z.number().optional()})}},description:`List of tenants`}}}),async n=>{let{page:i,per_page:a,include_totals:o,q:s}=n.req.valid(`query`),c=n.var.user,l=c?.permissions||[];if(!(c?.org_id??n.var.organization_id)&&l.includes(`admin:organizations`)){let e=await n.env.data.tenants.list({page:i,per_page:a,include_totals:o,q:s});return o?n.json({tenants:e.tenants,start:e.totals?.start??0,limit:e.totals?.limit??a,length:e.tenants.length}):n.json({tenants:e.tenants})}let u=e.accessControl?.controlPlaneTenantId??n.env.data.multiTenancyConfig?.controlPlaneTenantId;if(u&&!c?.sub)throw new r.HTTPException(403,{message:`Access denied: token has no subject`});if(u&&c?.sub){let e=(await(0,t.fetchAll)(e=>n.env.data.userOrganizations.listUserOrganizations(u,c.sub,e),`organizations`)).map(e=>e.name);if(e.length===0)return o?n.json({tenants:[],start:0,limit:a??50,length:0}):n.json({tenants:[]});let r=e.length,l=i??0,d=a??50,f=l*d,p=e.slice(f,f+d);if(p.length===0)return o?n.json({tenants:[],start:f,limit:d,length:r}):n.json({tenants:[]});let m=p.map(e=>`id:${e}`).join(` OR `),h=s?`(${m}) AND (${s})`:m,g=await n.env.data.tenants.list({q:h,per_page:d,include_totals:!1});return o?n.json({tenants:g.tenants,start:f,limit:d,length:r}):n.json({tenants:g.tenants})}let d=await n.env.data.tenants.list({page:i,per_page:a,include_totals:o,q:s});return o?n.json({tenants:d.tenants,start:d.totals?.start??0,limit:d.totals?.limit??a,length:d.tenants.length}):n.json({tenants:d.tenants})}),a.openapi((0,n.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 e=>{if(!e.var.user?.sub)throw new r.HTTPException(401,{message:`Authentication required to create tenants`});let t=e.req.valid(`json`),n={adapters:e.env.data,ctx:e};i.tenants?.beforeCreate&&(t=await i.tenants.beforeCreate(n,t));let a=await e.env.data.tenants.create(t);return i.tenants?.afterCreate&&await i.tenants.afterCreate(n,a),e.json(a,201)}),a.openapi((0,n.createRoute)({tags:[`tenants`],method:`delete`,path:`/{id}`,request:{params:n.z.object({id:n.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 n=>{let{id:a}=n.req.valid(`param`),o=e.accessControl?.controlPlaneTenantId??n.env.data.multiTenancyConfig?.controlPlaneTenantId;if(o){let e=y(n.var.user);if(!e?.sub)throw new r.HTTPException(401,{message:`Authentication required`});if(a===o)throw new r.HTTPException(403,{message:`Cannot delete the control plane`});let i=n.var.org_name,s=a.toLowerCase(),c=!!i&&i.toLowerCase()===s;if(!c){let t=!!(e.org_id??n.var.organization_id??i),r=!e.tenant_id||e.tenant_id===o;!t&&r&&b(e)&&(c=!0)}if(c||=(await(0,t.fetchAll)(t=>n.env.data.userOrganizations.listUserOrganizations(o,e.sub,t),`organizations`)).some(e=>e.name?.toLowerCase()===s),!c)throw new r.HTTPException(403,{message:`Access denied to this tenant`})}if(!await n.env.data.tenants.get(a))throw new r.HTTPException(404,{message:`Tenant not found`});let s={adapters:n.env.data,ctx:n};return i.tenants?.beforeDelete&&await i.tenants.beforeDelete(s,a),await n.env.data.tenants.remove(a),i.tenants?.afterDelete&&await i.tenants.afterDelete(s,a),n.body(null,204)}),a.openapi((0,n.createRoute)({tags:[`tenants`,`settings`],method:`get`,path:`/settings`,request:{headers:n.z.object({"tenant-id":n.z.string().optional()})},security:[{Bearer:[`read:tenants`]}],responses:{200:{content:{"application/json":{schema:t.tenantSchema}},description:`Current tenant settings`}}}),async e=>{let t=await e.env.data.tenants.get(e.var.tenant_id);if(!t)throw new r.HTTPException(404,{message:`Tenant not found`});return e.json(t)}),a.openapi((0,n.createRoute)({tags:[`tenants`,`settings`],method:`patch`,path:`/settings`,request:{headers:n.z.object({"tenant-id":n.z.string().optional()}),body:{content:{"application/json":{schema:n.z.object(t.tenantInsertSchema.shape).partial()}}}},security:[{Bearer:[`update:tenants`]}],responses:{200:{content:{"application/json":{schema:t.tenantSchema}},description:`Updated tenant settings`}}}),async e=>{let{id:n,...i}=e.req.valid(`json`),a=await e.env.data.tenants.get(e.var.tenant_id);if(!a)throw new r.HTTPException(404,{message:`Tenant not found`});let o=(0,t.deepMergePatch)(a,i);await e.env.data.tenants.update(e.var.tenant_id,o);let s=await e.env.data.tenants.get(e.var.tenant_id);if(!s)throw new r.HTTPException(500,{message:`Failed to retrieve updated tenant`});return e.json(s)}),a}function S(e){for(let{pattern:t,type:n}of[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:`resource_server`},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:`role`},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:`connection`}]){let r=e.match(t);if(r&&r[1])return{type:n,id:r[1]}}return null}async function C(e,t,n){try{switch(n.type){case`resource_server`:return(await e.resourceServers.get(t,n.id))?.is_system===!0;case`role`:return(await e.roles.get(t,n.id))?.is_system===!0;case`connection`:return(await e.connections.get(t,n.id))?.is_system===!0;default:return!1}}catch{return!1}}function w(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function T(){return async(e,t)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return t();let n=S(e.req.path);if(!n)return t();let i=e.var.tenant_id||e.req.header(`x-tenant-id`)||e.req.header(`tenant-id`);if(!i)return t();if(await C(e.env.data,i,n))throw new r.HTTPException(403,{message:`This ${w(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function E(e,n){let r=n.find(t=>t.strategy===e.strategy);if(!r?.options)return e;let i=t.connectionSchema.passthrough().parse({...r,...e});return i.options=t.connectionOptionsSchema.passthrough().parse({...r.options||{},...e.options}),i}function D(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function O(e,t){if(!t?.length)return e||[];if(!e?.length)return t;let n=new Map;for(let e of t)n.set(e.value,e);for(let t of e)n.set(t.value,t);return Array.from(n.values())}function k(e,t){return t?{...e,scopes:O(e.scopes,t.scopes)}:e}function ee(e,t){return t?{...e,callbacks:D(e.callbacks,t.callbacks),web_origins:D(e.web_origins,t.web_origins),allowed_logout_urls:D(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:D(e.allowed_origins,t.allowed_origins)}:e}function A(e){let{controlPlaneTenantId:t,controlPlaneClientId:n,resolveControlPlane:r}=e;if(r)return async e=>r({tenant_id:e});if(!t)return async()=>void 0;let i={tenantId:t,clientId:n};return async()=>i}function j(e,t){return{...e.resourceServers,get:async(n,r)=>{let i=await e.resourceServers.get(n,r);if(!i)return i;let a=await t(n);return!a||n===a.tenantId||!i.is_system?i:k(i,await e.resourceServers.get(a.tenantId,r))},list:async(n,r)=>{let i=await e.resourceServers.list(n,r),a=await t(n);if(!a||n===a.tenantId)return i;let o=a.tenantId,s=i.resource_servers.filter(e=>!!(e.is_system&&e.id)).map(e=>e.id);if(s.length===0)return i;let c=new Map;await Promise.all(s.map(async t=>{let n=await e.resourceServers.get(o,t);n&&c.set(t,n)}));let l=i.resource_servers.map(e=>e.is_system&&e.id?k(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function M(e,t){let n=A({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:j(e,n)}}function N(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i}=t,a=A({controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i});return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i},connections:{...e.connections,get:async(t,n)=>{let r=await e.connections.get(t,n);if(!r)return r;let i=await a(t);return!i||t===i.tenantId?r:E(r,(await e.connections.list(i.tenantId)).connections||[])},list:async(t,n)=>{let r=await e.connections.list(t,n),i=await a(t);if(!i||t===i.tenantId)return r;let o=await e.connections.list(i.tenantId),s=r.connections.map(e=>E(e,o.connections||[]));return{...r,connections:s}}},clientConnections:{...e.clientConnections,listByClient:async(t,n)=>{let r=await e.clientConnections.listByClient(t,n);r.length===0&&(r=(await e.connections.list(t)).connections||[]);let i=await a(t);if(!i||t===i.tenantId)return r;let o=await e.connections.list(i.tenantId);return r.map(e=>E(e,o.connections||[]))}},emailProviders:{...e.emailProviders,get:async t=>{let n=await e.emailProviders.get(t);if(n)return n;let r=await a(t);return!r||t===r.tenantId?null:e.emailProviders.get(r.tenantId)}},resourceServers:j(e,a),hooks:te(e,a)}}function P(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function te(e,t){return{...e.hooks,list:async(n,r)=>{let i=await e.hooks.list(n,r),a=await t(n);if(!a||n===a.tenantId)return i;let o=((await e.hooks.list(a.tenantId,r)).hooks||[]).filter(P);if(o.length===0)return i;let s=new Set((i.hooks||[]).map(e=>e.hook_id)),c=o.filter(e=>!s.has(e.hook_id));return{...i,hooks:[...i.hooks||[],...c],length:typeof i.length==`number`?i.length+c.length:i.length}},get:async(n,r)=>{let i=await e.hooks.get(n,r);if(i)return i;let a=await t(n);if(!a||n===a.tenantId)return i;let o=await e.hooks.get(a.tenantId,r);return o&&P(o)?o:null}}}function F(e,t){return N(e,t)}function I(e){return async(t,n)=>{let r=t.var.user;return r?.tenant_id===e&&r.org_name&&t.set(`tenant_id`,r.org_name),n()}}function L(e){return async(n,i)=>{if(!e.accessControl)return i();let{controlPlaneTenantId:o}=e.accessControl,s=n.var.org_name,c=n.var.organization_id,l=s||c,u=n.var.tenant_id,d=n.var.user,f=(d?.aud?Array.isArray(d.aud)?d.aud:[d.aud]:[]).includes(t.MANAGEMENT_API_AUDIENCE);if(!u&&l&&f&&(n.set(`tenant_id`,l),u=l),!u)throw new r.HTTPException(400,{message:`Tenant ID not found in request`});if(!a(c,u,o,s))throw new r.HTTPException(403,{message:`Access denied to tenant ${u}`});return i()}}function R(e){return async(t,n)=>{if(!e.subdomainRouting)return n();let{baseDomain:i,reservedSubdomains:a=[],resolveSubdomain:o}=e.subdomainRouting,s=t.req.header(`x-forwarded-host`)||t.req.header(`host`)||``,c=null;if(s.endsWith(i)){let e=s.slice(0,-(i.length+1));e&&!e.includes(`.`)&&(c=e)}if(c&&a.includes(c)&&(c=null),!c)return e.accessControl&&t.set(`tenant_id`,e.accessControl.controlPlaneTenantId),n();let l=null;if(o)l=await o(c);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{let n=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,c);n&&(l=n.id)}catch{}if(!l)throw new r.HTTPException(404,{message:`Tenant not found for subdomain: ${c}`});return t.set(`tenant_id`,l),n()}}function z(e){return async(t,n)=>{if(!e.databaseIsolation)return n();let i=t.var.tenant_id;if(!i)throw new r.HTTPException(400,{message:`Tenant ID not found in request`});try{let n=await e.databaseIsolation.getAdapters(i);t.env.data=n}catch(e){throw console.error(`Failed to resolve database for tenant ${i}:`,e),new r.HTTPException(500,{message:`Failed to resolve tenant database`})}return n()}}function B(e){let t=R(e),n=L(e),r=z(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}function ne(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,sync:s={resourceServers:!0,roles:!0},defaultPermissions:l=[`tenant:admin`],requireOrganizationMatch:u=!1,managementApiExtensions:d=[],entityHooks:f,getChildTenantIds:p,getAdapters:m,...h}=e;if(o&&!r)throw Error("initMultiTenant: `resolveControlPlane` requires `controlPlane` to be set. The static `controlPlane.tenantId` is used for access control, sync direction, and tenant management routing; the resolver only overrides per-tenant runtime inheritance lookups on top of it.");let g=n,v=n;r&&(g=F(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),v={...M(n,{controlPlaneTenantId:i,resolveControlPlane:o}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}});let y=s!==!1,b=y?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:S,tenantHooks:C}=_({controlPlaneTenantId:i,getChildTenantIds:p??(async()=>(await(0,t.fetchAll)(e=>g.tenants.list(e),`tenants`,{cursorField:`id`,pageSize:100})).filter(e=>e.id!==i).map(e=>e.id)),getAdapters:m??(async()=>g),getControlPlaneAdapters:async()=>g,sync:b}),w={resourceServers:[S.resourceServers,...f?.resourceServers??[]],roles:[S.roles,...f?.roles??[]],connections:f?.connections??[],tenants:f?.tenants??[],rolePermissions:f?.rolePermissions??[]},E=c({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:u,defaultPermissions:l}}),D=x({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:u,defaultPermissions:l}},{tenants:{async beforeCreate(e,t){return E.beforeCreate&&(t=await E.beforeCreate(e,t)),C.beforeCreate&&(t=await C.beforeCreate(e,t)),t},async afterCreate(e,t){await E.afterCreate?.(e,t),await C.afterCreate?.(e,t)},async beforeDelete(e,t){await E.beforeDelete?.(e,t),await C.beforeDelete?.(e,t)}}}),{app:O}=(0,t.init)({dataAdapter:g,managementDataAdapter:v,...h,entityHooks:w,managementApiExtensions:[...d,{path:`/tenants`,router:D}]});return O.use(`/api/v2/*`,I(i)),y&&O.use(`/api/v2/*`,T()),{app:O,controlPlaneTenantId:i}}function V(e={}){return{connections:e.connections??!0,resourceServers:e.resourceServers??!0,hooks:e.hooks??!0,emailProvider:e.emailProvider??!0,branding:e.branding??!0,promptSettings:e.promptSettings??!0}}function H(){return{upserted:0,errors:[]}}function U(e){return{tenantId:e,connections:H(),resourceServers:H(),hooks:H(),emailProvider:H(),branding:H(),promptSettings:H()}}function W(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function G(e,t,n,r){try{await r()}catch(r){let i=`${t}: ${r instanceof Error?r.message:String(r)}`;if(!n)throw Error(i,{cause:r});e.errors.push(i)}}async function K(e,n,r){return{connections:r.connections?await(0,t.fetchAll)(t=>e.connections.list(n,t),`connections`,{cursorField:`id`,pageSize:100}):[],resourceServers:r.resourceServers?await(0,t.fetchAll)(t=>e.resourceServers.list(n,t),`resource_servers`,{cursorField:`id`,pageSize:100}):[],hooks:r.hooks?await(0,t.fetchAll)(t=>e.hooks.list(n,t),`hooks`,{cursorField:`hook_id`,pageSize:100}):[],emailProvider:r.emailProvider?await e.emailProviders.get(n)??null:null,branding:r.branding?await e.branding.get(n)??null:null,promptSettings:r.promptSettings?await e.promptSettings.get(n)??null:null}}async function q(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await G(o.connections,`connection ${e}`,a,async()=>{let a=t.connectionInsertSchema.parse(i);await n.connections.get(r,e)?await n.connections.update(r,e,a):await n.connections.create(r,a),o.connections.upserted+=1})}if(i.resourceServers)for(let i of e.resourceServers)!i.is_system||!i.id||await G(o.resourceServers,`resource_server ${i.id}`,a,async()=>{let e=t.resourceServerInsertSchema.parse(i);await n.resourceServers.get(r,i.id)?await n.resourceServers.update(r,i.id,e):await n.resourceServers.create(r,e),o.resourceServers.upserted+=1});if(i.hooks)for(let i of e.hooks)!W(i)||!i.hook_id||await G(o.hooks,`hook ${i.hook_id}`,a,async()=>{let e=t.hookInsertSchema.parse(i);await n.hooks.get(r,i.hook_id)?await n.hooks.update(r,i.hook_id,e):await n.hooks.create(r,e),o.hooks.upserted+=1});i.emailProvider&&e.emailProvider&&await G(o.emailProvider,`email_provider`,a,async()=>{let t=e.emailProvider;await n.emailProviders.get(r)?await n.emailProviders.update(r,t):await n.emailProviders.create(r,t),o.emailProvider.upserted+=1}),i.branding&&e.branding&&await G(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await G(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function J(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=V(a),c=await K(await r(),n,s),l=await i(t),u=U(t);return await q(c,l,n,s,o,u),u}function Y(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function X(e,n,r={},i){let a=V(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await K(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(Y):[],u=s?await re(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(W),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function re(e,t,n){let r=n&&n!==t?[t,n]:[t],i=[];for(let t of r){let n=await e.tenants.get(t);i.push({id:t,friendly_name:n?.friendly_name||t})}return i}async function Z(e,n,r){let i=H();if(e.length===0)return i;let a=await(0,t.listControlPlaneKeys)(n.keys),o=new Set(a.map(e=>e.kid));for(let t of e)await G(i,`signing_key ${t.kid}`,r,async()=>{let e=Y(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function ie(e,t,n){let r=H();for(let i of e)await G(r,`tenant ${i.id}`,n,async()=>{await t.tenants.get(i.id)||(await t.tenants.create({id:i.id,friendly_name:i.friendly_name}),r.upserted+=1)});return r}async function ae(e,n,r,i={}){let a=i.continueOnError??!1,o=V(i.entities),s=i.entities?.signingKeys??!0,c=i.entities?.tenants??!0,l={connections:e.connections,resourceServers:e.resourceServers,hooks:e.hooks,emailProvider:e.emailProvider?t.emailProviderSchema.parse(e.emailProvider):null,branding:e.branding?t.brandingSchema.parse(e.branding):null,promptSettings:e.promptSettings?t.promptSettingSchema.parse(e.promptSettings):null},u=c?await ie(e.tenants??[],n,a):H(),d=U(r);await q(l,n,r,o,a,d);let f=s?await Z(e.signingKeys,n,a):H();return{...d,signingKeys:f,tenants:u}}function oe(e){return{syncDefaults:t=>J(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await J(e,r));return n}}}function se(e){let t=Q(e);return{name:`multi-tenancy`,middleware:B(e),hooks:t,routes:[{path:`/management`,handler:x(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 Q(e){let t=e.accessControl?i(e.accessControl):{},n=e.databaseIsolation?o(e.databaseIsolation):{},r=c(e);return{...t,...n,tenants:r}}function $(t){let n=new e.Hono,r=Q(t);return n.route(`/tenants`,x(t,r)),n}function ce(e){return{hooks:Q(e),middleware:B(e),app:$(e),config:e,wrapAdapters:(t,n)=>F(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.applyControlPlaneDefaultsPayload=ae,exports.buildControlPlaneDefaultsPayload=X,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=L,exports.createControlPlaneTenantMiddleware=I,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=z,exports.createDirectRolloutAdapter=oe,exports.createMultiTenancy=$,exports.createMultiTenancyHooks=Q,exports.createMultiTenancyMiddleware=B,exports.createMultiTenancyPlugin=se,exports.createProtectSyncedMiddleware=T,exports.createProvisioningHooks=c,exports.createRuntimeFallbackAdapter=N,exports.createSubdomainMiddleware=R,exports.createSyncHooks=_,exports.createTenantsOpenAPIRouter=x,exports.initMultiTenant=ne,exports.mergeClientWithFallback=ee,exports.projectControlPlaneDefaults=J,exports.setupMultiTenancy=ce,exports.validateTenantAccess=a,exports.withRuntimeFallback=F,exports.withSystemResourceServerInheritance=M;
@@ -214,11 +214,11 @@ var k = (e) => ({
214
214
  description: e.description
215
215
  })
216
216
  });
217
- function re(e) {
217
+ function j(e) {
218
218
  return e.metadata?.sync !== !1;
219
219
  }
220
- function ie(e) {
221
- let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) => re(e) ? n.resourceServers ? n.resourceServers(e) : !0 : !1, o = (e) => re(e) ? n.roles ? n.roles(e) : !0 : !1, s = r ? D(e, k, a) : void 0, c = i ? D(e, A, o) : void 0, l = r ? O(e, k, a) : void 0, d = i ? O(e, A, o) : void 0, f = i ? { async afterCreate(t, r) {
220
+ function re(e) {
221
+ let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) => j(e) ? n.resourceServers ? n.resourceServers(e) : !0 : !1, o = (e) => j(e) ? n.roles ? n.roles(e) : !0 : !1, s = r ? D(e, k, a) : void 0, c = i ? D(e, A, o) : void 0, l = r ? O(e, k, a) : void 0, d = i ? O(e, A, o) : void 0, f = i ? { async afterCreate(t, r) {
222
222
  if (r.id !== e.controlPlaneTenantId) {
223
223
  await d?.afterCreate?.(t, r);
224
224
  try {
@@ -273,22 +273,22 @@ function ie(e) {
273
273
  }
274
274
  //#endregion
275
275
  //#region src/routes/tenants.ts
276
- var ae = b.object({
276
+ var ie = b.object({
277
277
  sub: b.string(),
278
278
  tenant_id: b.string().optional(),
279
279
  org_id: b.string().optional(),
280
280
  scope: b.string().optional(),
281
281
  permissions: b.array(b.string()).optional()
282
282
  }).passthrough();
283
- function oe(e) {
284
- let t = ae.safeParse(e);
283
+ function ae(e) {
284
+ let t = ie.safeParse(e);
285
285
  return t.success ? t.data : void 0;
286
286
  }
287
- function se(e) {
287
+ function oe(e) {
288
288
  let t = e.permissions ?? [], n = e.scope ? e.scope.split(" ").filter(Boolean) : [], r = new Set([...t, ...n]);
289
289
  return r.has("delete:tenants") || r.has("admin:organizations");
290
290
  }
291
- function j(e, t) {
291
+ function M(e, t) {
292
292
  let n = new v();
293
293
  return n.openapi(y({
294
294
  tags: ["tenants"],
@@ -399,13 +399,13 @@ function j(e, t) {
399
399
  }), async (n) => {
400
400
  let { id: r } = n.req.valid("param"), i = e.accessControl?.controlPlaneTenantId ?? n.env.data.multiTenancyConfig?.controlPlaneTenantId;
401
401
  if (i) {
402
- let e = oe(n.var.user);
402
+ let e = ae(n.var.user);
403
403
  if (!e?.sub) throw new x(401, { message: "Authentication required" });
404
404
  if (r === i) throw new x(403, { message: "Cannot delete the control plane" });
405
405
  let t = n.var.org_name, a = r.toLowerCase(), o = !!t && t.toLowerCase() === a;
406
406
  if (!o) {
407
407
  let r = !!(e.org_id ?? n.var.organization_id ?? t), a = !e.tenant_id || e.tenant_id === i;
408
- !r && a && se(e) && (o = !0);
408
+ !r && a && oe(e) && (o = !0);
409
409
  }
410
410
  if (o ||= (await u((t) => n.env.data.userOrganizations.listUserOrganizations(i, e.sub, t), "organizations")).some((e) => e.name?.toLowerCase() === a), !o) throw new x(403, { message: "Access denied to this tenant" });
411
411
  }
@@ -454,7 +454,7 @@ function j(e, t) {
454
454
  }
455
455
  //#endregion
456
456
  //#region src/middleware/protect-synced.ts
457
- function ce(e) {
457
+ function se(e) {
458
458
  for (let { pattern: t, type: n } of [
459
459
  {
460
460
  pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
@@ -477,7 +477,7 @@ function ce(e) {
477
477
  }
478
478
  return null;
479
479
  }
480
- async function le(e, t, n) {
480
+ async function ce(e, t, n) {
481
481
  try {
482
482
  switch (n.type) {
483
483
  case "resource_server": return (await e.resourceServers.get(t, n.id))?.is_system === !0;
@@ -489,31 +489,31 @@ async function le(e, t, n) {
489
489
  return !1;
490
490
  }
491
491
  }
492
- function ue(e) {
492
+ function le(e) {
493
493
  return {
494
494
  resource_server: "resource server",
495
495
  role: "role",
496
496
  connection: "connection"
497
497
  }[e];
498
498
  }
499
- function M() {
499
+ function N() {
500
500
  return async (e, t) => {
501
501
  if (![
502
502
  "PATCH",
503
503
  "PUT",
504
504
  "DELETE"
505
505
  ].includes(e.req.method)) return t();
506
- let n = ce(e.req.path);
506
+ let n = se(e.req.path);
507
507
  if (!n) return t();
508
508
  let r = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
509
509
  if (!r) return t();
510
- if (await le(e.env.data, r, n)) throw new x(403, { message: `This ${ue(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.` });
510
+ if (await ce(e.env.data, r, n)) throw new x(403, { message: `This ${le(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.` });
511
511
  return t();
512
512
  };
513
513
  }
514
514
  //#endregion
515
515
  //#region src/middleware/settings-inheritance.ts
516
- function N(e, t) {
516
+ function P(e, t) {
517
517
  let n = t.find((t) => t.strategy === e.strategy);
518
518
  if (!n?.options) return e;
519
519
  let r = s.passthrough().parse({
@@ -525,11 +525,11 @@ function N(e, t) {
525
525
  ...e.options
526
526
  }), r;
527
527
  }
528
- function P(e, t) {
528
+ function F(e, t) {
529
529
  let n = [...t || [], ...e || []];
530
530
  return [...new Set(n)];
531
531
  }
532
- function de(e, t) {
532
+ function ue(e, t) {
533
533
  if (!t?.length) return e || [];
534
534
  if (!e?.length) return t;
535
535
  let n = /* @__PURE__ */ new Map();
@@ -537,22 +537,22 @@ function de(e, t) {
537
537
  for (let t of e) n.set(t.value, t);
538
538
  return Array.from(n.values());
539
539
  }
540
- function F(e, t) {
540
+ function I(e, t) {
541
541
  return t ? {
542
542
  ...e,
543
- scopes: de(e.scopes, t.scopes)
543
+ scopes: ue(e.scopes, t.scopes)
544
544
  } : e;
545
545
  }
546
- function fe(e, t) {
546
+ function de(e, t) {
547
547
  return t ? {
548
548
  ...e,
549
- callbacks: P(e.callbacks, t.callbacks),
550
- web_origins: P(e.web_origins, t.web_origins),
551
- allowed_logout_urls: P(e.allowed_logout_urls, t.allowed_logout_urls),
552
- allowed_origins: P(e.allowed_origins, t.allowed_origins)
549
+ callbacks: F(e.callbacks, t.callbacks),
550
+ web_origins: F(e.web_origins, t.web_origins),
551
+ allowed_logout_urls: F(e.allowed_logout_urls, t.allowed_logout_urls),
552
+ allowed_origins: F(e.allowed_origins, t.allowed_origins)
553
553
  } : e;
554
554
  }
555
- function I(e) {
555
+ function L(e) {
556
556
  let { controlPlaneTenantId: t, controlPlaneClientId: n, resolveControlPlane: r } = e;
557
557
  if (r) return async (e) => r({ tenant_id: e });
558
558
  if (!t) return async () => void 0;
@@ -562,14 +562,14 @@ function I(e) {
562
562
  };
563
563
  return async () => i;
564
564
  }
565
- function L(e, t) {
565
+ function R(e, t) {
566
566
  return {
567
567
  ...e.resourceServers,
568
568
  get: async (n, r) => {
569
569
  let i = await e.resourceServers.get(n, r);
570
570
  if (!i) return i;
571
571
  let a = await t(n);
572
- return !a || n === a.tenantId || !i.is_system ? i : F(i, await e.resourceServers.get(a.tenantId, r));
572
+ return !a || n === a.tenantId || !i.is_system ? i : I(i, await e.resourceServers.get(a.tenantId, r));
573
573
  },
574
574
  list: async (n, r) => {
575
575
  let i = await e.resourceServers.list(n, r), a = await t(n);
@@ -581,7 +581,7 @@ function L(e, t) {
581
581
  let n = await e.resourceServers.get(o, t);
582
582
  n && c.set(t, n);
583
583
  }));
584
- let l = i.resource_servers.map((e) => e.is_system && e.id ? F(e, c.get(e.id) ?? null) : e);
584
+ let l = i.resource_servers.map((e) => e.is_system && e.id ? I(e, c.get(e.id) ?? null) : e);
585
585
  return {
586
586
  ...i,
587
587
  resource_servers: l
@@ -589,18 +589,18 @@ function L(e, t) {
589
589
  }
590
590
  };
591
591
  }
592
- function R(e, t) {
593
- let n = I({
592
+ function z(e, t) {
593
+ let n = L({
594
594
  controlPlaneTenantId: t.controlPlaneTenantId,
595
595
  resolveControlPlane: t.resolveControlPlane
596
596
  });
597
597
  return {
598
598
  ...e,
599
- resourceServers: L(e, n)
599
+ resourceServers: R(e, n)
600
600
  };
601
601
  }
602
- function z(e, t) {
603
- let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i } = t, a = I({
602
+ function B(e, t) {
603
+ let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i } = t, a = L({
604
604
  controlPlaneTenantId: n,
605
605
  controlPlaneClientId: r,
606
606
  resolveControlPlane: i
@@ -618,12 +618,12 @@ function z(e, t) {
618
618
  let r = await e.connections.get(t, n);
619
619
  if (!r) return r;
620
620
  let i = await a(t);
621
- return !i || t === i.tenantId ? r : N(r, (await e.connections.list(i.tenantId)).connections || []);
621
+ return !i || t === i.tenantId ? r : P(r, (await e.connections.list(i.tenantId)).connections || []);
622
622
  },
623
623
  list: async (t, n) => {
624
624
  let r = await e.connections.list(t, n), i = await a(t);
625
625
  if (!i || t === i.tenantId) return r;
626
- let o = await e.connections.list(i.tenantId), s = r.connections.map((e) => N(e, o.connections || []));
626
+ let o = await e.connections.list(i.tenantId), s = r.connections.map((e) => P(e, o.connections || []));
627
627
  return {
628
628
  ...r,
629
629
  connections: s
@@ -638,7 +638,7 @@ function z(e, t) {
638
638
  let i = await a(t);
639
639
  if (!i || t === i.tenantId) return r;
640
640
  let o = await e.connections.list(i.tenantId);
641
- return r.map((e) => N(e, o.connections || []));
641
+ return r.map((e) => P(e, o.connections || []));
642
642
  }
643
643
  },
644
644
  emailProviders: {
@@ -650,22 +650,22 @@ function z(e, t) {
650
650
  return !r || t === r.tenantId ? null : e.emailProviders.get(r.tenantId);
651
651
  }
652
652
  },
653
- resourceServers: L(e, a),
654
- hooks: pe(e, a)
653
+ resourceServers: R(e, a),
654
+ hooks: fe(e, a)
655
655
  };
656
656
  }
657
- function B(e) {
657
+ function V(e) {
658
658
  if (!e || typeof e != "object") return !1;
659
659
  let t = e.metadata;
660
660
  return !t || typeof t != "object" ? !1 : t.inheritable === !0;
661
661
  }
662
- function pe(e, t) {
662
+ function fe(e, t) {
663
663
  return {
664
664
  ...e.hooks,
665
665
  list: async (n, r) => {
666
666
  let i = await e.hooks.list(n, r), a = await t(n);
667
667
  if (!a || n === a.tenantId) return i;
668
- let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(B);
668
+ let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(V);
669
669
  if (o.length === 0) return i;
670
670
  let s = new Set((i.hooks || []).map((e) => e.hook_id)), c = o.filter((e) => !s.has(e.hook_id));
671
671
  return {
@@ -680,22 +680,22 @@ function pe(e, t) {
680
680
  let a = await t(n);
681
681
  if (!a || n === a.tenantId) return i;
682
682
  let o = await e.hooks.get(a.tenantId, r);
683
- return o && B(o) ? o : null;
683
+ return o && V(o) ? o : null;
684
684
  }
685
685
  };
686
686
  }
687
- function V(e, t) {
688
- return z(e, t);
687
+ function H(e, t) {
688
+ return B(e, t);
689
689
  }
690
690
  //#endregion
691
691
  //#region src/middleware/index.ts
692
- function H(e) {
692
+ function U(e) {
693
693
  return async (t, n) => {
694
694
  let r = t.var.user;
695
695
  return r?.tenant_id === e && r.org_name && t.set("tenant_id", r.org_name), n();
696
696
  };
697
697
  }
698
- function U(e) {
698
+ function W(e) {
699
699
  return async (n, r) => {
700
700
  if (!e.accessControl) return r();
701
701
  let { controlPlaneTenantId: i } = e.accessControl, a = n.var.org_name, o = n.var.organization_id, s = a || o, c = n.var.tenant_id, l = n.var.user, u = (l?.aud ? Array.isArray(l.aud) ? l.aud : [l.aud] : []).includes(t);
@@ -704,7 +704,7 @@ function U(e) {
704
704
  return r();
705
705
  };
706
706
  }
707
- function W(e) {
707
+ function G(e) {
708
708
  return async (t, n) => {
709
709
  if (!e.subdomainRouting) return n();
710
710
  let { baseDomain: r, reservedSubdomains: i = [], resolveSubdomain: a } = e.subdomainRouting, o = t.req.header("x-forwarded-host") || t.req.header("host") || "", s = null;
@@ -723,7 +723,7 @@ function W(e) {
723
723
  return t.set("tenant_id", c), n();
724
724
  };
725
725
  }
726
- function G(e) {
726
+ function K(e) {
727
727
  return async (t, n) => {
728
728
  if (!e.databaseIsolation) return n();
729
729
  let r = t.var.tenant_id;
@@ -737,25 +737,25 @@ function G(e) {
737
737
  return n();
738
738
  };
739
739
  }
740
- function K(e) {
741
- let t = W(e), n = U(e), r = G(e);
740
+ function q(e) {
741
+ let t = G(e), n = W(e), r = K(e);
742
742
  return async (e, i) => (await t(e, async () => {}), await n(e, async () => {}), await r(e, async () => {}), i());
743
743
  }
744
744
  //#endregion
745
745
  //#region src/init.ts
746
- function me(e) {
746
+ function pe(e) {
747
747
  let { dataAdapter: t, controlPlane: n, controlPlane: { tenantId: r = "control_plane", clientId: i } = {}, resolveControlPlane: a, sync: o = {
748
748
  resourceServers: !0,
749
749
  roles: !0
750
750
  }, defaultPermissions: s = ["tenant:admin"], requireOrganizationMatch: c = !1, managementApiExtensions: l = [], entityHooks: d, getChildTenantIds: p, getAdapters: m, ...h } = e;
751
751
  if (a && !n) throw Error("initMultiTenant: `resolveControlPlane` requires `controlPlane` to be set. The static `controlPlane.tenantId` is used for access control, sync direction, and tenant management routing; the resolver only overrides per-tenant runtime inheritance lookups on top of it.");
752
752
  let g = t, _ = t;
753
- n && (g = V(t, {
753
+ n && (g = H(t, {
754
754
  controlPlaneTenantId: r,
755
755
  controlPlaneClientId: i,
756
756
  resolveControlPlane: a
757
757
  }), _ = {
758
- ...R(t, {
758
+ ...z(t, {
759
759
  controlPlaneTenantId: r,
760
760
  resolveControlPlane: a
761
761
  }),
@@ -771,7 +771,7 @@ function me(e) {
771
771
  } : {
772
772
  resourceServers: !1,
773
773
  roles: !1
774
- }, { entityHooks: b, tenantHooks: x } = ie({
774
+ }, { entityHooks: b, tenantHooks: x } = re({
775
775
  controlPlaneTenantId: r,
776
776
  getChildTenantIds: p ?? (async () => (await u((e) => g.tenants.list(e), "tenants", {
777
777
  cursorField: "id",
@@ -790,7 +790,7 @@ function me(e) {
790
790
  controlPlaneTenantId: r,
791
791
  requireOrganizationMatch: c,
792
792
  defaultPermissions: s
793
- } }), w = j({ accessControl: {
793
+ } }), w = M({ accessControl: {
794
794
  controlPlaneTenantId: r,
795
795
  requireOrganizationMatch: c,
796
796
  defaultPermissions: s
@@ -814,14 +814,14 @@ function me(e) {
814
814
  router: w
815
815
  }]
816
816
  });
817
- return T.use("/api/v2/*", H(r)), v && T.use("/api/v2/*", M()), {
817
+ return T.use("/api/v2/*", U(r)), v && T.use("/api/v2/*", N()), {
818
818
  app: T,
819
819
  controlPlaneTenantId: r
820
820
  };
821
821
  }
822
822
  //#endregion
823
823
  //#region src/rollout/defaults-projection.ts
824
- function q(e = {}) {
824
+ function J(e = {}) {
825
825
  return {
826
826
  connections: e.connections ?? !0,
827
827
  resourceServers: e.resourceServers ?? !0,
@@ -831,28 +831,28 @@ function q(e = {}) {
831
831
  promptSettings: e.promptSettings ?? !0
832
832
  };
833
833
  }
834
- function J() {
834
+ function Y() {
835
835
  return {
836
836
  upserted: 0,
837
837
  errors: []
838
838
  };
839
839
  }
840
- function he(e) {
840
+ function me(e) {
841
841
  return {
842
842
  tenantId: e,
843
- connections: J(),
844
- resourceServers: J(),
845
- hooks: J(),
846
- emailProvider: J(),
847
- branding: J(),
848
- promptSettings: J()
843
+ connections: Y(),
844
+ resourceServers: Y(),
845
+ hooks: Y(),
846
+ emailProvider: Y(),
847
+ branding: Y(),
848
+ promptSettings: Y()
849
849
  };
850
850
  }
851
- function ge(e) {
851
+ function he(e) {
852
852
  let t = e.metadata;
853
853
  return !!(t && t.inheritable === !0);
854
854
  }
855
- async function Y(e, t, n, r) {
855
+ async function X(e, t, n, r) {
856
856
  try {
857
857
  await r();
858
858
  } catch (r) {
@@ -861,7 +861,7 @@ async function Y(e, t, n, r) {
861
861
  e.errors.push(i);
862
862
  }
863
863
  }
864
- async function _e(e, t, n) {
864
+ async function ge(e, t, n) {
865
865
  return {
866
866
  connections: n.connections ? await u((n) => e.connections.list(t, n), "connections", {
867
867
  cursorField: "id",
@@ -880,102 +880,125 @@ async function _e(e, t, n) {
880
880
  promptSettings: n.promptSettings ? await e.promptSettings.get(t) ?? null : null
881
881
  };
882
882
  }
883
- async function ve(e, t, n, r, i, o) {
883
+ async function _e(e, t, n, r, i, o) {
884
884
  if (r.connections) for (let r of e.connections) {
885
885
  let e = r.id;
886
- e && await Y(o.connections, `connection ${e}`, i, async () => {
886
+ e && await X(o.connections, `connection ${e}`, i, async () => {
887
887
  let i = a.parse(r);
888
888
  await t.connections.get(n, e) ? await t.connections.update(n, e, i) : await t.connections.create(n, i), o.connections.upserted += 1;
889
889
  });
890
890
  }
891
- if (r.resourceServers) for (let r of e.resourceServers) !r.is_system || !r.id || await Y(o.resourceServers, `resource_server ${r.id}`, i, async () => {
891
+ if (r.resourceServers) for (let r of e.resourceServers) !r.is_system || !r.id || await X(o.resourceServers, `resource_server ${r.id}`, i, async () => {
892
892
  let e = h.parse(r);
893
893
  await t.resourceServers.get(n, r.id) ? await t.resourceServers.update(n, r.id, e) : await t.resourceServers.create(n, e), o.resourceServers.upserted += 1;
894
894
  });
895
- if (r.hooks) for (let r of e.hooks) !ge(r) || !r.hook_id || await Y(o.hooks, `hook ${r.hook_id}`, i, async () => {
895
+ if (r.hooks) for (let r of e.hooks) !he(r) || !r.hook_id || await X(o.hooks, `hook ${r.hook_id}`, i, async () => {
896
896
  let e = d.parse(r);
897
897
  await t.hooks.get(n, r.hook_id) ? await t.hooks.update(n, r.hook_id, e) : await t.hooks.create(n, e), o.hooks.upserted += 1;
898
898
  });
899
- r.emailProvider && e.emailProvider && await Y(o.emailProvider, "email_provider", i, async () => {
899
+ r.emailProvider && e.emailProvider && await X(o.emailProvider, "email_provider", i, async () => {
900
900
  let r = e.emailProvider;
901
901
  await t.emailProviders.get(n) ? await t.emailProviders.update(n, r) : await t.emailProviders.create(n, r), o.emailProvider.upserted += 1;
902
- }), r.branding && e.branding && await Y(o.branding, "branding", i, async () => {
902
+ }), r.branding && e.branding && await X(o.branding, "branding", i, async () => {
903
903
  await t.branding.set(n, e.branding), o.branding.upserted += 1;
904
- }), r.promptSettings && e.promptSettings && await Y(o.promptSettings, "prompt_settings", i, async () => {
904
+ }), r.promptSettings && e.promptSettings && await X(o.promptSettings, "prompt_settings", i, async () => {
905
905
  await t.promptSettings.set(n, e.promptSettings), o.promptSettings.upserted += 1;
906
906
  });
907
907
  }
908
- async function X(e, t) {
909
- let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s = q(a), c = await _e(await r(), n, s), l = await i(t), u = he(t);
910
- return await ve(c, l, n, s, o, u), u;
908
+ async function Z(e, t) {
909
+ let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s = J(a), c = await ge(await r(), n, s), l = await i(t), u = me(t);
910
+ return await _e(c, l, n, s, o, u), u;
911
911
  }
912
912
  //#endregion
913
913
  //#region src/rollout/payload.ts
914
- function Z(e) {
914
+ function ve(e) {
915
915
  let { pkcs7: t, tenant_id: n, ...r } = e;
916
916
  return r;
917
917
  }
918
- async function ye(e, t, n = {}) {
919
- let r = q(n), i = n.signingKeys ?? !0, a = await _e(e, t, r), o = i ? (await p(e.keys)).map(Z) : [];
918
+ async function ye(e, t, n = {}, r) {
919
+ let i = J(n), a = n.signingKeys ?? !0, o = n.tenants ?? !0, s = await ge(e, t, i), c = a ? (await p(e.keys)).map(ve) : [], l = o ? await be(e, t, r) : [];
920
920
  return {
921
- connections: a.connections,
922
- resourceServers: a.resourceServers.filter((e) => e.is_system),
923
- hooks: a.hooks.filter(ge),
924
- emailProvider: a.emailProvider,
925
- branding: a.branding,
926
- promptSettings: a.promptSettings,
927
- signingKeys: o
921
+ connections: s.connections,
922
+ resourceServers: s.resourceServers.filter((e) => e.is_system),
923
+ hooks: s.hooks.filter(he),
924
+ emailProvider: s.emailProvider,
925
+ branding: s.branding,
926
+ promptSettings: s.promptSettings,
927
+ signingKeys: c,
928
+ tenants: l
928
929
  };
929
930
  }
930
931
  async function be(e, t, n) {
931
- let r = J();
932
+ let r = n && n !== t ? [t, n] : [t], i = [];
933
+ for (let t of r) {
934
+ let n = await e.tenants.get(t);
935
+ i.push({
936
+ id: t,
937
+ friendly_name: n?.friendly_name || t
938
+ });
939
+ }
940
+ return i;
941
+ }
942
+ async function xe(e, t, n) {
943
+ let r = Y();
932
944
  if (e.length === 0) return r;
933
945
  let i = await p(t.keys), a = new Set(i.map((e) => e.kid));
934
- for (let i of e) await Y(r, `signing_key ${i.kid}`, n, async () => {
935
- let e = Z(i);
946
+ for (let i of e) await X(r, `signing_key ${i.kid}`, n, async () => {
947
+ let e = ve(i);
936
948
  a.has(e.kid) || (await t.keys.create(e), a.add(e.kid), r.upserted += 1);
937
949
  });
938
950
  return r;
939
951
  }
940
- async function xe(e, t, n, r = {}) {
941
- let a = r.continueOnError ?? !1, o = q(r.entities), s = r.entities?.signingKeys ?? !0, c = {
952
+ async function Se(e, t, n) {
953
+ let r = Y();
954
+ for (let i of e) await X(r, `tenant ${i.id}`, n, async () => {
955
+ await t.tenants.get(i.id) || (await t.tenants.create({
956
+ id: i.id,
957
+ friendly_name: i.friendly_name
958
+ }), r.upserted += 1);
959
+ });
960
+ return r;
961
+ }
962
+ async function Ce(e, t, n, r = {}) {
963
+ let a = r.continueOnError ?? !1, o = J(r.entities), s = r.entities?.signingKeys ?? !0, c = r.entities?.tenants ?? !0, u = {
942
964
  connections: e.connections,
943
965
  resourceServers: e.resourceServers,
944
966
  hooks: e.hooks,
945
967
  emailProvider: e.emailProvider ? l.parse(e.emailProvider) : null,
946
968
  branding: e.branding ? i.parse(e.branding) : null,
947
969
  promptSettings: e.promptSettings ? m.parse(e.promptSettings) : null
948
- }, u = he(n);
949
- await ve(c, t, n, o, a, u);
950
- let d = s ? await be(e.signingKeys, t, a) : J();
970
+ }, d = c ? await Se(e.tenants ?? [], t, a) : Y(), f = me(n);
971
+ await _e(u, t, n, o, a, f);
972
+ let p = s ? await xe(e.signingKeys, t, a) : Y();
951
973
  return {
952
- ...u,
953
- signingKeys: d
974
+ ...f,
975
+ signingKeys: p,
976
+ tenants: d
954
977
  };
955
978
  }
956
979
  //#endregion
957
980
  //#region src/rollout/index.ts
958
- function Se(e) {
981
+ function we(e) {
959
982
  return {
960
- syncDefaults: (t) => X(e, t),
983
+ syncDefaults: (t) => Z(e, t),
961
984
  syncDefaultsToTenants: async (t) => {
962
985
  let n = [];
963
- for (let r of t) n.push(await X(e, r));
986
+ for (let r of t) n.push(await Z(e, r));
964
987
  return n;
965
988
  }
966
989
  };
967
990
  }
968
991
  //#endregion
969
992
  //#region src/plugin.ts
970
- function Ce(e) {
993
+ function Te(e) {
971
994
  let t = Q(e);
972
995
  return {
973
996
  name: "multi-tenancy",
974
- middleware: K(e),
997
+ middleware: q(e),
975
998
  hooks: t,
976
999
  routes: [{
977
1000
  path: "/management",
978
- handler: j(e, t)
1001
+ handler: M(e, t)
979
1002
  }],
980
1003
  onRegister: async () => {
981
1004
  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");
@@ -994,19 +1017,19 @@ function Q(e) {
994
1017
  }
995
1018
  function $(t) {
996
1019
  let n = new e(), r = Q(t);
997
- return n.route("/tenants", j(t, r)), n;
1020
+ return n.route("/tenants", M(t, r)), n;
998
1021
  }
999
- function we(e) {
1022
+ function Ee(e) {
1000
1023
  return {
1001
1024
  hooks: Q(e),
1002
- middleware: K(e),
1025
+ middleware: q(e),
1003
1026
  app: $(e),
1004
1027
  config: e,
1005
- wrapAdapters: (t, n) => V(t, {
1028
+ wrapAdapters: (t, n) => H(t, {
1006
1029
  controlPlaneTenantId: e.accessControl?.controlPlaneTenantId,
1007
1030
  controlPlaneClientId: n?.controlPlaneClientId
1008
1031
  })
1009
1032
  };
1010
1033
  }
1011
1034
  //#endregion
1012
- export { xe as applyControlPlaneDefaultsPayload, ye as buildControlPlaneDefaultsPayload, S as createAccessControlHooks, U as createAccessControlMiddleware, H as createControlPlaneTenantMiddleware, w as createDatabaseHooks, G as createDatabaseMiddleware, Se as createDirectRolloutAdapter, $ as createMultiTenancy, Q as createMultiTenancyHooks, K as createMultiTenancyMiddleware, Ce as createMultiTenancyPlugin, M as createProtectSyncedMiddleware, E as createProvisioningHooks, z as createRuntimeFallbackAdapter, W as createSubdomainMiddleware, ie as createSyncHooks, j as createTenantsOpenAPIRouter, me as initMultiTenant, fe as mergeClientWithFallback, X as projectControlPlaneDefaults, we as setupMultiTenancy, C as validateTenantAccess, V as withRuntimeFallback, R as withSystemResourceServerInheritance };
1035
+ export { Ce as applyControlPlaneDefaultsPayload, ye as buildControlPlaneDefaultsPayload, S as createAccessControlHooks, W as createAccessControlMiddleware, U as createControlPlaneTenantMiddleware, w as createDatabaseHooks, K as createDatabaseMiddleware, we as createDirectRolloutAdapter, $ as createMultiTenancy, Q as createMultiTenancyHooks, q as createMultiTenancyMiddleware, Te as createMultiTenancyPlugin, N as createProtectSyncedMiddleware, E as createProvisioningHooks, B as createRuntimeFallbackAdapter, G as createSubdomainMiddleware, re as createSyncHooks, M as createTenantsOpenAPIRouter, pe as initMultiTenant, de as mergeClientWithFallback, Z as projectControlPlaneDefaults, Ee as setupMultiTenancy, C as validateTenantAccess, H as withRuntimeFallback, z as withSystemResourceServerInheritance };
@@ -4,7 +4,7 @@ export * from "./types";
4
4
  export { initMultiTenant } from "./init";
5
5
  export type { MultiTenantConfig, MultiTenantResult, ControlPlaneConfig, } from "./init";
6
6
  export { createDirectRolloutAdapter, projectControlPlaneDefaults, buildControlPlaneDefaultsPayload, applyControlPlaneDefaultsPayload, } from "./rollout";
7
- export type { ControlPlaneRolloutAdapter, DefaultsProjectionConfig, DefaultsProjectionEntities, DefaultsProjectionResult, EntityProjectionOutcome, ProjectableDefaults, ControlPlaneDefaultsPayload, ControlPlaneDefaultsApplyResult, DefaultsPayloadEntities, } from "./rollout";
7
+ export type { ControlPlaneRolloutAdapter, DefaultsProjectionConfig, DefaultsProjectionEntities, DefaultsProjectionResult, EntityProjectionOutcome, ProjectableDefaults, ControlPlaneDefaultsPayload, ControlPlaneDefaultsApplyResult, ControlPlaneTenantSeed, DefaultsPayloadEntities, } from "./rollout";
8
8
  export { createSyncHooks } from "./hooks/sync";
9
9
  export type { EntitySyncConfig, SyncHooksResult } from "./hooks/sync";
10
10
  export { createTenantsOpenAPIRouter } from "./routes";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAajB,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACzC,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAKhB,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,0BAA0B,EAC1B,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,EAC3B,+BAA+B,EAC/B,uBAAuB,GACxB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAEtD,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,kCAAkC,EAClC,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,4BAA4B,EAC5B,mBAAmB,EACnB,mCAAmC,EACnC,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,kBAAkB,GACzB,iBAAiB,CAgBnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB;cAE/C,oBAAoB;eACnB,qBAAqB;0CASnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB;;;;;;;kBAnD9C,oBAAoB;mBACnB,qBAAqB;;;IAwDhC;;;;;;;OAOG;6BAES,OAAO,UAAU,EAAE,YAAY,qBACtB;QAAE,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE;EAOzD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAajB,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACzC,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAKhB,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,0BAA0B,EAC1B,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAEtD,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,kCAAkC,EAClC,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,4BAA4B,EAC5B,mBAAmB,EACnB,mCAAmC,EACnC,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,kBAAkB,GACzB,iBAAiB,CAgBnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB;cAE/C,oBAAoB;eACnB,qBAAqB;0CASnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB;;;;;;;kBAnD9C,oBAAoB;mBACnB,qBAAqB;;;IAwDhC;;;;;;;OAOG;6BAES,OAAO,UAAU,EAAE,YAAY,qBACtB;QAAE,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE;EAOzD"}
@@ -1,7 +1,7 @@
1
1
  import { DefaultsProjectionConfig, DefaultsProjectionResult } from "./defaults-projection";
2
2
  export type { DefaultsProjectionConfig, DefaultsProjectionEntities, DefaultsProjectionResult, EntityProjectionOutcome, ProjectableDefaults, } from "./defaults-projection";
3
3
  export { projectControlPlaneDefaults } from "./defaults-projection";
4
- export type { ControlPlaneDefaultsPayload, ControlPlaneDefaultsApplyResult, DefaultsPayloadEntities, } from "./payload";
4
+ export type { ControlPlaneDefaultsPayload, ControlPlaneDefaultsApplyResult, ControlPlaneTenantSeed, DefaultsPayloadEntities, } from "./payload";
5
5
  export { buildControlPlaneDefaultsPayload, applyControlPlaneDefaultsPayload, } from "./payload";
6
6
  /**
7
7
  * A control plane rollout applies the control plane's state to one or more
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rollout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EAEzB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAEpE,YAAY,EACV,2BAA2B,EAC3B,+BAA+B,EAC/B,uBAAuB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,0BAA0B;IACzC,0EAA0E;IAC1E,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAExE;;;OAGG;IACH,qBAAqB,CACnB,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,wBAAwB,GAC/B,0BAA0B,CAa5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rollout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EAEzB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAEpE,YAAY,EACV,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,0BAA0B;IACzC,0EAA0E;IAC1E,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAExE;;;OAGG;IACH,qBAAqB,CACnB,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,wBAAwB,GAC/B,0BAA0B,CAa5B"}
@@ -2,12 +2,39 @@ import { DataAdapters, SigningKey } from "authhero";
2
2
  import { DefaultsProjectionEntities, DefaultsProjectionResult, EntityProjectionOutcome, ProjectableDefaults } from "./defaults-projection";
3
3
  /**
4
4
  * Entity flags for the wire payload — the six default entities plus signing
5
- * keys, which only flow through the payload (build + apply), never through the
6
- * in-process `projectControlPlaneDefaults`.
5
+ * keys and tenant rows, which only flow through the payload (build + apply),
6
+ * never through the in-process `projectControlPlaneDefaults`.
7
7
  */
8
8
  export type DefaultsPayloadEntities = DefaultsProjectionEntities & {
9
9
  signingKeys?: boolean;
10
+ /**
11
+ * Seed the FK-target `tenants` rows into the tenant DB before writing the
12
+ * keyed defaults. Defaults to `true`. See {@link ControlPlaneTenantSeed}.
13
+ */
14
+ tenants?: boolean;
10
15
  };
16
+ /**
17
+ * A minimal `tenants` row the payload carries so the tenant DB has the foreign
18
+ * key targets every other write depends on. D1 enforces the
19
+ * `tenant_id -> tenants(id)` FK, so a freshly provisioned tenant DB (which only
20
+ * has the empty `tenants` table the migrations create) rejects every
21
+ * tenant-scoped insert until these rows exist:
22
+ *
23
+ * 1. the **control-plane tenant id** — the projected defaults
24
+ * (connections / resource servers / hooks / …) are keyed under it; and
25
+ * 2. the **target tenant's own id** — the tenant's own users / connections /
26
+ * sessions reference it.
27
+ *
28
+ * Deliberately minimal (`id` + `friendly_name`): the FK only needs the row to
29
+ * exist, `friendly_name` is the only required create field, and keeping it
30
+ * minimal avoids shipping control-plane tenant settings/secrets into a tenant
31
+ * DB. Rows are create-if-missing on apply, so a re-sync never clobbers a row a
32
+ * tenant has since edited.
33
+ */
34
+ export interface ControlPlaneTenantSeed {
35
+ id: string;
36
+ friendly_name: string;
37
+ }
11
38
  /**
12
39
  * Wire shape pushed from a control plane to a tenant database. Transport-
13
40
  * agnostic: a Cloudflare dispatch push, an HTTP POST, or an in-process call all
@@ -23,10 +50,17 @@ export interface ControlPlaneDefaultsPayload extends ProjectableDefaults {
23
50
  * verify tokens the control plane signed (e.g. forwarded admin tokens).
24
51
  */
25
52
  signingKeys: SigningKey[];
53
+ /**
54
+ * FK-target `tenants` rows upserted into the tenant DB *before* any keyed
55
+ * default, so the `tenant_id -> tenants(id)` FK resolves. See
56
+ * {@link ControlPlaneTenantSeed}.
57
+ */
58
+ tenants: ControlPlaneTenantSeed[];
26
59
  }
27
- /** Result of applying a payload — the projection result plus the key outcome. */
60
+ /** Result of applying a payload — the projection result plus the key/tenant outcomes. */
28
61
  export interface ControlPlaneDefaultsApplyResult extends DefaultsProjectionResult {
29
62
  signingKeys: EntityProjectionOutcome;
63
+ tenants: EntityProjectionOutcome;
30
64
  }
31
65
  /**
32
66
  * Reads the control plane's defaults + public signing keys off a control-plane
@@ -37,7 +71,7 @@ export interface ControlPlaneDefaultsApplyResult extends DefaultsProjectionResul
37
71
  * (`-_exists_:tenant_id`) so the public-key query has a single source of truth;
38
72
  * this layer only strips `pkcs7`.
39
73
  */
40
- export declare function buildControlPlaneDefaultsPayload(controlPlaneAdapters: DataAdapters, controlPlaneTenantId: string, entities?: DefaultsPayloadEntities): Promise<ControlPlaneDefaultsPayload>;
74
+ export declare function buildControlPlaneDefaultsPayload(controlPlaneAdapters: DataAdapters, controlPlaneTenantId: string, entities?: DefaultsPayloadEntities, targetTenantId?: string): Promise<ControlPlaneDefaultsPayload>;
41
75
  /**
42
76
  * Applies a control-plane defaults payload to a tenant's own adapter, writing
43
77
  * the rows under `controlPlaneTenantId` so the runtime fallback resolves them
@@ -1 +1 @@
1
- {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/rollout/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,UAAU,EAKX,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EAQpB,MAAM,uBAAuB,CAAC;AAE/B;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,GAAG;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,2BAA4B,SAAQ,mBAAmB;IACtE;;;;;OAKG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,iFAAiF;AACjF,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAC/E,WAAW,EAAE,uBAAuB,CAAC;CACtC;AAkBD;;;;;;;;GAQG;AACH,wBAAsB,gCAAgC,CACpD,oBAAoB,EAAE,YAAY,EAClC,oBAAoB,EAAE,MAAM,EAC5B,QAAQ,GAAE,uBAA4B,GACrC,OAAO,CAAC,2BAA2B,CAAC,CA2BtC;AAuCD;;;;;;;;;;;GAWG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,2BAA2B,EACpC,cAAc,EAAE,YAAY,EAC5B,oBAAoB,EAAE,MAAM,EAC5B,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CAC/B,GACL,OAAO,CAAC,+BAA+B,CAAC,CAwC1C"}
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/rollout/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,UAAU,EAKX,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EAQpB,MAAM,uBAAuB,CAAC;AAE/B;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,GAAG;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,2BAA4B,SAAQ,mBAAmB;IACtE;;;;;OAKG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B;;;;OAIG;IACH,OAAO,EAAE,sBAAsB,EAAE,CAAC;CACnC;AAED,yFAAyF;AACzF,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAC/E,WAAW,EAAE,uBAAuB,CAAC;IACrC,OAAO,EAAE,uBAAuB,CAAC;CAClC;AAkBD;;;;;;;;GAQG;AACH,wBAAsB,gCAAgC,CACpD,oBAAoB,EAAE,YAAY,EAClC,oBAAoB,EAAE,MAAM,EAC5B,QAAQ,GAAE,uBAA4B,EACtC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,2BAA2B,CAAC,CAqCtC;AA0FD;;;;;;;;;;;GAWG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,2BAA2B,EACpC,cAAc,EAAE,YAAY,EAC5B,oBAAoB,EAAE,MAAM,EAC5B,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CAC/B,GACL,OAAO,CAAC,+BAA+B,CAAC,CAoD1C"}
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.25.0",
14
+ "version": "14.25.1",
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": "^8.0.14",
38
38
  "vitest": "^4.1.7",
39
+ "@authhero/adapter-interfaces": "3.1.1",
39
40
  "@authhero/kysely-adapter": "11.8.9",
40
- "authhero": "8.5.0",
41
- "@authhero/adapter-interfaces": "3.1.1"
41
+ "authhero": "8.7.0"
42
42
  },
43
43
  "dependencies": {
44
44
  "zod": "^4.4.3"