@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.
- package/dist/multi-tenancy.cjs +1 -1
- package/dist/multi-tenancy.mjs +134 -111
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/rollout/index.d.ts +1 -1
- package/dist/types/rollout/index.d.ts.map +1 -1
- package/dist/types/rollout/payload.d.ts +38 -4
- package/dist/types/rollout/payload.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/multi-tenancy.cjs
CHANGED
|
@@ -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;
|
package/dist/multi-tenancy.mjs
CHANGED
|
@@ -214,11 +214,11 @@ var k = (e) => ({
|
|
|
214
214
|
description: e.description
|
|
215
215
|
})
|
|
216
216
|
});
|
|
217
|
-
function
|
|
217
|
+
function j(e) {
|
|
218
218
|
return e.metadata?.sync !== !1;
|
|
219
219
|
}
|
|
220
|
-
function
|
|
221
|
-
let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) =>
|
|
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
|
|
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
|
|
284
|
-
let t =
|
|
283
|
+
function ae(e) {
|
|
284
|
+
let t = ie.safeParse(e);
|
|
285
285
|
return t.success ? t.data : void 0;
|
|
286
286
|
}
|
|
287
|
-
function
|
|
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
|
|
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 =
|
|
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 &&
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
528
|
+
function F(e, t) {
|
|
529
529
|
let n = [...t || [], ...e || []];
|
|
530
530
|
return [...new Set(n)];
|
|
531
531
|
}
|
|
532
|
-
function
|
|
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
|
|
540
|
+
function I(e, t) {
|
|
541
541
|
return t ? {
|
|
542
542
|
...e,
|
|
543
|
-
scopes:
|
|
543
|
+
scopes: ue(e.scopes, t.scopes)
|
|
544
544
|
} : e;
|
|
545
545
|
}
|
|
546
|
-
function
|
|
546
|
+
function de(e, t) {
|
|
547
547
|
return t ? {
|
|
548
548
|
...e,
|
|
549
|
-
callbacks:
|
|
550
|
-
web_origins:
|
|
551
|
-
allowed_logout_urls:
|
|
552
|
-
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
|
|
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
|
|
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 :
|
|
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 ?
|
|
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
|
|
593
|
-
let n =
|
|
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:
|
|
599
|
+
resourceServers: R(e, n)
|
|
600
600
|
};
|
|
601
601
|
}
|
|
602
|
-
function
|
|
603
|
-
let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i } = t, a =
|
|
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 :
|
|
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) =>
|
|
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) =>
|
|
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:
|
|
654
|
-
hooks:
|
|
653
|
+
resourceServers: R(e, a),
|
|
654
|
+
hooks: fe(e, a)
|
|
655
655
|
};
|
|
656
656
|
}
|
|
657
|
-
function
|
|
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
|
|
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(
|
|
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 &&
|
|
683
|
+
return o && V(o) ? o : null;
|
|
684
684
|
}
|
|
685
685
|
};
|
|
686
686
|
}
|
|
687
|
-
function
|
|
688
|
-
return
|
|
687
|
+
function H(e, t) {
|
|
688
|
+
return B(e, t);
|
|
689
689
|
}
|
|
690
690
|
//#endregion
|
|
691
691
|
//#region src/middleware/index.ts
|
|
692
|
-
function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
741
|
-
let t =
|
|
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
|
|
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 =
|
|
753
|
+
n && (g = H(t, {
|
|
754
754
|
controlPlaneTenantId: r,
|
|
755
755
|
controlPlaneClientId: i,
|
|
756
756
|
resolveControlPlane: a
|
|
757
757
|
}), _ = {
|
|
758
|
-
...
|
|
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 } =
|
|
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 =
|
|
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/*",
|
|
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
|
|
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
|
|
834
|
+
function Y() {
|
|
835
835
|
return {
|
|
836
836
|
upserted: 0,
|
|
837
837
|
errors: []
|
|
838
838
|
};
|
|
839
839
|
}
|
|
840
|
-
function
|
|
840
|
+
function me(e) {
|
|
841
841
|
return {
|
|
842
842
|
tenantId: e,
|
|
843
|
-
connections:
|
|
844
|
-
resourceServers:
|
|
845
|
-
hooks:
|
|
846
|
-
emailProvider:
|
|
847
|
-
branding:
|
|
848
|
-
promptSettings:
|
|
843
|
+
connections: Y(),
|
|
844
|
+
resourceServers: Y(),
|
|
845
|
+
hooks: Y(),
|
|
846
|
+
emailProvider: Y(),
|
|
847
|
+
branding: Y(),
|
|
848
|
+
promptSettings: Y()
|
|
849
849
|
};
|
|
850
850
|
}
|
|
851
|
-
function
|
|
851
|
+
function he(e) {
|
|
852
852
|
let t = e.metadata;
|
|
853
853
|
return !!(t && t.inheritable === !0);
|
|
854
854
|
}
|
|
855
|
-
async function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) !
|
|
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
|
|
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
|
|
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
|
|
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
|
|
909
|
-
let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s =
|
|
910
|
-
return await
|
|
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
|
|
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
|
|
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:
|
|
922
|
-
resourceServers:
|
|
923
|
-
hooks:
|
|
924
|
-
emailProvider:
|
|
925
|
-
branding:
|
|
926
|
-
promptSettings:
|
|
927
|
-
signingKeys:
|
|
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 =
|
|
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
|
|
935
|
-
let e =
|
|
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
|
|
941
|
-
let
|
|
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
|
-
},
|
|
949
|
-
await
|
|
950
|
-
let
|
|
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
|
-
...
|
|
953
|
-
signingKeys:
|
|
974
|
+
...f,
|
|
975
|
+
signingKeys: p,
|
|
976
|
+
tenants: d
|
|
954
977
|
};
|
|
955
978
|
}
|
|
956
979
|
//#endregion
|
|
957
980
|
//#region src/rollout/index.ts
|
|
958
|
-
function
|
|
981
|
+
function we(e) {
|
|
959
982
|
return {
|
|
960
|
-
syncDefaults: (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
|
|
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
|
|
993
|
+
function Te(e) {
|
|
971
994
|
let t = Q(e);
|
|
972
995
|
return {
|
|
973
996
|
name: "multi-tenancy",
|
|
974
|
-
middleware:
|
|
997
|
+
middleware: q(e),
|
|
975
998
|
hooks: t,
|
|
976
999
|
routes: [{
|
|
977
1000
|
path: "/management",
|
|
978
|
-
handler:
|
|
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",
|
|
1020
|
+
return n.route("/tenants", M(t, r)), n;
|
|
998
1021
|
}
|
|
999
|
-
function
|
|
1022
|
+
function Ee(e) {
|
|
1000
1023
|
return {
|
|
1001
1024
|
hooks: Q(e),
|
|
1002
|
-
middleware:
|
|
1025
|
+
middleware: q(e),
|
|
1003
1026
|
app: $(e),
|
|
1004
1027
|
config: e,
|
|
1005
|
-
wrapAdapters: (t, n) =>
|
|
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 {
|
|
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 };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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),
|
|
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
|
|
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;
|
|
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.
|
|
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.
|
|
41
|
-
"@authhero/adapter-interfaces": "3.1.1"
|
|
41
|
+
"authhero": "8.7.0"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"zod": "^4.4.3"
|