@authhero/multi-tenancy 15.1.2 → 15.2.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 +1 -1
- package/dist/multi-tenancy.mjs +748 -353
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/inheritance/chain.d.ts +18 -0
- package/dist/types/inheritance/chain.d.ts.map +1 -0
- package/dist/types/inheritance/index.d.ts +10 -0
- package/dist/types/inheritance/index.d.ts.map +1 -0
- package/dist/types/inheritance/legacy.d.ts +7 -0
- package/dist/types/inheritance/legacy.d.ts.map +1 -0
- package/dist/types/inheritance/merge.d.ts +39 -0
- package/dist/types/inheritance/merge.d.ts.map +1 -0
- package/dist/types/inheritance/read.d.ts +5 -0
- package/dist/types/inheritance/read.d.ts.map +1 -0
- package/dist/types/inheritance/report.d.ts +20 -0
- package/dist/types/inheritance/report.d.ts.map +1 -0
- package/dist/types/inheritance/shadow.d.ts +30 -0
- package/dist/types/inheritance/shadow.d.ts.map +1 -0
- package/dist/types/inheritance/types.d.ts +22 -0
- package/dist/types/inheritance/types.d.ts.map +1 -0
- package/dist/types/init.d.ts +10 -0
- package/dist/types/init.d.ts.map +1 -1
- package/dist/types/middleware/settings-inheritance.d.ts +31 -1
- package/dist/types/middleware/settings-inheritance.d.ts.map +1 -1
- package/dist/types/routes/tenants.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/tenant-tree.d.ts +32 -0
- package/dist/types/utils/tenant-tree.d.ts.map +1 -0
- package/package.json +4 -4
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(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,n,r){let i=await e.adapters.userRoles.list(n,r,void 0,``);for(let r of i)if((await e.adapters.rolePermissions.list(n,r.id,{per_page:1e3})).some(e=>e.permission_name===`admin:organizations`&&e.resource_server_identifier===t.MANAGEMENT_API_AUDIENCE))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,n,r=()=>!0){let{controlPlaneTenantId:i,getChildTenantIds:a,getAdapters:o}=e,s=new Map;async function c(e,r,i){return(await n(e).list(r,{q:`name:${(0,t.escapeLuceneValue)(i)}`,per_page:1}))[0]??null}async function l(e){let t=await a(),r=n(await o(i));await Promise.all(t.map(async t=>{try{let i=await o(t),a=n(i),s={...r.transform(e),is_system:!0},l=await c(i,t,e.name),u=l?a.getId(l):void 0;if(l&&u){let e=a.preserveOnUpdate?a.preserveOnUpdate(l,s):s;await a.update(t,u,e)}else await a.create(t,s)}catch(n){console.error(`Failed to sync ${r.listKey} "${e.name}" to tenant "${t}":`,n)}}))}async function u(e){let t=await a();await Promise.all(t.map(async t=>{try{let r=await o(t),i=n(r),a=await c(r,t,e),s=a?i.getId(a):void 0;a&&s&&await i.remove(t,s)}catch(n){console.error(`Failed to delete entity "${e}" from tenant "${t}":`,n)}}))}return{afterCreate:async(e,t)=>{e.tenantId===i&&r(t)&&await l(t)},afterUpdate:async(e,t,n)=>{e.tenantId===i&&r(n)&&await l(n)},beforeDelete:async(e,t)=>{if(e.tenantId!==i)return;let a=await n(e.adapters).get(e.tenantId,t);a&&r(a)&&s.set(t,a)},afterDelete:async(e,t)=>{if(e.tenantId!==i)return;let n=s.get(t);n&&(s.delete(t),await u(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,n,r){return(await e.roles.list(n,{q:`name:${(0,t.escapeLuceneValue)(r)}`,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(`; `))}}}}function j(e){return e.var.data??e.env.data}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 M(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(),total: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 j(n).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,total:e.totals?.length}):n.json({tenants:e.tenants})}let u=e.accessControl?.controlPlaneTenantId??j(n).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=>j(n).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,total: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:0,total:r}):n.json({tenants:[]});let m=p.map(e=>`id:${e}`).join(` OR `),h=s?`(${m}) AND (${s})`:m,g=await j(n).tenants.list({q:h,per_page:d,include_totals:!1});return o?n.json({tenants:g.tenants,start:f,limit:d,length:g.tenants.length,total:r}):n.json({tenants:g.tenants})}let d=await j(n).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,total:d.totals?.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:j(e),ctx:e};i.tenants?.beforeCreate&&(t=await i.tenants.beforeCreate(n,t));let a=await j(e).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??j(n).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=>j(n).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 j(n).tenants.get(a))throw new r.HTTPException(404,{message:`Tenant not found`});let s={adapters:j(n),ctx:n};return i.tenants?.beforeDelete&&await i.tenants.beforeDelete(s,a),await j(n).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 j(e).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 j(e).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 j(e).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 j(e).tenants.update(e.var.tenant_id,o);let s=await j(e).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 oe(){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(j(e),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 se(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:se(e.scopes,t.scopes)}:e}function ce(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 L(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 R(e,t){let n=I({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:L(e,n)}}function z(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:L(e,a),hooks:le(e,a)}}function B(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function le(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(B);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&&B(o)?o:null}}}function V(e,t){return z(e,t)}function ue(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 H(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 U(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 j(t).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 W(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.set(`baseData`,n),t.env={...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 G(e){let t=U(e),n=H(e),r=W(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=V(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),v={...R(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=M({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}],managementApiMiddleware:[...m.managementApiMiddleware??[],...b?[oe()]:[]]});return{app:O,controlPlaneTenantId:i}}function K(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 q(){return{upserted:0,errors:[]}}function J(e){return{tenantId:e,connections:q(),resourceServers:q(),hooks:q(),emailProvider:q(),branding:q(),promptSettings:q()}}function Y(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function X(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 Z(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 fe(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await X(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 X(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)!Y(i)||!i.hook_id||await X(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 X(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 X(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await X(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=K(a),c=await Z(await r(),n,s),l=await i(t),u=J(t);return await fe(c,l,n,s,o,u),u}function pe(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function me(e,n,r={},i){let a=K(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await Z(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(pe):[],u=s?await he(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(Y),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function he(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 ge(e,n,r){let i=q();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 X(i,`signing_key ${t.kid}`,r,async()=>{let e=pe(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function _e(e,t,n){let r=q();for(let i of e)await X(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 ve(e,n,r,i={}){let a=i.continueOnError??!1,o=K(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 _e(e.tenants??[],n,a):q(),d=J(r);await fe(l,n,r,o,a,d);let f=s?await ge(e.signingKeys,n,a):q();return{...d,signingKeys:f,tenants:u}}function ye(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 be(e){let t=$(e);return{name:`multi-tenancy`,middleware:G(e),hooks:t,routes:[{path:`/management`,handler:M(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 xe(t){let n=new e.Hono,r=$(t);return n.route(`/tenants`,M(t,r)),n}function Se(e){return{hooks:$(e),middleware:G(e),app:xe(e),config:e,wrapAdapters:(t,n)=>V(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.applyControlPlaneDefaultsPayload=ve,exports.buildControlPlaneDefaultsPayload=me,exports.buildEngineInstanceId=l,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=H,exports.createControlPlaneTenantMiddleware=ue,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=W,exports.createDirectRolloutAdapter=ye,exports.createInlineExecutor=h,exports.createMultiTenancy=xe,exports.createMultiTenancyHooks=$,exports.createMultiTenancyMiddleware=G,exports.createMultiTenancyPlugin=be,exports.createOperationRecorder=f,exports.createProtectSyncedMiddleware=oe,exports.createProvisioningHooks=x,exports.createRuntimeFallbackAdapter=z,exports.createSubdomainMiddleware=U,exports.createSyncHooks=A,exports.createTenantsOpenAPIRouter=M,exports.enqueueTenantOperation=_,exports.errorToMessage=d,exports.initMultiTenant=de,exports.inlineStepRunner=m,exports.isTerminalStatus=p,exports.mergeClientWithFallback=ce,exports.projectControlPlaneDefaults=Q,exports.runRecordedTenantOperation=y,exports.setupMultiTenancy=Se,exports.validateTenantAccess=a,exports.withRuntimeFallback=V,exports.withSystemResourceServerInheritance=R;
|
|
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 C(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await ee(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 ee(e,n,r){let i=await e.adapters.userRoles.list(n,r,void 0,``);for(let r of i)if((await e.adapters.rolePermissions.list(n,r.id,{per_page:1e3})).some(e=>e.permission_name===`admin:organizations`&&e.resource_server_identifier===t.MANAGEMENT_API_AUDIENCE))return!0;return!1}async function C(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 w(e,n,r=()=>!0){let{controlPlaneTenantId:i,getChildTenantIds:a,getAdapters:o}=e,s=new Map;async function c(e,r,i){return(await n(e).list(r,{q:`name:${(0,t.escapeLuceneValue)(i)}`,per_page:1}))[0]??null}async function l(e){let t=await a(),r=n(await o(i));await Promise.all(t.map(async t=>{try{let i=await o(t),a=n(i),s={...r.transform(e),is_system:!0},l=await c(i,t,e.name),u=l?a.getId(l):void 0;if(l&&u){let e=a.preserveOnUpdate?a.preserveOnUpdate(l,s):s;await a.update(t,u,e)}else await a.create(t,s)}catch(n){console.error(`Failed to sync ${r.listKey} "${e.name}" to tenant "${t}":`,n)}}))}async function u(e){let t=await a();await Promise.all(t.map(async t=>{try{let r=await o(t),i=n(r),a=await c(r,t,e),s=a?i.getId(a):void 0;a&&s&&await i.remove(t,s)}catch(n){console.error(`Failed to delete entity "${e}" from tenant "${t}":`,n)}}))}return{afterCreate:async(e,t)=>{e.tenantId===i&&r(t)&&await l(t)},afterUpdate:async(e,t,n)=>{e.tenantId===i&&r(n)&&await l(n)},beforeDelete:async(e,t)=>{if(e.tenantId!==i)return;let a=await n(e.adapters).get(e.tenantId,t);a&&r(a)&&s.set(t,a)},afterDelete:async(e,t)=>{if(e.tenantId!==i)return;let n=s.get(t);n&&(s.delete(t),await u(n.name))}}}function T(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 E=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})}),D=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 O(e){return e.metadata?.sync!==!1}function te(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>O(e)?r.resourceServers?r.resourceServers(e):!0:!1,s=e=>O(e)?r.roles?r.roles(e):!0:!1,c=i?w(e,E,o):void 0,l=a?w(e,D,s):void 0,u=i?T(e,E,o):void 0,d=a?T(e,D,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,n,r){return(await e.roles.list(n,{q:`name:${(0,t.escapeLuceneValue)(r)}`,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(`; `))}}}}function k(e){return e.var.data??e.env.data}async function ne(e){let{tenantId:t,parentTenantId:n,getTenant:i,getChildren:a}=e,o=e.maxDepth??2;if(!n)return;if(t&&n===t)throw new r.HTTPException(400,{message:`A tenant cannot be its own parent`});let s=new Set(t?[t]:[]),c=0,l=n;for(;l;){if(s.has(l))throw new r.HTTPException(400,{message:`Setting parent_tenant_id to '${n}' would create a cycle`});s.add(l);let e=await i(l);if(!e)throw new r.HTTPException(400,{message:`Parent tenant '${l}' not found`});if(c+=1,c>o)throw new r.HTTPException(400,{message:`Tenant tree is limited to ${o} levels above a tenant`});l=e.parent_tenant_id}if(t&&a){let e=new Set([t]),i=0,s=[t];for(;s.length>0;){let t=[];for(let n of s)for(let r of await a(n))e.has(r)||(e.add(r),t.push(r));if(t.length>0&&(i+=1,c+i>o))throw new r.HTTPException(400,{message:`Moving tenant under '${n}' would make its descendant '${t[0]}' exceed the tenant tree limit of ${o} levels`});s=t}}}var re=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 ie(e){let t=re.safeParse(e);return t.success?t.data:void 0}function ae(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 A(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(),total: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 k(n).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,total:e.totals?.length}):n.json({tenants:e.tenants})}let u=e.accessControl?.controlPlaneTenantId??k(n).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=>k(n).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,total: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:0,total:r}):n.json({tenants:[]});let m=p.map(e=>`id:${e}`).join(` OR `),h=s?`(${m}) AND (${s})`:m,g=await k(n).tenants.list({q:h,per_page:d,include_totals:!1});return o?n.json({tenants:g.tenants,start:f,limit:d,length:g.tenants.length,total:r}):n.json({tenants:g.tenants})}let d=await k(n).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,total:d.totals?.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:k(e),ctx:e};i.tenants?.beforeCreate&&(t=await i.tenants.beforeCreate(n,t)),await ne({tenantId:t.id,parentTenantId:t.parent_tenant_id,getTenant:t=>k(e).tenants.get(t)});let a=await k(e).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??k(n).multiTenancyConfig?.controlPlaneTenantId;if(o){let e=ie(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&&ae(e)&&(c=!0)}if(c||=(await(0,t.fetchAll)(t=>k(n).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 k(n).tenants.get(a))throw new r.HTTPException(404,{message:`Tenant not found`});let s={adapters:k(n),ctx:n};return i.tenants?.beforeDelete&&await i.tenants.beforeDelete(s,a),await k(n).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 k(e).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 k(e).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 k(e).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`})}}`parent_tenant_id`in i&&await ne({tenantId:e.var.tenant_id,parentTenantId:i.parent_tenant_id,getTenant:t=>k(e).tenants.get(t),getChildren:async n=>(await(0,t.fetchAll)(t=>k(e).tenants.list(t),`tenants`)).filter(e=>e.parent_tenant_id===n).map(e=>e.id)});let o=(0,t.deepMergePatch)(a,i);await k(e).tenants.update(e.var.tenant_id,o);let s=await k(e).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 oe(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 se(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 ce(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function j(){return async(e,t)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return t();let n=oe(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 se(k(e),i,n))throw new r.HTTPException(403,{message:`This ${ce(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}async function le(e){let{tenantId:t,getTenant:n,legacyControlPlane:i}=e,a=e.maxDepth??2,o=await n(t);if(!o?.parent_tenant_id)return i&&i!==t?[i]:[];let s=[],c=new Set([t]),l=o.parent_tenant_id;for(;l;){if(c.has(l))throw new r.HTTPException(400,{message:`Tenant chain for '${t}' contains a cycle at '${l}'`});if(c.add(l),s.length>=a)throw new r.HTTPException(400,{message:`Tenant chain for '${t}' is deeper than ${a}`});let e=await n(l);if(!e)break;s.push(l),l=e.parent_tenant_id}return s}function M(e){let t={};for(let n of e??[])n.value!==void 0&&(t[n.name]=n.value);return t}function ue(e,t){if(!e.inherit)return e;let n=t.find(t=>t.name===e.name&&t.is_system);if(!n)return e;let r={...M(n.secrets),...M(e.secrets)};return{...e,code:n.code,secrets:Object.entries(r).map(([e,t])=>({name:e,value:t}))}}function de(e,t){if(!t)return e;let n=new Set(e.hooks.map(e=>e.hook_id)),r=t.hooks.filter(e=>X(e)&&!n.has(e.hook_id));return{connections:e.connections.map(e=>q(e,t.connections)),resourceServers:e.resourceServers.map(e=>e.is_system?Y(e,t.resourceServers.find(t=>t.id===e.id)??null):e),hooks:[...e.hooks,...r],actions:e.actions.map(e=>ue(e,t.actions)),emailProvider:e.emailProvider??t.emailProvider,branding:e.branding,promptSettings:e.promptSettings}}var fe=()=>({connections:[],resourceServers:[],hooks:[],actions:[],emailProvider:null,branding:null,promptSettings:null});function N(e,t){if(t.scope)return t.scope;switch(e){case`connection`:case`emailProvider`:return`shared`;case`resourceServer`:case`action`:return t.is_system?`shared`:`local`;case`hook`:return X(t)?`shared`:`local`;default:return`local`}}function P(e){return e.override??`fields`}var pe=/secret|password|private_key|api_key|token/i;function me(e,t){let n={...e??{}};for(let[e,r]of Object.entries(t??{}))pe.test(e)&&(n[e]=r);return n}function F(e,t){switch(P(e)){case`none`:return{...e,id:t.id};case`secrets`:return{...e,id:t.id,options:me(e.options,t.options)};default:return{...e,...t,options:{...e.options??{},...t.options??{}}}}}function he(e,t){switch(P(e)){case`none`:return{...e,id:t.id};case`secrets`:return{...e,id:t.id,signing_secret:t.signing_secret??e.signing_secret};default:return{...t,scopes:je(t.scopes,e.scopes)}}}function I(e){return new Map((e??[]).map(e=>[e.name,e]))}function ge(e,t){let n=P(e);if(n===`none`)return{...e,id:t.id};let r=I(e.secrets);if(n===`secrets`||n===`fields`)for(let[e,n]of I(t.secrets))r.set(e,n);return{...n===`fields`&&!t.inherit?t:e,id:t.id,secrets:[...r.values()]}}function _e(e,t){let n=new Set,r=[...e].reverse().concat(t),i=(e,t,r,i)=>r?t:t.filter(t=>{let r=N(e,t);return r===`local`?!1:(r===`platform`&&n.add(`${e}:${i(t)}`),!0)}),a=fe(),o=e=>`${e.strategy}:${e.name}`,s=e=>e.identifier,c=e=>e.hook_id??``,l=e=>e.name,u=new Map,d=[],f=new Map,p=new Map,m=new Map;r.forEach((e,t)=>{let h=t===r.length-1;for(let t of i(`connection`,e.connections,h,o)){let e=u.get(t.strategy);h?d.push(e?F(e,t):t):u.set(t.strategy,e?F(e,t):t)}for(let t of i(`resourceServer`,e.resourceServers,h,s)){let e=f.get(s(t));f.set(s(t),e?he(e,t):t)}for(let t of i(`hook`,e.hooks,h,c))p.set(c(t),t);for(let t of i(`action`,e.actions,h,l)){let e=m.get(l(t));m.set(l(t),e?ge(e,t):t)}for(let t of[`emailProvider`,`branding`,`promptSettings`]){let r=e[t];r&&(h||N(t,r)!==`local`)&&(!h&&N(t,r)===`platform`&&n.add(`${t}:singleton`),a[t]=r)}});let h=new Set(r[r.length-1].connections.map(e=>e.strategy));return a.connections=[...d,...[...u.values()].filter(e=>!h.has(e.strategy))],a.resourceServers=[...f.values()],a.hooks=[...p.values()],a.actions=[...m.values()],{...a,hidden:[...n]}}function L(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 R(){return{upserted:0,errors:[]}}function ve(e){return{tenantId:e,connections:R(),resourceServers:R(),hooks:R(),emailProvider:R(),branding:R(),promptSettings:R()}}function z(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function B(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 V(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 H(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await B(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 B(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)!z(i)||!i.hook_id||await B(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 B(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 B(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await B(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function U(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=L(a),c=await V(await r(),n,s),l=await i(t),u=ve(t);return await H(c,l,n,s,o,u),u}async function W(e,n){let r=await V(e,n,{connections:!0,resourceServers:!0,hooks:!0,emailProvider:!0,branding:!0,promptSettings:!0}),i=await(0,t.fetchAll)(t=>e.actions.list(n,t),`actions`,{cursorField:`id`,pageSize:100});return{...r,actions:i}}var ye=/secret|password|private_key|api_key|token/i,be=new Set([`id`,`tenant_id`,`created_at`,`updated_at`,`scope`,`override`,`enforce`,`enabled_clients`]);async function G(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return[...new Uint8Array(t)].map(e=>e.toString(16).padStart(2,`0`)).join(``).slice(0,16)}async function K(e,t=``){if(Array.isArray(e)){if(t===`secrets`){let t={};for(let n of e)t[n.name]=n.value===void 0?null:`sha256:${await G(n.value)}`;return t}return Promise.all(e.map(e=>K(e,t)))}if(e&&typeof e==`object`){let t={};for(let n of Object.keys(e).sort()){let r=e[n];r!=null&&(t[n]=typeof r==`string`&&ye.test(n)?`sha256:${await G(r)}`:await K(r,n))}return t}return e}async function xe(e){let t={};for(let[n,r]of Object.entries(e))be.has(n)||(t[n]=r);return await K(t)}var Se={connection:e=>`${e.strategy}:${e.name}`,resourceServer:e=>e.identifier,hook:e=>e.hook_id,action:e=>e.name},Ce=new Set([`connection`,`resourceServer`,`action`,`emailProvider`,`branding`,`promptSettings`]);async function we(e){let t=new Map,n=async(e,n,r)=>{let i=t.get(e)??new Map;i.set(n,await xe(r)),t.set(e,i)};for(let[t,r]of Object.entries(Se)){let i=e[{connection:`connections`,resourceServer:`resourceServers`,hook:`hooks`,action:`actions`}[t]];for(let e of i)await n(t,r(e),e)}for(let t of[`emailProvider`,`branding`,`promptSettings`])e[t]&&await n(t,`singleton`,e[t]);return t}async function Te(e,t){let[n,r]=await Promise.all([we(e),we(t)]),i=[],a=new Set([...n.keys(),...r.keys()]);for(let e of a){let t=n.get(e)??new Map,a=r.get(e)??new Map;for(let n of new Set([...t.keys(),...a.keys()])){let r=t.get(n),o=a.get(n);if(r&&!o)i.push({entity:e,key:n,kind:`missing`,fields:[],expected:!1});else if(!r&&o)i.push({entity:e,key:n,kind:`extra`,fields:[],expected:Ce.has(e)});else if(r&&o){let t=JSON.stringify(r),a=JSON.stringify(o);if(t===a)continue;let s=[...new Set([...Object.keys(r),...Object.keys(o)])].filter(e=>JSON.stringify(r[e])!==JSON.stringify(o[e])).sort();i.push({entity:e,key:n,kind:`changed`,fields:s,expected:!1,legacy_hash:await G(t),new_hash:await G(a)})}}}return i}async function Ee(e){let{adapters:t,tenantId:n,legacyControlPlane:r}=e,i=await le({tenantId:n,getTenant:e=>t.tenants.get(e),legacyControlPlane:r,maxDepth:e.maxDepth}),a=await W(t,n),o=await Promise.all(i.map(e=>W(t,e))),s=r&&r!==n?await W(t,r):void 0,{hidden:c,...l}=_e(o,a),u=new Set(c);return(await Te(de(a,s),l)).filter(e=>!u.has(`${e.entity}:${e.key}`))}var De=3600*1e3,Oe=1e4;function ke(e,t){let n=t.sample??1,r=t.intervalMs??6e4,i=new Map,a=new Set,o=new Map;async function s(n,r){let i=await Ee({adapters:e,tenantId:n,legacyControlPlane:r}),a=Date.now();o.size>Oe&&o.clear();for(let s of i){if(s.expected&&!t.includeExpected)continue;let i=await G([n,s.entity,s.key,s.kind,s.fields.join(`,`)].join(`|`)),c=o.get(i);c!==void 0&&a-c<De||(o.set(i,a),await Ae(e,n,s,r))}}return{schedule(e,t){if(a.has(e)||n<1&&Math.random()>=n)return;let o=Date.now(),c=i.get(e);c!==void 0&&o-c<r||(i.set(e,o),a.add(e),s(e,t).catch(()=>{}).finally(()=>a.delete(e)))}}}async function Ae(e,n,r,i){await e.logs.create(n,{type:t.LogTypes.CONFIG_INHERITANCE_DIFF,date:new Date().toISOString(),isMobile:!1,description:`${r.kind} ${r.entity} ${r.key}`,details:{shadow:`config-inheritance`,legacy_control_plane:i,...r}})}function q(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 J(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function je(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 Y(e,t){return t?{...e,scopes:je(e.scopes,t.scopes)}:e}function Me(e,t){return t?{...e,callbacks:J(e.callbacks,t.callbacks),web_origins:J(e.web_origins,t.web_origins),allowed_logout_urls:J(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:J(e.allowed_origins,t.allowed_origins)}:e}function Ne(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 Pe(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:Y(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?Y(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function Fe(e,t){let n=Ne({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:Pe(e,n)}}function Ie(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i,inheritanceShadow:a}=t,o=Ne({controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i}),s=a?ke(e,a===!0?{}:a):void 0,c=s?async e=>{let t=await o(e);return s.schedule(e,t?.tenantId),t}:o;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 c(t);return!i||t===i.tenantId?r:q(r,(await e.connections.list(i.tenantId)).connections||[])},list:async(t,n)=>{let r=await e.connections.list(t,n),i=await c(t);if(!i||t===i.tenantId)return r;let a=await e.connections.list(i.tenantId),o=r.connections.map(e=>q(e,a.connections||[]));return{...r,connections:o}}},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 c(t);if(!i||t===i.tenantId)return r;let a=await e.connections.list(i.tenantId);return r.map(e=>q(e,a.connections||[]))}},emailProviders:{...e.emailProviders,get:async t=>{let n=await e.emailProviders.get(t);if(n)return n;let r=await c(t);return!r||t===r.tenantId?null:e.emailProviders.get(r.tenantId)}},resourceServers:Pe(e,c),hooks:Le(e,c)}}function X(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function Le(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(X);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&&X(o)?o:null}}}function Z(e,t){return Ie(e,t)}function Re(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 ze(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 Be(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 k(t).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 Ve(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.set(`baseData`,n),t.env={...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 Q(e){let t=Be(e),n=ze(e),r=Ve(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}function He(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,inheritanceShadow:s,sync:c={resourceServers:!0,roles:!0},defaultPermissions:l=[`tenant:admin`],requireOrganizationMatch:u=!1,managementApiExtensions:d=[],entityHooks:f,getChildTenantIds:p,getAdapters:m,...g}=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 v=n,y=n;r&&(v=Z(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o,inheritanceShadow:s}),y={...Fe(n,{controlPlaneTenantId:i,resolveControlPlane:o}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}});let b=g.tenantOperationExecutor;if(!b&&n.tenantOperations&&n.tenantOperationEvents&&g.tenantUpgrade){let e={tenantOperations:n.tenantOperations,tenantOperationEvents:n.tenantOperationEvents},t=g.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)}}]}});b={engine:r.engine,enqueue:t=>_(e,r,{...t,tenant_id:t.tenant_id})}}let S=c!==!1,ee=S?{resourceServers:c.resourceServers??!0,roles:c.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:C,tenantHooks:w}=te({controlPlaneTenantId:i,getChildTenantIds:p??(async()=>(await(0,t.fetchAll)(e=>v.tenants.list(e),`tenants`,{cursorField:`id`,pageSize:100})).filter(e=>e.id!==i).map(e=>e.id)),getAdapters:m??(async()=>v),getControlPlaneAdapters:async()=>v,sync:ee}),T={resourceServers:[C.resourceServers,...f?.resourceServers??[]],roles:[C.roles,...f?.roles??[]],connections:f?.connections??[],tenants:f?.tenants??[],rolePermissions:f?.rolePermissions??[]},E=x({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:u,defaultPermissions:l}}),D=A({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:u,defaultPermissions:l}},{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:v,managementDataAdapter:y,...g,tenantOperationExecutor:b,entityHooks:T,managementApiExtensions:[...d,{path:`/tenants`,router:D}],managementApiMiddleware:[...g.managementApiMiddleware??[],...S?[j()]:[]]});return{app:O,controlPlaneTenantId:i}}function Ue(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function We(e,n,r={},i){let a=L(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await V(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(Ue):[],u=s?await Ge(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(z),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function Ge(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 Ke(e,n,r){let i=R();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 B(i,`signing_key ${t.kid}`,r,async()=>{let e=Ue(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function qe(e,t,n){let r=R();for(let i of e)await B(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 Je(e,n,r,i={}){let a=i.continueOnError??!1,o=L(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 qe(e.tenants??[],n,a):R(),d=ve(r);await H(l,n,r,o,a,d);let f=s?await Ke(e.signingKeys,n,a):R();return{...d,signingKeys:f,tenants:u}}function Ye(e){return{syncDefaults:t=>U(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await U(e,r));return n}}}function Xe(e){let t=$(e);return{name:`multi-tenancy`,middleware:Q(e),hooks:t,routes:[{path:`/management`,handler:A(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 Ze(t){let n=new e.Hono,r=$(t);return n.route(`/tenants`,A(t,r)),n}function Qe(e){return{hooks:$(e),middleware:Q(e),app:Ze(e),config:e,wrapAdapters:(t,n)=>Z(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.applyControlPlaneDefaultsPayload=Je,exports.buildControlPlaneDefaultsPayload=We,exports.buildEngineInstanceId=l,exports.compareShadow=Ee,exports.computeLegacyConfig=de,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=ze,exports.createControlPlaneTenantMiddleware=Re,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=Ve,exports.createDirectRolloutAdapter=Ye,exports.createInlineExecutor=h,exports.createMultiTenancy=Ze,exports.createMultiTenancyHooks=$,exports.createMultiTenancyMiddleware=Q,exports.createMultiTenancyPlugin=Xe,exports.createOperationRecorder=f,exports.createProtectSyncedMiddleware=j,exports.createProvisioningHooks=x,exports.createRuntimeFallbackAdapter=Ie,exports.createShadowReporter=ke,exports.createSubdomainMiddleware=Be,exports.createSyncHooks=te,exports.createTenantsOpenAPIRouter=A,exports.diffConfig=Te,exports.effectiveOverride=P,exports.effectiveScope=N,exports.enqueueTenantOperation=_,exports.errorToMessage=d,exports.initMultiTenant=He,exports.inlineStepRunner=m,exports.isTerminalStatus=p,exports.mergeClientWithFallback=Me,exports.mergeConfig=_e,exports.projectControlPlaneDefaults=U,exports.readConfigRows=W,exports.resolveTenantChain=le,exports.runRecordedTenantOperation=y,exports.setupMultiTenancy=Qe,exports.validateTenantAccess=a,exports.withRuntimeFallback=Z,exports.withSystemResourceServerInheritance=Fe;
|