@authhero/multi-tenancy 14.26.0 → 14.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/multi-tenancy.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
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}}}}var s=64;function c(e){return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}function l(e){let t=c(e.id),n=Math.max(0,s-(5+t.length)),r=c(e.kind).slice(0,n),i=3+r.length+2+t.length,a=Math.max(0,s-i);return`op-${r}-${c(e.tenant_id??`fleet`).slice(0,a)}-${t}`.slice(0,s)}var u=2048;function d(e){let t;if(e instanceof Error)t=e.message;else try{t=String(e??`unknown error`)}catch{t=Object.prototype.toString.call(e)}return t.slice(0,u)}function f(e){let{tenantOperations:t,tenantOperationEvents:n}=e;return{async markRunning(e,n){await t.update(e,{status:`running`,...n===void 0?{}:{current_step:n}})},async setCurrentStep(e,n){await t.update(e,{current_step:n})},async appendEvent(e,t){await n.create({operation_id:e,step:t.step,outcome:t.outcome,detail:t.detail,attempt:t.attempt??1})},async markSucceeded(e){await t.update(e,{status:`succeeded`,error:null,finished_at:new Date().toISOString()})},async markFailed(e,n){await t.update(e,{status:`failed`,error:d(n),finished_at:new Date().toISOString()})}}}function p(e){return e===`succeeded`||e===`failed`||e===`cancelled`}var m={async do(e,t,n){let r=typeof t==`function`?t:n;if(!r)throw Error(`StepRunner.do called without a function`);return r()}};function h(e){let t=f(e.stores);return{engine:`inline`,async start(n){let r=e.definitions[n.kind];if(!r){let e=Error(`No inline operation definition for kind "${n.kind}"`);throw await t.markFailed(n.id,e),e}let i=r(n);await t.markRunning(n.id,i[0]?.name);for(let e of i){await t.setCurrentStep(n.id,e.name),await t.appendEvent(n.id,{step:e.name,outcome:`started`});try{let r=await e.run({operation:n,step:m});await t.appendEvent(n.id,{step:e.name,outcome:`succeeded`,detail:r??void 0})}catch(r){throw await t.appendEvent(n.id,{step:e.name,outcome:`failed`,detail:{message:d(r)}}),await t.markFailed(n.id,r),r}}await t.markSucceeded(n.id)}}}async function g(e,t,n){let r=await e.tenantOperations.create({tenant_id:t.tenant_id,rollout_id:t.rollout_id,kind:t.kind,engine:n,initiated_by:t.initiated_by,target_worker_version:t.target_worker_version,target_database_version:t.target_database_version}),i=l(r);try{await e.tenantOperations.update(r.id,{engine_instance_id:i})}catch(t){try{await f(e).markFailed(r.id,t)}catch{}throw t}return{...r,engine_instance_id:i}}async function _(e,t,n){let r=f(e),i=await g(e,n,t.engine);try{await t.start(i)}catch(t){try{let n=await e.tenantOperations.get(i.id);n&&!p(n.status)&&await r.markFailed(i.id,t)}catch(e){console.warn(`Failed to record tenant operation failure:`,e)}throw t}try{return await e.tenantOperations.get(i.id)??i}catch(e){return console.warn(`Failed to re-fetch tenant operation after start:`,e),i}}function v(e){if(e.tenantOperations&&e.tenantOperationEvents)return{tenantOperations:e.tenantOperations,tenantOperationEvents:e.tenantOperationEvents}}async function y(e,t,n){let r=v(e);if(!r){await n(void 0);return}let i=f(r),a=async e=>{try{await e()}catch(e){console.warn(`Failed to record tenant operation progress:`,e)}},o;if(await a(async()=>{let e=await g(r,t,`inline`);o=e.id,await i.markRunning(e.id)}),!o){await n(void 0);return}let s=o,c=!1,l=async(e,t,n)=>{c=!0,await a(async()=>{t===`started`&&await i.setCurrentStep(s,e),await i.appendEvent(s,{step:e,outcome:t,detail:n})})};try{await n(l)}catch(e){throw await a(async()=>{c||await i.appendEvent(s,{step:t.kind,outcome:`failed`,detail:{message:d(e)}}),await i.markFailed(s,e)}),e}await a(async()=>{c||await i.appendEvent(s,{step:t.kind,outcome:`succeeded`}),await i.markSucceeded(s)})}function b(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function x(e){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:b(t.id)}:t},async afterCreate(t,n){let{accessControl:r,databaseIsolation:i}=e;if(r&&t.ctx&&await S(t,n,r),i?.onProvision){let e=i.onProvision;i.recordProvisionOperations===!1?await e(n.id):await y(t.adapters,{kind:`provision`,tenant_id:n.id,initiated_by:t.ctx?.var.user?.sub},t=>e(n.id,t))}},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 S(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,u=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id}),d;if(o&&(d=await w(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await C(e,r,t.sub))try{await e.adapters.userOrganizations.create(r,{user_id:t.sub,organization_id:u.id}),d&&await e.adapters.userRoles.create(r,t.sub,d,u.id)}catch(e){console.warn(`Failed to add creator ${t.sub} to organization ${u.id}:`,e)}}a&&a.length>0&&console.log(`Would assign roles ${a.join(`, `)} to organization ${u.id}`),i&&i.length>0&&console.log(`Would grant permissions ${i.join(`, `)} to organization ${u.id}`)}async function C(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 w(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 T(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 E(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 D=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})}),O=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 k(e){return e.metadata?.sync!==!1}function A(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>k(e)?r.resourceServers?r.resourceServers(e):!0:!1,s=e=>k(e)?r.roles?r.roles(e):!0:!1,c=i?T(e,D,o):void 0,l=a?T(e,O,s):void 0,u=i?E(e,D,o):void 0,d=a?E(e,O,s):void 0,f=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 p(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 p(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,f?.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 ee=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 te(e){let t=ee.safeParse(e);return t.success?t.data:void 0}function ne(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 j(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=te(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&&ne(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 re(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 ie(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 ae(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function M(){return async(e,t)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return t();let n=re(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 ie(e.env.data,i,n))throw new r.HTTPException(403,{message:`This ${ae(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function N(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 P(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function oe(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 F(e,t){return t?{...e,scopes:oe(e.scopes,t.scopes)}:e}function se(e,t){return t?{...e,callbacks:P(e.callbacks,t.callbacks),web_origins:P(e.web_origins,t.web_origins),allowed_logout_urls:P(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:P(e.allowed_origins,t.allowed_origins)}:e}function I(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 ce(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:F(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?F(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function le(e,t){let n=I({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:ce(e,n)}}function L(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i}=t,a=I({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:N(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=>N(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=>N(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:ce(e,a),hooks:ue(e,a)}}function R(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function ue(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(R);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&&R(o)?o:null}}}function z(e,t){return L(e,t)}function B(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 V(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 H(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 U(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 W(e){let t=H(e),n=V(e),r=U(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}function de(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,sync:s={resourceServers:!0,roles:!0},defaultPermissions:c=[`tenant:admin`],requireOrganizationMatch:l=!1,managementApiExtensions:u=[],entityHooks:d,getChildTenantIds:f,getAdapters:p,...m}=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=z(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),v={...le(n,{controlPlaneTenantId:i,resolveControlPlane:o}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}});let y=m.tenantOperationExecutor;if(!y&&n.tenantOperations&&n.tenantOperationEvents&&m.tenantUpgrade){let e={tenantOperations:n.tenantOperations,tenantOperationEvents:n.tenantOperationEvents},t=m.tenantUpgrade,r=h({stores:e,definitions:{upgrade:e=>[{name:`upgrade`,async run(){if(!e.tenant_id)throw Error(`upgrade operations require a tenant_id`);await t(e.tenant_id)}}]}});y={engine:r.engine,enqueue:t=>_(e,r,{...t,tenant_id:t.tenant_id})}}let b=s!==!1,S=b?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:C,tenantHooks:w}=A({controlPlaneTenantId:i,getChildTenantIds:f??(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:p??(async()=>g),getControlPlaneAdapters:async()=>g,sync:S}),T={resourceServers:[C.resourceServers,...d?.resourceServers??[]],roles:[C.roles,...d?.roles??[]],connections:d?.connections??[],tenants:d?.tenants??[],rolePermissions:d?.rolePermissions??[]},E=x({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:l,defaultPermissions:c}}),D=j({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:l,defaultPermissions:c}},{tenants:{async beforeCreate(e,t){return E.beforeCreate&&(t=await E.beforeCreate(e,t)),w.beforeCreate&&(t=await w.beforeCreate(e,t)),t},async afterCreate(e,t){await E.afterCreate?.(e,t),await w.afterCreate?.(e,t)},async beforeDelete(e,t){await E.beforeDelete?.(e,t),await w.beforeDelete?.(e,t)}}}),{app:O}=(0,t.init)({dataAdapter:g,managementDataAdapter:v,...m,tenantOperationExecutor:y,entityHooks:T,managementApiExtensions:[...u,{path:`/tenants`,router:D}]});return O.use(`/api/v2/*`,B(i)),b&&O.use(`/api/v2/*`,M()),{app:O,controlPlaneTenantId:i}}function G(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 K(){return{upserted:0,errors:[]}}function q(e){return{tenantId:e,connections:K(),resourceServers:K(),hooks:K(),emailProvider:K(),branding:K(),promptSettings:K()}}function J(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function Y(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 X(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 Z(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await Y(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 Y(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)!J(i)||!i.hook_id||await Y(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 Y(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 Y(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await Y(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function Q(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=G(a),c=await X(await r(),n,s),l=await i(t),u=q(t);return await Z(c,l,n,s,o,u),u}function fe(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function pe(e,n,r={},i){let a=G(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await X(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(fe):[],u=s?await me(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(J),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function me(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 he(e,n,r){let i=K();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 Y(i,`signing_key ${t.kid}`,r,async()=>{let e=fe(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function ge(e,t,n){let r=K();for(let i of e)await Y(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 _e(e,n,r,i={}){let a=i.continueOnError??!1,o=G(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 ge(e.tenants??[],n,a):K(),d=q(r);await Z(l,n,r,o,a,d);let f=s?await he(e.signingKeys,n,a):K();return{...d,signingKeys:f,tenants:u}}function ve(e){return{syncDefaults:t=>Q(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await Q(e,r));return n}}}function ye(e){let t=$(e);return{name:`multi-tenancy`,middleware:W(e),hooks:t,routes:[{path:`/management`,handler:j(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 $(e){let t=e.accessControl?i(e.accessControl):{},n=e.databaseIsolation?o(e.databaseIsolation):{},r=x(e);return{...t,...n,tenants:r}}function be(t){let n=new e.Hono,r=$(t);return n.route(`/tenants`,j(t,r)),n}function xe(e){return{hooks:$(e),middleware:W(e),app:be(e),config:e,wrapAdapters:(t,n)=>z(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.applyControlPlaneDefaultsPayload=_e,exports.buildControlPlaneDefaultsPayload=pe,exports.buildEngineInstanceId=l,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=V,exports.createControlPlaneTenantMiddleware=B,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=U,exports.createDirectRolloutAdapter=ve,exports.createInlineExecutor=h,exports.createMultiTenancy=be,exports.createMultiTenancyHooks=$,exports.createMultiTenancyMiddleware=W,exports.createMultiTenancyPlugin=ye,exports.createOperationRecorder=f,exports.createProtectSyncedMiddleware=M,exports.createProvisioningHooks=x,exports.createRuntimeFallbackAdapter=L,exports.createSubdomainMiddleware=H,exports.createSyncHooks=A,exports.createTenantsOpenAPIRouter=j,exports.enqueueTenantOperation=_,exports.errorToMessage=d,exports.initMultiTenant=de,exports.inlineStepRunner=m,exports.isTerminalStatus=p,exports.mergeClientWithFallback=se,exports.projectControlPlaneDefaults=Q,exports.runRecordedTenantOperation=y,exports.setupMultiTenancy=xe,exports.validateTenantAccess=a,exports.withRuntimeFallback=z,exports.withSystemResourceServerInheritance=le;
|
|
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}}}}var s=64;function c(e){return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}function l(e){let t=c(e.id),n=Math.max(0,s-(5+t.length)),r=c(e.kind).slice(0,n),i=3+r.length+2+t.length,a=Math.max(0,s-i);return`op-${r}-${c(e.tenant_id??`fleet`).slice(0,a)}-${t}`.slice(0,s)}var u=2048;function d(e){let t;if(e instanceof Error)t=e.message;else try{t=String(e??`unknown error`)}catch{t=Object.prototype.toString.call(e)}return t.slice(0,u)}function f(e){let{tenantOperations:t,tenantOperationEvents:n}=e;return{async markRunning(e,n){await t.update(e,{status:`running`,...n===void 0?{}:{current_step:n}})},async setCurrentStep(e,n){await t.update(e,{current_step:n})},async appendEvent(e,t){await n.create({operation_id:e,step:t.step,outcome:t.outcome,detail:t.detail,attempt:t.attempt??1})},async markSucceeded(e){await t.update(e,{status:`succeeded`,error:null,finished_at:new Date().toISOString()})},async markFailed(e,n){await t.update(e,{status:`failed`,error:d(n),finished_at:new Date().toISOString()})}}}function p(e){return e===`succeeded`||e===`failed`||e===`cancelled`}var m={async do(e,t,n){let r=typeof t==`function`?t:n;if(!r)throw Error(`StepRunner.do called without a function`);return r()}};function h(e){let t=f(e.stores);return{engine:`inline`,async start(n){let r=e.definitions[n.kind];if(!r){let e=Error(`No inline operation definition for kind "${n.kind}"`);throw await t.markFailed(n.id,e),e}let i=r(n);await t.markRunning(n.id,i[0]?.name);for(let e of i){await t.setCurrentStep(n.id,e.name),await t.appendEvent(n.id,{step:e.name,outcome:`started`});try{let r=await e.run({operation:n,step:m});await t.appendEvent(n.id,{step:e.name,outcome:`succeeded`,detail:r??void 0})}catch(r){throw await t.appendEvent(n.id,{step:e.name,outcome:`failed`,detail:{message:d(r)}}),await t.markFailed(n.id,r),r}}await t.markSucceeded(n.id)}}}async function g(e,t,n){let r=await e.tenantOperations.create({tenant_id:t.tenant_id,rollout_id:t.rollout_id,kind:t.kind,engine:n,initiated_by:t.initiated_by,target_worker_version:t.target_worker_version,target_database_version:t.target_database_version}),i=l(r);try{await e.tenantOperations.update(r.id,{engine_instance_id:i})}catch(t){try{await f(e).markFailed(r.id,t)}catch{}throw t}return{...r,engine_instance_id:i}}async function _(e,t,n){let r=f(e),i=await g(e,n,t.engine);try{await t.start(i)}catch(t){try{let n=await e.tenantOperations.get(i.id);n&&!p(n.status)&&await r.markFailed(i.id,t)}catch(e){console.warn(`Failed to record tenant operation failure:`,e)}throw t}try{return await e.tenantOperations.get(i.id)??i}catch(e){return console.warn(`Failed to re-fetch tenant operation after start:`,e),i}}function v(e){if(e.tenantOperations&&e.tenantOperationEvents)return{tenantOperations:e.tenantOperations,tenantOperationEvents:e.tenantOperationEvents}}async function y(e,t,n){let r=v(e);if(!r){await n(void 0);return}let i=f(r),a=async e=>{try{await e()}catch(e){console.warn(`Failed to record tenant operation progress:`,e)}},o;if(await a(async()=>{let e=await g(r,t,`inline`);o=e.id,await i.markRunning(e.id)}),!o){await n(void 0);return}let s=o,c=!1,l=async(e,t,n)=>{c=!0,await a(async()=>{t===`started`&&await i.setCurrentStep(s,e),await i.appendEvent(s,{step:e,outcome:t,detail:n})})};try{await n(l)}catch(e){throw await a(async()=>{c||await i.appendEvent(s,{step:t.kind,outcome:`failed`,detail:{message:d(e)}}),await i.markFailed(s,e)}),e}await a(async()=>{c||await i.appendEvent(s,{step:t.kind,outcome:`succeeded`}),await i.markSucceeded(s)})}function b(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function x(e){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:b(t.id)}:t},async afterCreate(n,r){let{accessControl:i,databaseIsolation:a}=e;if(i&&n.ctx&&await S(n,r,i),a?.onProvision){let e=a.onProvision;a.recordProvisionOperations===!1?await e(r.id):await y(n.adapters,{kind:`provision`,tenant_id:r.id,initiated_by:n.ctx?.var.user?.sub},t=>e(r.id,t))}else try{await(0,t.provisionDefaultClients)(n.adapters,r.id,{managementApiIdentifier:t.MANAGEMENT_API_AUDIENCE,managementApiScopes:t.MANAGEMENT_API_SCOPES})}catch(e){throw console.warn(`Failed to provision default clients for tenant ${r.id}:`,e),e}},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 S(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,u=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id}),d;if(o&&(d=await w(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await C(e,r,t.sub))try{await e.adapters.userOrganizations.create(r,{user_id:t.sub,organization_id:u.id}),d&&await e.adapters.userRoles.create(r,t.sub,d,u.id)}catch(e){console.warn(`Failed to add creator ${t.sub} to organization ${u.id}:`,e)}}a&&a.length>0&&console.log(`Would assign roles ${a.join(`, `)} to organization ${u.id}`),i&&i.length>0&&console.log(`Would grant permissions ${i.join(`, `)} to organization ${u.id}`)}async function C(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 w(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 T(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 E(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 D=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})}),O=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 k(e){return e.metadata?.sync!==!1}function A(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>k(e)?!r.resourceServers||r.resourceServers(e):!1,s=e=>k(e)?!r.roles||r.roles(e):!1,c=i?T(e,D,o):void 0,l=a?T(e,O,s):void 0,u=i?E(e,D,o):void 0,d=a?E(e,O,s):void 0,f=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 p(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 p(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,f?.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 ee=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 te(e){let t=ee.safeParse(e);return t.success?t.data:void 0}function ne(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 j(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=te(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&&ne(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`});if(`default_client_id`in i){let n=i.default_client_id;if(typeof n==`string`&&n.length>0){let i=await e.env.data.clients.get(e.var.tenant_id,n);if(!i)throw new r.HTTPException(400,{message:`Client with id '${n}' not found`});if(!(0,t.isInteractiveClient)(i))throw new r.HTTPException(400,{message:`Client '${n}' is not an interactive client and cannot be used as the default client`})}}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 re(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 ie(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 ae(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function M(){return async(e,t)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return t();let n=re(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 ie(e.env.data,i,n))throw new r.HTTPException(403,{message:`This ${ae(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function N(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 P(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function oe(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 F(e,t){return t?{...e,scopes:oe(e.scopes,t.scopes)}:e}function se(e,t){return t?{...e,callbacks:P(e.callbacks,t.callbacks),web_origins:P(e.web_origins,t.web_origins),allowed_logout_urls:P(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:P(e.allowed_origins,t.allowed_origins)}:e}function I(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 ce(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:F(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?F(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function le(e,t){let n=I({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:ce(e,n)}}function L(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i}=t,a=I({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:N(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=>N(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=>N(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:ce(e,a),hooks:ue(e,a)}}function R(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function ue(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(R);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&&R(o)?o:null}}}function z(e,t){return L(e,t)}function B(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 V(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 H(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 U(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 W(e){let t=H(e),n=V(e),r=U(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}function de(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,sync:s={resourceServers:!0,roles:!0},defaultPermissions:c=[`tenant:admin`],requireOrganizationMatch:l=!1,managementApiExtensions:u=[],entityHooks:d,getChildTenantIds:f,getAdapters:p,...m}=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=z(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),v={...le(n,{controlPlaneTenantId:i,resolveControlPlane:o}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}});let y=m.tenantOperationExecutor;if(!y&&n.tenantOperations&&n.tenantOperationEvents&&m.tenantUpgrade){let e={tenantOperations:n.tenantOperations,tenantOperationEvents:n.tenantOperationEvents},t=m.tenantUpgrade,r=h({stores:e,definitions:{upgrade:e=>[{name:`upgrade`,async run(){if(!e.tenant_id)throw Error(`upgrade operations require a tenant_id`);await t(e.tenant_id)}}]}});y={engine:r.engine,enqueue:t=>_(e,r,{...t,tenant_id:t.tenant_id})}}let b=s!==!1,S=b?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:C,tenantHooks:w}=A({controlPlaneTenantId:i,getChildTenantIds:f??(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:p??(async()=>g),getControlPlaneAdapters:async()=>g,sync:S}),T={resourceServers:[C.resourceServers,...d?.resourceServers??[]],roles:[C.roles,...d?.roles??[]],connections:d?.connections??[],tenants:d?.tenants??[],rolePermissions:d?.rolePermissions??[]},E=x({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:l,defaultPermissions:c}}),D=j({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:l,defaultPermissions:c}},{tenants:{async beforeCreate(e,t){return E.beforeCreate&&(t=await E.beforeCreate(e,t)),w.beforeCreate&&(t=await w.beforeCreate(e,t)),t},async afterCreate(e,t){await E.afterCreate?.(e,t),await w.afterCreate?.(e,t)},async beforeDelete(e,t){await E.beforeDelete?.(e,t),await w.beforeDelete?.(e,t)}}}),{app:O}=(0,t.init)({dataAdapter:g,managementDataAdapter:v,...m,tenantOperationExecutor:y,entityHooks:T,managementApiExtensions:[...u,{path:`/tenants`,router:D}]});return O.use(`/api/v2/*`,B(i)),b&&O.use(`/api/v2/*`,M()),{app:O,controlPlaneTenantId:i}}function G(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 K(){return{upserted:0,errors:[]}}function q(e){return{tenantId:e,connections:K(),resourceServers:K(),hooks:K(),emailProvider:K(),branding:K(),promptSettings:K()}}function J(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function Y(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 X(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 Z(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await Y(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 Y(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)!J(i)||!i.hook_id||await Y(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 Y(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 Y(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await Y(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function Q(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=G(a),c=await X(await r(),n,s),l=await i(t),u=q(t);return await Z(c,l,n,s,o,u),u}function fe(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function pe(e,n,r={},i){let a=G(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await X(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(fe):[],u=s?await me(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(J),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function me(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 he(e,n,r){let i=K();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 Y(i,`signing_key ${t.kid}`,r,async()=>{let e=fe(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function ge(e,t,n){let r=K();for(let i of e)await Y(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 _e(e,n,r,i={}){let a=i.continueOnError??!1,o=G(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 ge(e.tenants??[],n,a):K(),d=q(r);await Z(l,n,r,o,a,d);let f=s?await he(e.signingKeys,n,a):K();return{...d,signingKeys:f,tenants:u}}function ve(e){return{syncDefaults:t=>Q(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await Q(e,r));return n}}}function ye(e){let t=$(e);return{name:`multi-tenancy`,middleware:W(e),hooks:t,routes:[{path:`/management`,handler:j(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 $(e){let t=e.accessControl?i(e.accessControl):{},n=e.databaseIsolation?o(e.databaseIsolation):{},r=x(e);return{...t,...n,tenants:r}}function be(t){let n=new e.Hono,r=$(t);return n.route(`/tenants`,j(t,r)),n}function xe(e){return{hooks:$(e),middleware:W(e),app:be(e),config:e,wrapAdapters:(t,n)=>z(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.applyControlPlaneDefaultsPayload=_e,exports.buildControlPlaneDefaultsPayload=pe,exports.buildEngineInstanceId=l,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=V,exports.createControlPlaneTenantMiddleware=B,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=U,exports.createDirectRolloutAdapter=ve,exports.createInlineExecutor=h,exports.createMultiTenancy=be,exports.createMultiTenancyHooks=$,exports.createMultiTenancyMiddleware=W,exports.createMultiTenancyPlugin=ye,exports.createOperationRecorder=f,exports.createProtectSyncedMiddleware=M,exports.createProvisioningHooks=x,exports.createRuntimeFallbackAdapter=L,exports.createSubdomainMiddleware=H,exports.createSyncHooks=A,exports.createTenantsOpenAPIRouter=j,exports.enqueueTenantOperation=_,exports.errorToMessage=d,exports.initMultiTenant=de,exports.inlineStepRunner=m,exports.isTerminalStatus=p,exports.mergeClientWithFallback=se,exports.projectControlPlaneDefaults=Q,exports.runRecordedTenantOperation=y,exports.setupMultiTenancy=xe,exports.validateTenantAccess=a,exports.withRuntimeFallback=z,exports.withSystemResourceServerInheritance=le;
|
package/dist/multi-tenancy.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Hono as e } from "hono";
|
|
2
|
-
import { MANAGEMENT_API_AUDIENCE as t, MANAGEMENT_API_SCOPES as n, auth0QuerySchema as r, brandingSchema as i, connectionInsertSchema as a, connectionOptionsSchema as o, connectionSchema as s, deepMergePatch as c, emailProviderSchema as l, fetchAll as u, hookInsertSchema as d, init as f,
|
|
3
|
-
import { OpenAPIHono as
|
|
4
|
-
import { HTTPException as
|
|
2
|
+
import { MANAGEMENT_API_AUDIENCE as t, MANAGEMENT_API_SCOPES as n, auth0QuerySchema as r, brandingSchema as i, connectionInsertSchema as a, connectionOptionsSchema as o, connectionSchema as s, deepMergePatch as c, emailProviderSchema as l, fetchAll as u, hookInsertSchema as d, init as f, isInteractiveClient as p, listControlPlaneKeys as m, promptSettingSchema as h, provisionDefaultClients as g, resourceServerInsertSchema as _, tenantInsertSchema as v, tenantSchema as y } from "authhero";
|
|
3
|
+
import { OpenAPIHono as ee, createRoute as b, z as x } from "@hono/zod-openapi";
|
|
4
|
+
import { HTTPException as S } from "hono/http-exception";
|
|
5
5
|
//#region src/hooks/access-control.ts
|
|
6
|
-
function
|
|
6
|
+
function C(e) {
|
|
7
7
|
let { controlPlaneTenantId: t, requireOrganizationMatch: n = !0 } = e;
|
|
8
8
|
return { async onTenantAccessValidation(e, r) {
|
|
9
9
|
if (r === t) return !0;
|
|
@@ -14,14 +14,14 @@ function S(e) {
|
|
|
14
14
|
return !0;
|
|
15
15
|
} };
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function w(e, t, n, r) {
|
|
18
18
|
if (t === n) return !0;
|
|
19
19
|
let i = r || e;
|
|
20
20
|
return i ? i.toLowerCase() === t.toLowerCase() : !1;
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/hooks/database.ts
|
|
24
|
-
function
|
|
24
|
+
function T(e) {
|
|
25
25
|
return { async resolveDataAdapters(t) {
|
|
26
26
|
try {
|
|
27
27
|
return await e.getAdapters(t);
|
|
@@ -33,18 +33,18 @@ function w(e) {
|
|
|
33
33
|
}
|
|
34
34
|
//#endregion
|
|
35
35
|
//#region src/operations/instance-id.ts
|
|
36
|
-
var
|
|
37
|
-
function
|
|
36
|
+
var E = 64;
|
|
37
|
+
function D(e) {
|
|
38
38
|
return e.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
39
39
|
}
|
|
40
|
-
function
|
|
41
|
-
let t =
|
|
42
|
-
return `op-${r}-${
|
|
40
|
+
function te(e) {
|
|
41
|
+
let t = D(e.id), n = Math.max(0, E - (5 + t.length)), r = D(e.kind).slice(0, n), i = 3 + r.length + 2 + t.length, a = Math.max(0, E - i);
|
|
42
|
+
return `op-${r}-${D(e.tenant_id ?? "fleet").slice(0, a)}-${t}`.slice(0, E);
|
|
43
43
|
}
|
|
44
44
|
//#endregion
|
|
45
45
|
//#region src/operations/recorder.ts
|
|
46
|
-
var
|
|
47
|
-
function
|
|
46
|
+
var ne = 2048;
|
|
47
|
+
function O(e) {
|
|
48
48
|
let t;
|
|
49
49
|
if (e instanceof Error) t = e.message;
|
|
50
50
|
else try {
|
|
@@ -52,9 +52,9 @@ function D(e) {
|
|
|
52
52
|
} catch {
|
|
53
53
|
t = Object.prototype.toString.call(e);
|
|
54
54
|
}
|
|
55
|
-
return t.slice(0,
|
|
55
|
+
return t.slice(0, ne);
|
|
56
56
|
}
|
|
57
|
-
function
|
|
57
|
+
function k(e) {
|
|
58
58
|
let { tenantOperations: t, tenantOperationEvents: n } = e;
|
|
59
59
|
return {
|
|
60
60
|
async markRunning(e, n) {
|
|
@@ -85,13 +85,13 @@ function O(e) {
|
|
|
85
85
|
async markFailed(e, n) {
|
|
86
86
|
await t.update(e, {
|
|
87
87
|
status: "failed",
|
|
88
|
-
error:
|
|
88
|
+
error: O(n),
|
|
89
89
|
finished_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
-
function
|
|
94
|
+
function re(e) {
|
|
95
95
|
return e === "succeeded" || e === "failed" || e === "cancelled";
|
|
96
96
|
}
|
|
97
97
|
//#endregion
|
|
@@ -101,8 +101,8 @@ var A = { async do(e, t, n) {
|
|
|
101
101
|
if (!r) throw Error("StepRunner.do called without a function");
|
|
102
102
|
return r();
|
|
103
103
|
} };
|
|
104
|
-
function
|
|
105
|
-
let t =
|
|
104
|
+
function j(e) {
|
|
105
|
+
let t = k(e.stores);
|
|
106
106
|
return {
|
|
107
107
|
engine: "inline",
|
|
108
108
|
async start(n) {
|
|
@@ -132,7 +132,7 @@ function ne(e) {
|
|
|
132
132
|
throw await t.appendEvent(n.id, {
|
|
133
133
|
step: e.name,
|
|
134
134
|
outcome: "failed",
|
|
135
|
-
detail: { message:
|
|
135
|
+
detail: { message: O(r) }
|
|
136
136
|
}), await t.markFailed(n.id, r), r;
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -142,7 +142,7 @@ function ne(e) {
|
|
|
142
142
|
}
|
|
143
143
|
//#endregion
|
|
144
144
|
//#region src/operations/enqueue.ts
|
|
145
|
-
async function
|
|
145
|
+
async function M(e, t, n) {
|
|
146
146
|
let r = await e.tenantOperations.create({
|
|
147
147
|
tenant_id: t.tenant_id,
|
|
148
148
|
rollout_id: t.rollout_id,
|
|
@@ -151,12 +151,12 @@ async function re(e, t, n) {
|
|
|
151
151
|
initiated_by: t.initiated_by,
|
|
152
152
|
target_worker_version: t.target_worker_version,
|
|
153
153
|
target_database_version: t.target_database_version
|
|
154
|
-
}), i =
|
|
154
|
+
}), i = te(r);
|
|
155
155
|
try {
|
|
156
156
|
await e.tenantOperations.update(r.id, { engine_instance_id: i });
|
|
157
157
|
} catch (t) {
|
|
158
158
|
try {
|
|
159
|
-
await
|
|
159
|
+
await k(e).markFailed(r.id, t);
|
|
160
160
|
} catch {}
|
|
161
161
|
throw t;
|
|
162
162
|
}
|
|
@@ -165,14 +165,14 @@ async function re(e, t, n) {
|
|
|
165
165
|
engine_instance_id: i
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
|
-
async function
|
|
169
|
-
let r =
|
|
168
|
+
async function N(e, t, n) {
|
|
169
|
+
let r = k(e), i = await M(e, n, t.engine);
|
|
170
170
|
try {
|
|
171
171
|
await t.start(i);
|
|
172
172
|
} catch (t) {
|
|
173
173
|
try {
|
|
174
174
|
let n = await e.tenantOperations.get(i.id);
|
|
175
|
-
n && !
|
|
175
|
+
n && !re(n.status) && await r.markFailed(i.id, t);
|
|
176
176
|
} catch (e) {
|
|
177
177
|
console.warn("Failed to record tenant operation failure:", e);
|
|
178
178
|
}
|
|
@@ -186,19 +186,19 @@ async function ie(e, t, n) {
|
|
|
186
186
|
}
|
|
187
187
|
//#endregion
|
|
188
188
|
//#region src/operations/record-provision.ts
|
|
189
|
-
function
|
|
189
|
+
function ie(e) {
|
|
190
190
|
if (e.tenantOperations && e.tenantOperationEvents) return {
|
|
191
191
|
tenantOperations: e.tenantOperations,
|
|
192
192
|
tenantOperationEvents: e.tenantOperationEvents
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
|
-
async function
|
|
196
|
-
let r =
|
|
195
|
+
async function P(e, t, n) {
|
|
196
|
+
let r = ie(e);
|
|
197
197
|
if (!r) {
|
|
198
198
|
await n(void 0);
|
|
199
199
|
return;
|
|
200
200
|
}
|
|
201
|
-
let i =
|
|
201
|
+
let i = k(r), a = async (e) => {
|
|
202
202
|
try {
|
|
203
203
|
await e();
|
|
204
204
|
} catch (e) {
|
|
@@ -206,7 +206,7 @@ async function oe(e, t, n) {
|
|
|
206
206
|
}
|
|
207
207
|
}, o;
|
|
208
208
|
if (await a(async () => {
|
|
209
|
-
let e = await
|
|
209
|
+
let e = await M(r, t, "inline");
|
|
210
210
|
o = e.id, await i.markRunning(e.id);
|
|
211
211
|
}), !o) {
|
|
212
212
|
await n(void 0);
|
|
@@ -228,7 +228,7 @@ async function oe(e, t, n) {
|
|
|
228
228
|
c || await i.appendEvent(s, {
|
|
229
229
|
step: t.kind,
|
|
230
230
|
outcome: "failed",
|
|
231
|
-
detail: { message:
|
|
231
|
+
detail: { message: O(e) }
|
|
232
232
|
}), await i.markFailed(s, e);
|
|
233
233
|
}), e;
|
|
234
234
|
}
|
|
@@ -241,26 +241,33 @@ async function oe(e, t, n) {
|
|
|
241
241
|
}
|
|
242
242
|
//#endregion
|
|
243
243
|
//#region src/hooks/provisioning.ts
|
|
244
|
-
function
|
|
244
|
+
function ae(e) {
|
|
245
245
|
return `urn:authhero:tenant:${e.toLowerCase()}`;
|
|
246
246
|
}
|
|
247
|
-
function
|
|
247
|
+
function F(e) {
|
|
248
248
|
return {
|
|
249
249
|
async beforeCreate(e, t) {
|
|
250
250
|
return !t.audience && t.id ? {
|
|
251
251
|
...t,
|
|
252
|
-
audience:
|
|
252
|
+
audience: ae(t.id)
|
|
253
253
|
} : t;
|
|
254
254
|
},
|
|
255
|
-
async afterCreate(
|
|
256
|
-
let { accessControl:
|
|
257
|
-
if (
|
|
258
|
-
let e =
|
|
259
|
-
|
|
255
|
+
async afterCreate(r, i) {
|
|
256
|
+
let { accessControl: a, databaseIsolation: o } = e;
|
|
257
|
+
if (a && r.ctx && await oe(r, i, a), o?.onProvision) {
|
|
258
|
+
let e = o.onProvision;
|
|
259
|
+
o.recordProvisionOperations === !1 ? await e(i.id) : await P(r.adapters, {
|
|
260
260
|
kind: "provision",
|
|
261
|
-
tenant_id:
|
|
262
|
-
initiated_by:
|
|
263
|
-
}, (t) => e(
|
|
261
|
+
tenant_id: i.id,
|
|
262
|
+
initiated_by: r.ctx?.var.user?.sub
|
|
263
|
+
}, (t) => e(i.id, t));
|
|
264
|
+
} else try {
|
|
265
|
+
await g(r.adapters, i.id, {
|
|
266
|
+
managementApiIdentifier: t,
|
|
267
|
+
managementApiScopes: n
|
|
268
|
+
});
|
|
269
|
+
} catch (e) {
|
|
270
|
+
throw console.warn(`Failed to provision default clients for tenant ${i.id}:`, e), e;
|
|
264
271
|
}
|
|
265
272
|
},
|
|
266
273
|
async beforeDelete(t, n) {
|
|
@@ -279,14 +286,14 @@ function j(e) {
|
|
|
279
286
|
}
|
|
280
287
|
};
|
|
281
288
|
}
|
|
282
|
-
async function
|
|
289
|
+
async function oe(e, t, n) {
|
|
283
290
|
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, u = await e.adapters.organizations.create(r, {
|
|
284
291
|
name: t.id,
|
|
285
292
|
display_name: t.friendly_name || t.id
|
|
286
293
|
}), d;
|
|
287
|
-
if (o && (d = await
|
|
294
|
+
if (o && (d = await ce(e, r, s, c)), l && e.ctx) {
|
|
288
295
|
let t = e.ctx.var.user;
|
|
289
|
-
if (t?.sub && !await
|
|
296
|
+
if (t?.sub && !await se(e, r, t.sub)) try {
|
|
290
297
|
await e.adapters.userOrganizations.create(r, {
|
|
291
298
|
user_id: t.sub,
|
|
292
299
|
organization_id: u.id
|
|
@@ -297,12 +304,12 @@ async function ce(e, t, n) {
|
|
|
297
304
|
}
|
|
298
305
|
a && a.length > 0 && console.log(`Would assign roles ${a.join(", ")} to organization ${u.id}`), i && i.length > 0 && console.log(`Would grant permissions ${i.join(", ")} to organization ${u.id}`);
|
|
299
306
|
}
|
|
300
|
-
async function
|
|
307
|
+
async function se(e, t, n) {
|
|
301
308
|
let r = await e.adapters.userRoles.list(t, n, void 0, "");
|
|
302
309
|
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;
|
|
303
310
|
return !1;
|
|
304
311
|
}
|
|
305
|
-
async function
|
|
312
|
+
async function ce(e, r, i, a) {
|
|
306
313
|
let o = (await e.adapters.roles.list(r, {})).roles.find((e) => e.name === i);
|
|
307
314
|
if (o) return o.id;
|
|
308
315
|
let s = await e.adapters.roles.create(r, {
|
|
@@ -317,7 +324,7 @@ async function ue(e, r, i, a) {
|
|
|
317
324
|
}
|
|
318
325
|
//#endregion
|
|
319
326
|
//#region src/hooks/sync.ts
|
|
320
|
-
function
|
|
327
|
+
function le(e, t, n = () => !0) {
|
|
321
328
|
let { controlPlaneTenantId: r, getChildTenantIds: i, getAdapters: a } = e, o = /* @__PURE__ */ new Map();
|
|
322
329
|
async function s(e, n, r) {
|
|
323
330
|
return (await t(e).list(n, {
|
|
@@ -372,7 +379,7 @@ function M(e, t, n = () => !0) {
|
|
|
372
379
|
}
|
|
373
380
|
};
|
|
374
381
|
}
|
|
375
|
-
function
|
|
382
|
+
function ue(e, t, n = () => !0) {
|
|
376
383
|
let { controlPlaneTenantId: r, getControlPlaneAdapters: i, getAdapters: a } = e;
|
|
377
384
|
return { async afterCreate(e, o) {
|
|
378
385
|
if (o.id !== r) try {
|
|
@@ -396,7 +403,7 @@ function N(e, t, n = () => !0) {
|
|
|
396
403
|
}
|
|
397
404
|
} };
|
|
398
405
|
}
|
|
399
|
-
var
|
|
406
|
+
var de = (e) => ({
|
|
400
407
|
list: async (t, n) => (await e.resourceServers.list(t, n)).resource_servers,
|
|
401
408
|
listPaginated: (t, n) => e.resourceServers.list(t, n),
|
|
402
409
|
get: (t, n) => e.resourceServers.get(t, n),
|
|
@@ -414,7 +421,7 @@ var P = (e) => ({
|
|
|
414
421
|
token_lifetime: e.token_lifetime,
|
|
415
422
|
token_lifetime_for_web: e.token_lifetime_for_web
|
|
416
423
|
})
|
|
417
|
-
}),
|
|
424
|
+
}), fe = (e) => ({
|
|
418
425
|
list: async (t, n) => (await e.roles.list(t, n)).roles,
|
|
419
426
|
listPaginated: (t, n) => e.roles.list(t, n),
|
|
420
427
|
get: (t, n) => e.roles.get(t, n),
|
|
@@ -429,11 +436,11 @@ var P = (e) => ({
|
|
|
429
436
|
description: e.description
|
|
430
437
|
})
|
|
431
438
|
});
|
|
432
|
-
function
|
|
439
|
+
function pe(e) {
|
|
433
440
|
return e.metadata?.sync !== !1;
|
|
434
441
|
}
|
|
435
|
-
function
|
|
436
|
-
let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) =>
|
|
442
|
+
function I(e) {
|
|
443
|
+
let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) => pe(e) ? !n.resourceServers || n.resourceServers(e) : !1, o = (e) => pe(e) ? !n.roles || n.roles(e) : !1, s = r ? le(e, de, a) : void 0, c = i ? le(e, fe, o) : void 0, l = r ? ue(e, de, a) : void 0, d = i ? ue(e, fe, o) : void 0, f = i ? { async afterCreate(t, r) {
|
|
437
444
|
if (r.id !== e.controlPlaneTenantId) {
|
|
438
445
|
await d?.afterCreate?.(t, r);
|
|
439
446
|
try {
|
|
@@ -488,35 +495,35 @@ function L(e) {
|
|
|
488
495
|
}
|
|
489
496
|
//#endregion
|
|
490
497
|
//#region src/routes/tenants.ts
|
|
491
|
-
var
|
|
492
|
-
sub:
|
|
493
|
-
tenant_id:
|
|
494
|
-
org_id:
|
|
495
|
-
scope:
|
|
496
|
-
permissions:
|
|
498
|
+
var me = x.object({
|
|
499
|
+
sub: x.string(),
|
|
500
|
+
tenant_id: x.string().optional(),
|
|
501
|
+
org_id: x.string().optional(),
|
|
502
|
+
scope: x.string().optional(),
|
|
503
|
+
permissions: x.array(x.string()).optional()
|
|
497
504
|
}).passthrough();
|
|
498
|
-
function
|
|
499
|
-
let t =
|
|
505
|
+
function he(e) {
|
|
506
|
+
let t = me.safeParse(e);
|
|
500
507
|
return t.success ? t.data : void 0;
|
|
501
508
|
}
|
|
502
|
-
function
|
|
509
|
+
function ge(e) {
|
|
503
510
|
let t = e.permissions ?? [], n = e.scope ? e.scope.split(" ").filter(Boolean) : [], r = /* @__PURE__ */ new Set([...t, ...n]);
|
|
504
511
|
return r.has("delete:tenants") || r.has("admin:organizations");
|
|
505
512
|
}
|
|
506
|
-
function
|
|
507
|
-
let n = new
|
|
508
|
-
return n.openapi(
|
|
513
|
+
function L(e, t) {
|
|
514
|
+
let n = new ee();
|
|
515
|
+
return n.openapi(b({
|
|
509
516
|
tags: ["tenants"],
|
|
510
517
|
method: "get",
|
|
511
518
|
path: "/",
|
|
512
519
|
request: { query: r },
|
|
513
520
|
security: [{ Bearer: [] }],
|
|
514
521
|
responses: { 200: {
|
|
515
|
-
content: { "application/json": { schema:
|
|
516
|
-
tenants:
|
|
517
|
-
start:
|
|
518
|
-
limit:
|
|
519
|
-
length:
|
|
522
|
+
content: { "application/json": { schema: x.object({
|
|
523
|
+
tenants: x.array(y),
|
|
524
|
+
start: x.number().optional(),
|
|
525
|
+
limit: x.number().optional(),
|
|
526
|
+
length: x.number().optional()
|
|
520
527
|
}) } },
|
|
521
528
|
description: "List of tenants"
|
|
522
529
|
} }
|
|
@@ -537,7 +544,7 @@ function R(e, t) {
|
|
|
537
544
|
}) : t.json({ tenants: e.tenants });
|
|
538
545
|
}
|
|
539
546
|
let c = e.accessControl?.controlPlaneTenantId ?? t.env.data.multiTenancyConfig?.controlPlaneTenantId;
|
|
540
|
-
if (c && !o?.sub) throw new
|
|
547
|
+
if (c && !o?.sub) throw new S(403, { message: "Access denied: token has no subject" });
|
|
541
548
|
if (c && o?.sub) {
|
|
542
549
|
let e = (await u((e) => t.env.data.userOrganizations.listUserOrganizations(c, o.sub, e), "organizations")).map((e) => e.name);
|
|
543
550
|
if (e.length === 0) return i ? t.json({
|
|
@@ -577,22 +584,22 @@ function R(e, t) {
|
|
|
577
584
|
limit: l.totals?.limit ?? r,
|
|
578
585
|
length: l.tenants.length
|
|
579
586
|
}) : t.json({ tenants: l.tenants });
|
|
580
|
-
}), n.openapi(
|
|
587
|
+
}), n.openapi(b({
|
|
581
588
|
tags: ["tenants"],
|
|
582
589
|
method: "post",
|
|
583
590
|
path: "/",
|
|
584
|
-
request: { body: { content: { "application/json": { schema:
|
|
591
|
+
request: { body: { content: { "application/json": { schema: v } } } },
|
|
585
592
|
security: [{ Bearer: [] }],
|
|
586
593
|
responses: {
|
|
587
594
|
201: {
|
|
588
|
-
content: { "application/json": { schema:
|
|
595
|
+
content: { "application/json": { schema: y } },
|
|
589
596
|
description: "Tenant created"
|
|
590
597
|
},
|
|
591
598
|
400: { description: "Validation error" },
|
|
592
599
|
409: { description: "Tenant with this ID already exists" }
|
|
593
600
|
}
|
|
594
601
|
}), async (e) => {
|
|
595
|
-
if (!e.var.user?.sub) throw new
|
|
602
|
+
if (!e.var.user?.sub) throw new S(401, { message: "Authentication required to create tenants" });
|
|
596
603
|
let n = e.req.valid("json"), r = {
|
|
597
604
|
adapters: e.env.data,
|
|
598
605
|
ctx: e
|
|
@@ -600,11 +607,11 @@ function R(e, t) {
|
|
|
600
607
|
t.tenants?.beforeCreate && (n = await t.tenants.beforeCreate(r, n));
|
|
601
608
|
let i = await e.env.data.tenants.create(n);
|
|
602
609
|
return t.tenants?.afterCreate && await t.tenants.afterCreate(r, i), e.json(i, 201);
|
|
603
|
-
}), n.openapi(
|
|
610
|
+
}), n.openapi(b({
|
|
604
611
|
tags: ["tenants"],
|
|
605
612
|
method: "delete",
|
|
606
613
|
path: "/{id}",
|
|
607
|
-
request: { params:
|
|
614
|
+
request: { params: x.object({ id: x.string() }) },
|
|
608
615
|
security: [{ Bearer: ["delete:tenants"] }],
|
|
609
616
|
responses: {
|
|
610
617
|
204: { description: "Tenant deleted" },
|
|
@@ -614,62 +621,70 @@ function R(e, t) {
|
|
|
614
621
|
}), async (n) => {
|
|
615
622
|
let { id: r } = n.req.valid("param"), i = e.accessControl?.controlPlaneTenantId ?? n.env.data.multiTenancyConfig?.controlPlaneTenantId;
|
|
616
623
|
if (i) {
|
|
617
|
-
let e =
|
|
618
|
-
if (!e?.sub) throw new
|
|
619
|
-
if (r === i) throw new
|
|
624
|
+
let e = he(n.var.user);
|
|
625
|
+
if (!e?.sub) throw new S(401, { message: "Authentication required" });
|
|
626
|
+
if (r === i) throw new S(403, { message: "Cannot delete the control plane" });
|
|
620
627
|
let t = n.var.org_name, a = r.toLowerCase(), o = !!t && t.toLowerCase() === a;
|
|
621
628
|
if (!o) {
|
|
622
629
|
let r = !!(e.org_id ?? n.var.organization_id ?? t), a = !e.tenant_id || e.tenant_id === i;
|
|
623
|
-
!r && a &&
|
|
630
|
+
!r && a && ge(e) && (o = !0);
|
|
624
631
|
}
|
|
625
|
-
if (o ||= (await u((t) => n.env.data.userOrganizations.listUserOrganizations(i, e.sub, t), "organizations")).some((e) => e.name?.toLowerCase() === a), !o) throw new
|
|
632
|
+
if (o ||= (await u((t) => n.env.data.userOrganizations.listUserOrganizations(i, e.sub, t), "organizations")).some((e) => e.name?.toLowerCase() === a), !o) throw new S(403, { message: "Access denied to this tenant" });
|
|
626
633
|
}
|
|
627
|
-
if (!await n.env.data.tenants.get(r)) throw new
|
|
634
|
+
if (!await n.env.data.tenants.get(r)) throw new S(404, { message: "Tenant not found" });
|
|
628
635
|
let a = {
|
|
629
636
|
adapters: n.env.data,
|
|
630
637
|
ctx: n
|
|
631
638
|
};
|
|
632
639
|
return t.tenants?.beforeDelete && await t.tenants.beforeDelete(a, r), await n.env.data.tenants.remove(r), t.tenants?.afterDelete && await t.tenants.afterDelete(a, r), n.body(null, 204);
|
|
633
|
-
}), n.openapi(
|
|
640
|
+
}), n.openapi(b({
|
|
634
641
|
tags: ["tenants", "settings"],
|
|
635
642
|
method: "get",
|
|
636
643
|
path: "/settings",
|
|
637
|
-
request: { headers:
|
|
644
|
+
request: { headers: x.object({ "tenant-id": x.string().optional() }) },
|
|
638
645
|
security: [{ Bearer: ["read:tenants"] }],
|
|
639
646
|
responses: { 200: {
|
|
640
|
-
content: { "application/json": { schema:
|
|
647
|
+
content: { "application/json": { schema: y } },
|
|
641
648
|
description: "Current tenant settings"
|
|
642
649
|
} }
|
|
643
650
|
}), async (e) => {
|
|
644
651
|
let t = await e.env.data.tenants.get(e.var.tenant_id);
|
|
645
|
-
if (!t) throw new
|
|
652
|
+
if (!t) throw new S(404, { message: "Tenant not found" });
|
|
646
653
|
return e.json(t);
|
|
647
|
-
}), n.openapi(
|
|
654
|
+
}), n.openapi(b({
|
|
648
655
|
tags: ["tenants", "settings"],
|
|
649
656
|
method: "patch",
|
|
650
657
|
path: "/settings",
|
|
651
658
|
request: {
|
|
652
|
-
headers:
|
|
653
|
-
body: { content: { "application/json": { schema:
|
|
659
|
+
headers: x.object({ "tenant-id": x.string().optional() }),
|
|
660
|
+
body: { content: { "application/json": { schema: x.object(v.shape).partial() } } }
|
|
654
661
|
},
|
|
655
662
|
security: [{ Bearer: ["update:tenants"] }],
|
|
656
663
|
responses: { 200: {
|
|
657
|
-
content: { "application/json": { schema:
|
|
664
|
+
content: { "application/json": { schema: y } },
|
|
658
665
|
description: "Updated tenant settings"
|
|
659
666
|
} }
|
|
660
667
|
}), async (e) => {
|
|
661
668
|
let { id: t, ...n } = e.req.valid("json"), r = await e.env.data.tenants.get(e.var.tenant_id);
|
|
662
|
-
if (!r) throw new
|
|
669
|
+
if (!r) throw new S(404, { message: "Tenant not found" });
|
|
670
|
+
if ("default_client_id" in n) {
|
|
671
|
+
let t = n.default_client_id;
|
|
672
|
+
if (typeof t == "string" && t.length > 0) {
|
|
673
|
+
let n = await e.env.data.clients.get(e.var.tenant_id, t);
|
|
674
|
+
if (!n) throw new S(400, { message: `Client with id '${t}' not found` });
|
|
675
|
+
if (!p(n)) throw new S(400, { message: `Client '${t}' is not an interactive client and cannot be used as the default client` });
|
|
676
|
+
}
|
|
677
|
+
}
|
|
663
678
|
let i = c(r, n);
|
|
664
679
|
await e.env.data.tenants.update(e.var.tenant_id, i);
|
|
665
680
|
let a = await e.env.data.tenants.get(e.var.tenant_id);
|
|
666
|
-
if (!a) throw new
|
|
681
|
+
if (!a) throw new S(500, { message: "Failed to retrieve updated tenant" });
|
|
667
682
|
return e.json(a);
|
|
668
683
|
}), n;
|
|
669
684
|
}
|
|
670
685
|
//#endregion
|
|
671
686
|
//#region src/middleware/protect-synced.ts
|
|
672
|
-
function
|
|
687
|
+
function _e(e) {
|
|
673
688
|
for (let { pattern: t, type: n } of [
|
|
674
689
|
{
|
|
675
690
|
pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
|
|
@@ -692,7 +707,7 @@ function me(e) {
|
|
|
692
707
|
}
|
|
693
708
|
return null;
|
|
694
709
|
}
|
|
695
|
-
async function
|
|
710
|
+
async function ve(e, t, n) {
|
|
696
711
|
try {
|
|
697
712
|
switch (n.type) {
|
|
698
713
|
case "resource_server": return (await e.resourceServers.get(t, n.id))?.is_system === !0;
|
|
@@ -704,31 +719,31 @@ async function he(e, t, n) {
|
|
|
704
719
|
return !1;
|
|
705
720
|
}
|
|
706
721
|
}
|
|
707
|
-
function
|
|
722
|
+
function ye(e) {
|
|
708
723
|
return {
|
|
709
724
|
resource_server: "resource server",
|
|
710
725
|
role: "role",
|
|
711
726
|
connection: "connection"
|
|
712
727
|
}[e];
|
|
713
728
|
}
|
|
714
|
-
function
|
|
729
|
+
function R() {
|
|
715
730
|
return async (e, t) => {
|
|
716
731
|
if (![
|
|
717
732
|
"PATCH",
|
|
718
733
|
"PUT",
|
|
719
734
|
"DELETE"
|
|
720
735
|
].includes(e.req.method)) return t();
|
|
721
|
-
let n =
|
|
736
|
+
let n = _e(e.req.path);
|
|
722
737
|
if (!n) return t();
|
|
723
738
|
let r = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
|
|
724
739
|
if (!r) return t();
|
|
725
|
-
if (await
|
|
740
|
+
if (await ve(e.env.data, r, n)) throw new S(403, { message: `This ${ye(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.` });
|
|
726
741
|
return t();
|
|
727
742
|
};
|
|
728
743
|
}
|
|
729
744
|
//#endregion
|
|
730
745
|
//#region src/middleware/settings-inheritance.ts
|
|
731
|
-
function
|
|
746
|
+
function z(e, t) {
|
|
732
747
|
let n = t.find((t) => t.strategy === e.strategy);
|
|
733
748
|
if (!n?.options) return e;
|
|
734
749
|
let r = s.passthrough().parse({
|
|
@@ -740,11 +755,11 @@ function B(e, t) {
|
|
|
740
755
|
...e.options
|
|
741
756
|
}), r;
|
|
742
757
|
}
|
|
743
|
-
function
|
|
758
|
+
function B(e, t) {
|
|
744
759
|
let n = [...t || [], ...e || []];
|
|
745
760
|
return [...new Set(n)];
|
|
746
761
|
}
|
|
747
|
-
function
|
|
762
|
+
function be(e, t) {
|
|
748
763
|
if (!t?.length) return e || [];
|
|
749
764
|
if (!e?.length) return t;
|
|
750
765
|
let n = /* @__PURE__ */ new Map();
|
|
@@ -752,22 +767,22 @@ function _e(e, t) {
|
|
|
752
767
|
for (let t of e) n.set(t.value, t);
|
|
753
768
|
return Array.from(n.values());
|
|
754
769
|
}
|
|
755
|
-
function
|
|
770
|
+
function V(e, t) {
|
|
756
771
|
return t ? {
|
|
757
772
|
...e,
|
|
758
|
-
scopes:
|
|
773
|
+
scopes: be(e.scopes, t.scopes)
|
|
759
774
|
} : e;
|
|
760
775
|
}
|
|
761
|
-
function
|
|
776
|
+
function xe(e, t) {
|
|
762
777
|
return t ? {
|
|
763
778
|
...e,
|
|
764
|
-
callbacks:
|
|
765
|
-
web_origins:
|
|
766
|
-
allowed_logout_urls:
|
|
767
|
-
allowed_origins:
|
|
779
|
+
callbacks: B(e.callbacks, t.callbacks),
|
|
780
|
+
web_origins: B(e.web_origins, t.web_origins),
|
|
781
|
+
allowed_logout_urls: B(e.allowed_logout_urls, t.allowed_logout_urls),
|
|
782
|
+
allowed_origins: B(e.allowed_origins, t.allowed_origins)
|
|
768
783
|
} : e;
|
|
769
784
|
}
|
|
770
|
-
function
|
|
785
|
+
function H(e) {
|
|
771
786
|
let { controlPlaneTenantId: t, controlPlaneClientId: n, resolveControlPlane: r } = e;
|
|
772
787
|
if (r) return async (e) => r({ tenant_id: e });
|
|
773
788
|
if (!t) return async () => void 0;
|
|
@@ -777,14 +792,14 @@ function U(e) {
|
|
|
777
792
|
};
|
|
778
793
|
return async () => i;
|
|
779
794
|
}
|
|
780
|
-
function
|
|
795
|
+
function U(e, t) {
|
|
781
796
|
return {
|
|
782
797
|
...e.resourceServers,
|
|
783
798
|
get: async (n, r) => {
|
|
784
799
|
let i = await e.resourceServers.get(n, r);
|
|
785
800
|
if (!i) return i;
|
|
786
801
|
let a = await t(n);
|
|
787
|
-
return !a || n === a.tenantId || !i.is_system ? i :
|
|
802
|
+
return !a || n === a.tenantId || !i.is_system ? i : V(i, await e.resourceServers.get(a.tenantId, r));
|
|
788
803
|
},
|
|
789
804
|
list: async (n, r) => {
|
|
790
805
|
let i = await e.resourceServers.list(n, r), a = await t(n);
|
|
@@ -796,7 +811,7 @@ function W(e, t) {
|
|
|
796
811
|
let n = await e.resourceServers.get(o, t);
|
|
797
812
|
n && c.set(t, n);
|
|
798
813
|
}));
|
|
799
|
-
let l = i.resource_servers.map((e) => e.is_system && e.id ?
|
|
814
|
+
let l = i.resource_servers.map((e) => e.is_system && e.id ? V(e, c.get(e.id) ?? null) : e);
|
|
800
815
|
return {
|
|
801
816
|
...i,
|
|
802
817
|
resource_servers: l
|
|
@@ -804,18 +819,18 @@ function W(e, t) {
|
|
|
804
819
|
}
|
|
805
820
|
};
|
|
806
821
|
}
|
|
807
|
-
function
|
|
808
|
-
let n =
|
|
822
|
+
function W(e, t) {
|
|
823
|
+
let n = H({
|
|
809
824
|
controlPlaneTenantId: t.controlPlaneTenantId,
|
|
810
825
|
resolveControlPlane: t.resolveControlPlane
|
|
811
826
|
});
|
|
812
827
|
return {
|
|
813
828
|
...e,
|
|
814
|
-
resourceServers:
|
|
829
|
+
resourceServers: U(e, n)
|
|
815
830
|
};
|
|
816
831
|
}
|
|
817
|
-
function
|
|
818
|
-
let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i } = t, a =
|
|
832
|
+
function G(e, t) {
|
|
833
|
+
let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i } = t, a = H({
|
|
819
834
|
controlPlaneTenantId: n,
|
|
820
835
|
controlPlaneClientId: r,
|
|
821
836
|
resolveControlPlane: i
|
|
@@ -833,12 +848,12 @@ function be(e, t) {
|
|
|
833
848
|
let r = await e.connections.get(t, n);
|
|
834
849
|
if (!r) return r;
|
|
835
850
|
let i = await a(t);
|
|
836
|
-
return !i || t === i.tenantId ? r :
|
|
851
|
+
return !i || t === i.tenantId ? r : z(r, (await e.connections.list(i.tenantId)).connections || []);
|
|
837
852
|
},
|
|
838
853
|
list: async (t, n) => {
|
|
839
854
|
let r = await e.connections.list(t, n), i = await a(t);
|
|
840
855
|
if (!i || t === i.tenantId) return r;
|
|
841
|
-
let o = await e.connections.list(i.tenantId), s = r.connections.map((e) =>
|
|
856
|
+
let o = await e.connections.list(i.tenantId), s = r.connections.map((e) => z(e, o.connections || []));
|
|
842
857
|
return {
|
|
843
858
|
...r,
|
|
844
859
|
connections: s
|
|
@@ -853,7 +868,7 @@ function be(e, t) {
|
|
|
853
868
|
let i = await a(t);
|
|
854
869
|
if (!i || t === i.tenantId) return r;
|
|
855
870
|
let o = await e.connections.list(i.tenantId);
|
|
856
|
-
return r.map((e) =>
|
|
871
|
+
return r.map((e) => z(e, o.connections || []));
|
|
857
872
|
}
|
|
858
873
|
},
|
|
859
874
|
emailProviders: {
|
|
@@ -865,11 +880,11 @@ function be(e, t) {
|
|
|
865
880
|
return !r || t === r.tenantId ? null : e.emailProviders.get(r.tenantId);
|
|
866
881
|
}
|
|
867
882
|
},
|
|
868
|
-
resourceServers:
|
|
883
|
+
resourceServers: U(e, a),
|
|
869
884
|
hooks: Se(e, a)
|
|
870
885
|
};
|
|
871
886
|
}
|
|
872
|
-
function
|
|
887
|
+
function K(e) {
|
|
873
888
|
if (!e || typeof e != "object") return !1;
|
|
874
889
|
let t = e.metadata;
|
|
875
890
|
return !t || typeof t != "object" ? !1 : t.inheritable === !0;
|
|
@@ -880,7 +895,7 @@ function Se(e, t) {
|
|
|
880
895
|
list: async (n, r) => {
|
|
881
896
|
let i = await e.hooks.list(n, r), a = await t(n);
|
|
882
897
|
if (!a || n === a.tenantId) return i;
|
|
883
|
-
let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(
|
|
898
|
+
let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(K);
|
|
884
899
|
if (o.length === 0) return i;
|
|
885
900
|
let s = new Set((i.hooks || []).map((e) => e.hook_id)), c = o.filter((e) => !s.has(e.hook_id));
|
|
886
901
|
return {
|
|
@@ -895,12 +910,12 @@ function Se(e, t) {
|
|
|
895
910
|
let a = await t(n);
|
|
896
911
|
if (!a || n === a.tenantId) return i;
|
|
897
912
|
let o = await e.hooks.get(a.tenantId, r);
|
|
898
|
-
return o &&
|
|
913
|
+
return o && K(o) ? o : null;
|
|
899
914
|
}
|
|
900
915
|
};
|
|
901
916
|
}
|
|
902
|
-
function
|
|
903
|
-
return
|
|
917
|
+
function q(e, t) {
|
|
918
|
+
return G(e, t);
|
|
904
919
|
}
|
|
905
920
|
//#endregion
|
|
906
921
|
//#region src/middleware/index.ts
|
|
@@ -914,8 +929,8 @@ function we(e) {
|
|
|
914
929
|
return async (n, r) => {
|
|
915
930
|
if (!e.accessControl) return r();
|
|
916
931
|
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);
|
|
917
|
-
if (!c && s && u && (n.set("tenant_id", s), c = s), !c) throw new
|
|
918
|
-
if (!
|
|
932
|
+
if (!c && s && u && (n.set("tenant_id", s), c = s), !c) throw new S(400, { message: "Tenant ID not found in request" });
|
|
933
|
+
if (!w(o, c, i, a)) throw new S(403, { message: `Access denied to tenant ${c}` });
|
|
919
934
|
return r();
|
|
920
935
|
};
|
|
921
936
|
}
|
|
@@ -934,7 +949,7 @@ function Te(e) {
|
|
|
934
949
|
let n = await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId, s);
|
|
935
950
|
n && (c = n.id);
|
|
936
951
|
} catch {}
|
|
937
|
-
if (!c) throw new
|
|
952
|
+
if (!c) throw new S(404, { message: `Tenant not found for subdomain: ${s}` });
|
|
938
953
|
return t.set("tenant_id", c), n();
|
|
939
954
|
};
|
|
940
955
|
}
|
|
@@ -942,17 +957,17 @@ function Ee(e) {
|
|
|
942
957
|
return async (t, n) => {
|
|
943
958
|
if (!e.databaseIsolation) return n();
|
|
944
959
|
let r = t.var.tenant_id;
|
|
945
|
-
if (!r) throw new
|
|
960
|
+
if (!r) throw new S(400, { message: "Tenant ID not found in request" });
|
|
946
961
|
try {
|
|
947
962
|
let n = await e.databaseIsolation.getAdapters(r);
|
|
948
963
|
t.env.data = n;
|
|
949
964
|
} catch (e) {
|
|
950
|
-
throw console.error(`Failed to resolve database for tenant ${r}:`, e), new
|
|
965
|
+
throw console.error(`Failed to resolve database for tenant ${r}:`, e), new S(500, { message: "Failed to resolve tenant database" });
|
|
951
966
|
}
|
|
952
967
|
return n();
|
|
953
968
|
};
|
|
954
969
|
}
|
|
955
|
-
function
|
|
970
|
+
function J(e) {
|
|
956
971
|
let t = Te(e), n = we(e), r = Ee(e);
|
|
957
972
|
return async (e, i) => (await t(e, async () => {}), await n(e, async () => {}), await r(e, async () => {}), i());
|
|
958
973
|
}
|
|
@@ -965,12 +980,12 @@ function De(e) {
|
|
|
965
980
|
}, defaultPermissions: s = ["tenant:admin"], requireOrganizationMatch: c = !1, managementApiExtensions: l = [], entityHooks: d, getChildTenantIds: p, getAdapters: m, ...h } = e;
|
|
966
981
|
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.");
|
|
967
982
|
let g = t, _ = t;
|
|
968
|
-
n && (g =
|
|
983
|
+
n && (g = q(t, {
|
|
969
984
|
controlPlaneTenantId: r,
|
|
970
985
|
controlPlaneClientId: i,
|
|
971
986
|
resolveControlPlane: a
|
|
972
987
|
}), _ = {
|
|
973
|
-
...
|
|
988
|
+
...W(t, {
|
|
974
989
|
controlPlaneTenantId: r,
|
|
975
990
|
resolveControlPlane: a
|
|
976
991
|
}),
|
|
@@ -985,7 +1000,7 @@ function De(e) {
|
|
|
985
1000
|
let e = {
|
|
986
1001
|
tenantOperations: t.tenantOperations,
|
|
987
1002
|
tenantOperationEvents: t.tenantOperationEvents
|
|
988
|
-
}, n = h.tenantUpgrade, r =
|
|
1003
|
+
}, n = h.tenantUpgrade, r = j({
|
|
989
1004
|
stores: e,
|
|
990
1005
|
definitions: { upgrade: (e) => [{
|
|
991
1006
|
name: "upgrade",
|
|
@@ -997,19 +1012,19 @@ function De(e) {
|
|
|
997
1012
|
});
|
|
998
1013
|
v = {
|
|
999
1014
|
engine: r.engine,
|
|
1000
|
-
enqueue: (t) =>
|
|
1015
|
+
enqueue: (t) => N(e, r, {
|
|
1001
1016
|
...t,
|
|
1002
1017
|
tenant_id: t.tenant_id
|
|
1003
1018
|
})
|
|
1004
1019
|
};
|
|
1005
1020
|
}
|
|
1006
|
-
let y = o !== !1,
|
|
1021
|
+
let y = o !== !1, ee = y ? {
|
|
1007
1022
|
resourceServers: o.resourceServers ?? !0,
|
|
1008
1023
|
roles: o.roles ?? !0
|
|
1009
1024
|
} : {
|
|
1010
1025
|
resourceServers: !1,
|
|
1011
1026
|
roles: !1
|
|
1012
|
-
}, { entityHooks:
|
|
1027
|
+
}, { entityHooks: b, tenantHooks: x } = I({
|
|
1013
1028
|
controlPlaneTenantId: r,
|
|
1014
1029
|
getChildTenantIds: p ?? (async () => (await u((e) => g.tenants.list(e), "tenants", {
|
|
1015
1030
|
cursorField: "id",
|
|
@@ -1017,50 +1032,50 @@ function De(e) {
|
|
|
1017
1032
|
})).filter((e) => e.id !== r).map((e) => e.id)),
|
|
1018
1033
|
getAdapters: m ?? (async () => g),
|
|
1019
1034
|
getControlPlaneAdapters: async () => g,
|
|
1020
|
-
sync:
|
|
1021
|
-
}),
|
|
1022
|
-
resourceServers: [
|
|
1023
|
-
roles: [
|
|
1035
|
+
sync: ee
|
|
1036
|
+
}), S = {
|
|
1037
|
+
resourceServers: [b.resourceServers, ...d?.resourceServers ?? []],
|
|
1038
|
+
roles: [b.roles, ...d?.roles ?? []],
|
|
1024
1039
|
connections: d?.connections ?? [],
|
|
1025
1040
|
tenants: d?.tenants ?? [],
|
|
1026
1041
|
rolePermissions: d?.rolePermissions ?? []
|
|
1027
|
-
},
|
|
1042
|
+
}, C = F({ accessControl: {
|
|
1028
1043
|
controlPlaneTenantId: r,
|
|
1029
1044
|
requireOrganizationMatch: c,
|
|
1030
1045
|
defaultPermissions: s
|
|
1031
|
-
} }),
|
|
1046
|
+
} }), w = L({ accessControl: {
|
|
1032
1047
|
controlPlaneTenantId: r,
|
|
1033
1048
|
requireOrganizationMatch: c,
|
|
1034
1049
|
defaultPermissions: s
|
|
1035
1050
|
} }, { tenants: {
|
|
1036
1051
|
async beforeCreate(e, t) {
|
|
1037
|
-
return
|
|
1052
|
+
return C.beforeCreate && (t = await C.beforeCreate(e, t)), x.beforeCreate && (t = await x.beforeCreate(e, t)), t;
|
|
1038
1053
|
},
|
|
1039
1054
|
async afterCreate(e, t) {
|
|
1040
|
-
await
|
|
1055
|
+
await C.afterCreate?.(e, t), await x.afterCreate?.(e, t);
|
|
1041
1056
|
},
|
|
1042
1057
|
async beforeDelete(e, t) {
|
|
1043
|
-
await
|
|
1058
|
+
await C.beforeDelete?.(e, t), await x.beforeDelete?.(e, t);
|
|
1044
1059
|
}
|
|
1045
|
-
} }), { app:
|
|
1060
|
+
} }), { app: T } = f({
|
|
1046
1061
|
dataAdapter: g,
|
|
1047
1062
|
managementDataAdapter: _,
|
|
1048
1063
|
...h,
|
|
1049
1064
|
tenantOperationExecutor: v,
|
|
1050
|
-
entityHooks:
|
|
1065
|
+
entityHooks: S,
|
|
1051
1066
|
managementApiExtensions: [...l, {
|
|
1052
1067
|
path: "/tenants",
|
|
1053
|
-
router:
|
|
1068
|
+
router: w
|
|
1054
1069
|
}]
|
|
1055
1070
|
});
|
|
1056
|
-
return
|
|
1057
|
-
app:
|
|
1071
|
+
return T.use("/api/v2/*", Ce(r)), y && T.use("/api/v2/*", R()), {
|
|
1072
|
+
app: T,
|
|
1058
1073
|
controlPlaneTenantId: r
|
|
1059
1074
|
};
|
|
1060
1075
|
}
|
|
1061
1076
|
//#endregion
|
|
1062
1077
|
//#region src/rollout/defaults-projection.ts
|
|
1063
|
-
function
|
|
1078
|
+
function Y(e = {}) {
|
|
1064
1079
|
return {
|
|
1065
1080
|
connections: e.connections ?? !0,
|
|
1066
1081
|
resourceServers: e.resourceServers ?? !0,
|
|
@@ -1070,28 +1085,28 @@ function q(e = {}) {
|
|
|
1070
1085
|
promptSettings: e.promptSettings ?? !0
|
|
1071
1086
|
};
|
|
1072
1087
|
}
|
|
1073
|
-
function
|
|
1088
|
+
function X() {
|
|
1074
1089
|
return {
|
|
1075
1090
|
upserted: 0,
|
|
1076
1091
|
errors: []
|
|
1077
1092
|
};
|
|
1078
1093
|
}
|
|
1079
|
-
function
|
|
1094
|
+
function Oe(e) {
|
|
1080
1095
|
return {
|
|
1081
1096
|
tenantId: e,
|
|
1082
|
-
connections:
|
|
1083
|
-
resourceServers:
|
|
1084
|
-
hooks:
|
|
1085
|
-
emailProvider:
|
|
1086
|
-
branding:
|
|
1087
|
-
promptSettings:
|
|
1097
|
+
connections: X(),
|
|
1098
|
+
resourceServers: X(),
|
|
1099
|
+
hooks: X(),
|
|
1100
|
+
emailProvider: X(),
|
|
1101
|
+
branding: X(),
|
|
1102
|
+
promptSettings: X()
|
|
1088
1103
|
};
|
|
1089
1104
|
}
|
|
1090
|
-
function
|
|
1105
|
+
function ke(e) {
|
|
1091
1106
|
let t = e.metadata;
|
|
1092
1107
|
return !!(t && t.inheritable === !0);
|
|
1093
1108
|
}
|
|
1094
|
-
async function
|
|
1109
|
+
async function Z(e, t, n, r) {
|
|
1095
1110
|
try {
|
|
1096
1111
|
await r();
|
|
1097
1112
|
} catch (r) {
|
|
@@ -1100,7 +1115,7 @@ async function X(e, t, n, r) {
|
|
|
1100
1115
|
e.errors.push(i);
|
|
1101
1116
|
}
|
|
1102
1117
|
}
|
|
1103
|
-
async function
|
|
1118
|
+
async function Ae(e, t, n) {
|
|
1104
1119
|
return {
|
|
1105
1120
|
connections: n.connections ? await u((n) => e.connections.list(t, n), "connections", {
|
|
1106
1121
|
cursorField: "id",
|
|
@@ -1119,47 +1134,47 @@ async function ke(e, t, n) {
|
|
|
1119
1134
|
promptSettings: n.promptSettings ? await e.promptSettings.get(t) ?? null : null
|
|
1120
1135
|
};
|
|
1121
1136
|
}
|
|
1122
|
-
async function
|
|
1137
|
+
async function je(e, t, n, r, i, o) {
|
|
1123
1138
|
if (r.connections) for (let r of e.connections) {
|
|
1124
1139
|
let e = r.id;
|
|
1125
|
-
e && await
|
|
1140
|
+
e && await Z(o.connections, `connection ${e}`, i, async () => {
|
|
1126
1141
|
let i = a.parse(r);
|
|
1127
1142
|
await t.connections.get(n, e) ? await t.connections.update(n, e, i) : await t.connections.create(n, i), o.connections.upserted += 1;
|
|
1128
1143
|
});
|
|
1129
1144
|
}
|
|
1130
|
-
if (r.resourceServers) for (let r of e.resourceServers) !r.is_system || !r.id || await
|
|
1131
|
-
let e =
|
|
1145
|
+
if (r.resourceServers) for (let r of e.resourceServers) !r.is_system || !r.id || await Z(o.resourceServers, `resource_server ${r.id}`, i, async () => {
|
|
1146
|
+
let e = _.parse(r);
|
|
1132
1147
|
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;
|
|
1133
1148
|
});
|
|
1134
|
-
if (r.hooks) for (let r of e.hooks) !
|
|
1149
|
+
if (r.hooks) for (let r of e.hooks) !ke(r) || !r.hook_id || await Z(o.hooks, `hook ${r.hook_id}`, i, async () => {
|
|
1135
1150
|
let e = d.parse(r);
|
|
1136
1151
|
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;
|
|
1137
1152
|
});
|
|
1138
|
-
r.emailProvider && e.emailProvider && await
|
|
1153
|
+
r.emailProvider && e.emailProvider && await Z(o.emailProvider, "email_provider", i, async () => {
|
|
1139
1154
|
let r = e.emailProvider;
|
|
1140
1155
|
await t.emailProviders.get(n) ? await t.emailProviders.update(n, r) : await t.emailProviders.create(n, r), o.emailProvider.upserted += 1;
|
|
1141
|
-
}), r.branding && e.branding && await
|
|
1156
|
+
}), r.branding && e.branding && await Z(o.branding, "branding", i, async () => {
|
|
1142
1157
|
await t.branding.set(n, e.branding), o.branding.upserted += 1;
|
|
1143
|
-
}), r.promptSettings && e.promptSettings && await
|
|
1158
|
+
}), r.promptSettings && e.promptSettings && await Z(o.promptSettings, "prompt_settings", i, async () => {
|
|
1144
1159
|
await t.promptSettings.set(n, e.promptSettings), o.promptSettings.upserted += 1;
|
|
1145
1160
|
});
|
|
1146
1161
|
}
|
|
1147
|
-
async function
|
|
1148
|
-
let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s =
|
|
1149
|
-
return await
|
|
1162
|
+
async function Q(e, t) {
|
|
1163
|
+
let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s = Y(a), c = await Ae(await r(), n, s), l = await i(t), u = Oe(t);
|
|
1164
|
+
return await je(c, l, n, s, o, u), u;
|
|
1150
1165
|
}
|
|
1151
1166
|
//#endregion
|
|
1152
1167
|
//#region src/rollout/payload.ts
|
|
1153
|
-
function
|
|
1168
|
+
function Me(e) {
|
|
1154
1169
|
let { pkcs7: t, tenant_id: n, ...r } = e;
|
|
1155
1170
|
return r;
|
|
1156
1171
|
}
|
|
1157
|
-
async function
|
|
1158
|
-
let i =
|
|
1172
|
+
async function Ne(e, t, n = {}, r) {
|
|
1173
|
+
let i = Y(n), a = n.signingKeys ?? !0, o = n.tenants ?? !0, s = await Ae(e, t, i), c = a ? (await m(e.keys)).map(Me) : [], l = o ? await Pe(e, t, r) : [];
|
|
1159
1174
|
return {
|
|
1160
1175
|
connections: s.connections,
|
|
1161
1176
|
resourceServers: s.resourceServers.filter((e) => e.is_system),
|
|
1162
|
-
hooks: s.hooks.filter(
|
|
1177
|
+
hooks: s.hooks.filter(ke),
|
|
1163
1178
|
emailProvider: s.emailProvider,
|
|
1164
1179
|
branding: s.branding,
|
|
1165
1180
|
promptSettings: s.promptSettings,
|
|
@@ -1167,7 +1182,7 @@ async function Me(e, t, n = {}, r) {
|
|
|
1167
1182
|
tenants: l
|
|
1168
1183
|
};
|
|
1169
1184
|
}
|
|
1170
|
-
async function
|
|
1185
|
+
async function Pe(e, t, n) {
|
|
1171
1186
|
let r = n && n !== t ? [t, n] : [t], i = [];
|
|
1172
1187
|
for (let t of r) {
|
|
1173
1188
|
let n = await e.tenants.get(t);
|
|
@@ -1178,19 +1193,19 @@ async function Ne(e, t, n) {
|
|
|
1178
1193
|
}
|
|
1179
1194
|
return i;
|
|
1180
1195
|
}
|
|
1181
|
-
async function
|
|
1182
|
-
let r =
|
|
1196
|
+
async function Fe(e, t, n) {
|
|
1197
|
+
let r = X();
|
|
1183
1198
|
if (e.length === 0) return r;
|
|
1184
|
-
let i = await
|
|
1185
|
-
for (let i of e) await
|
|
1186
|
-
let e =
|
|
1199
|
+
let i = await m(t.keys), a = new Set(i.map((e) => e.kid));
|
|
1200
|
+
for (let i of e) await Z(r, `signing_key ${i.kid}`, n, async () => {
|
|
1201
|
+
let e = Me(i);
|
|
1187
1202
|
a.has(e.kid) || (await t.keys.create(e), a.add(e.kid), r.upserted += 1);
|
|
1188
1203
|
});
|
|
1189
1204
|
return r;
|
|
1190
1205
|
}
|
|
1191
|
-
async function
|
|
1192
|
-
let r =
|
|
1193
|
-
for (let i of e) await
|
|
1206
|
+
async function Ie(e, t, n) {
|
|
1207
|
+
let r = X();
|
|
1208
|
+
for (let i of e) await Z(r, `tenant ${i.id}`, n, async () => {
|
|
1194
1209
|
await t.tenants.get(i.id) || (await t.tenants.create({
|
|
1195
1210
|
id: i.id,
|
|
1196
1211
|
friendly_name: i.friendly_name
|
|
@@ -1198,17 +1213,17 @@ async function Fe(e, t, n) {
|
|
|
1198
1213
|
});
|
|
1199
1214
|
return r;
|
|
1200
1215
|
}
|
|
1201
|
-
async function
|
|
1202
|
-
let a = r.continueOnError ?? !1, o =
|
|
1216
|
+
async function Le(e, t, n, r = {}) {
|
|
1217
|
+
let a = r.continueOnError ?? !1, o = Y(r.entities), s = r.entities?.signingKeys ?? !0, c = r.entities?.tenants ?? !0, u = {
|
|
1203
1218
|
connections: e.connections,
|
|
1204
1219
|
resourceServers: e.resourceServers,
|
|
1205
1220
|
hooks: e.hooks,
|
|
1206
1221
|
emailProvider: e.emailProvider ? l.parse(e.emailProvider) : null,
|
|
1207
1222
|
branding: e.branding ? i.parse(e.branding) : null,
|
|
1208
|
-
promptSettings: e.promptSettings ?
|
|
1209
|
-
}, d = c ? await
|
|
1210
|
-
await
|
|
1211
|
-
let p = s ? await
|
|
1223
|
+
promptSettings: e.promptSettings ? h.parse(e.promptSettings) : null
|
|
1224
|
+
}, d = c ? await Ie(e.tenants ?? [], t, a) : X(), f = Oe(n);
|
|
1225
|
+
await je(u, t, n, o, a, f);
|
|
1226
|
+
let p = s ? await Fe(e.signingKeys, t, a) : X();
|
|
1212
1227
|
return {
|
|
1213
1228
|
...f,
|
|
1214
1229
|
signingKeys: p,
|
|
@@ -1217,27 +1232,27 @@ async function Ie(e, t, n, r = {}) {
|
|
|
1217
1232
|
}
|
|
1218
1233
|
//#endregion
|
|
1219
1234
|
//#region src/rollout/index.ts
|
|
1220
|
-
function
|
|
1235
|
+
function Re(e) {
|
|
1221
1236
|
return {
|
|
1222
|
-
syncDefaults: (t) =>
|
|
1237
|
+
syncDefaults: (t) => Q(e, t),
|
|
1223
1238
|
syncDefaultsToTenants: async (t) => {
|
|
1224
1239
|
let n = [];
|
|
1225
|
-
for (let r of t) n.push(await
|
|
1240
|
+
for (let r of t) n.push(await Q(e, r));
|
|
1226
1241
|
return n;
|
|
1227
1242
|
}
|
|
1228
1243
|
};
|
|
1229
1244
|
}
|
|
1230
1245
|
//#endregion
|
|
1231
1246
|
//#region src/plugin.ts
|
|
1232
|
-
function
|
|
1233
|
-
let t =
|
|
1247
|
+
function ze(e) {
|
|
1248
|
+
let t = $(e);
|
|
1234
1249
|
return {
|
|
1235
1250
|
name: "multi-tenancy",
|
|
1236
|
-
middleware:
|
|
1251
|
+
middleware: J(e),
|
|
1237
1252
|
hooks: t,
|
|
1238
1253
|
routes: [{
|
|
1239
1254
|
path: "/management",
|
|
1240
|
-
handler:
|
|
1255
|
+
handler: L(e, t)
|
|
1241
1256
|
}],
|
|
1242
1257
|
onRegister: async () => {
|
|
1243
1258
|
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");
|
|
@@ -1246,29 +1261,29 @@ function Re(e) {
|
|
|
1246
1261
|
}
|
|
1247
1262
|
//#endregion
|
|
1248
1263
|
//#region src/index.ts
|
|
1249
|
-
function
|
|
1250
|
-
let t = e.accessControl ?
|
|
1264
|
+
function $(e) {
|
|
1265
|
+
let t = e.accessControl ? C(e.accessControl) : {}, n = e.databaseIsolation ? T(e.databaseIsolation) : {}, r = F(e);
|
|
1251
1266
|
return {
|
|
1252
1267
|
...t,
|
|
1253
1268
|
...n,
|
|
1254
1269
|
tenants: r
|
|
1255
1270
|
};
|
|
1256
1271
|
}
|
|
1257
|
-
function
|
|
1258
|
-
let n = new e(), r =
|
|
1259
|
-
return n.route("/tenants",
|
|
1272
|
+
function Be(t) {
|
|
1273
|
+
let n = new e(), r = $(t);
|
|
1274
|
+
return n.route("/tenants", L(t, r)), n;
|
|
1260
1275
|
}
|
|
1261
|
-
function
|
|
1276
|
+
function Ve(e) {
|
|
1262
1277
|
return {
|
|
1263
|
-
hooks:
|
|
1264
|
-
middleware:
|
|
1265
|
-
app:
|
|
1278
|
+
hooks: $(e),
|
|
1279
|
+
middleware: J(e),
|
|
1280
|
+
app: Be(e),
|
|
1266
1281
|
config: e,
|
|
1267
|
-
wrapAdapters: (t, n) =>
|
|
1282
|
+
wrapAdapters: (t, n) => q(t, {
|
|
1268
1283
|
controlPlaneTenantId: e.accessControl?.controlPlaneTenantId,
|
|
1269
1284
|
controlPlaneClientId: n?.controlPlaneClientId
|
|
1270
1285
|
})
|
|
1271
1286
|
};
|
|
1272
1287
|
}
|
|
1273
1288
|
//#endregion
|
|
1274
|
-
export {
|
|
1289
|
+
export { Le as applyControlPlaneDefaultsPayload, Ne as buildControlPlaneDefaultsPayload, te as buildEngineInstanceId, C as createAccessControlHooks, we as createAccessControlMiddleware, Ce as createControlPlaneTenantMiddleware, T as createDatabaseHooks, Ee as createDatabaseMiddleware, Re as createDirectRolloutAdapter, j as createInlineExecutor, Be as createMultiTenancy, $ as createMultiTenancyHooks, J as createMultiTenancyMiddleware, ze as createMultiTenancyPlugin, k as createOperationRecorder, R as createProtectSyncedMiddleware, F as createProvisioningHooks, G as createRuntimeFallbackAdapter, Te as createSubdomainMiddleware, I as createSyncHooks, L as createTenantsOpenAPIRouter, N as enqueueTenantOperation, O as errorToMessage, De as initMultiTenant, A as inlineStepRunner, re as isTerminalStatus, xe as mergeClientWithFallback, Q as projectControlPlaneDefaults, P as runRecordedTenantOperation, Ve as setupMultiTenancy, w as validateTenantAccess, q as withRuntimeFallback, W as withSystemResourceServerInheritance };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../../src/hooks/provisioning.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../../src/hooks/provisioning.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,UAAU,CAAC;AAGlB;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,kBAAkB,GACzB,iBAAiB,CAiHnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants.d.ts","sourceRoot":"","sources":["../../../src/routes/tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"tenants.d.ts","sourceRoot":"","sources":["../../../src/routes/tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAWhE,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,UAAU,CAAC;AAwClB;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,iBAAiB;cAGZ,oBAAoB;eACnB,qBAAqB;YAshBnC"}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/markusahlstrand/authhero"
|
|
13
13
|
},
|
|
14
|
-
"version": "14.
|
|
14
|
+
"version": "14.27.0",
|
|
15
15
|
"description": "Multi-tenancy support for AuthHero with organization-based access control and per-tenant database isolation",
|
|
16
16
|
"files": [
|
|
17
17
|
"dist"
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"typescript": "^5.6.0",
|
|
37
37
|
"vite": "^8.0.14",
|
|
38
38
|
"vitest": "^4.1.7",
|
|
39
|
-
"@authhero/adapter-interfaces": "3.
|
|
40
|
-
"
|
|
41
|
-
"authhero": "
|
|
39
|
+
"@authhero/adapter-interfaces": "3.8.0",
|
|
40
|
+
"authhero": "8.18.0",
|
|
41
|
+
"@authhero/kysely-adapter": "11.14.2"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"zod": "^4.4.3"
|