@authhero/multi-tenancy 15.2.0 → 15.4.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.
Files changed (74) hide show
  1. package/dist/multi-tenancy.cjs +1 -1
  2. package/dist/multi-tenancy.mjs +2968 -1176
  3. package/dist/types/index.d.ts +5 -2
  4. package/dist/types/index.d.ts.map +1 -1
  5. package/dist/types/inheritance/legacy.d.ts.map +1 -1
  6. package/dist/types/inheritance/merge.d.ts +1 -0
  7. package/dist/types/inheritance/merge.d.ts.map +1 -1
  8. package/dist/types/inheritance/read.d.ts.map +1 -1
  9. package/dist/types/inheritance/report.d.ts +6 -2
  10. package/dist/types/inheritance/report.d.ts.map +1 -1
  11. package/dist/types/inheritance/types.d.ts +3 -1
  12. package/dist/types/inheritance/types.d.ts.map +1 -1
  13. package/dist/types/init.d.ts +84 -1
  14. package/dist/types/init.d.ts.map +1 -1
  15. package/dist/types/middleware/config-sync-mode.d.ts +39 -0
  16. package/dist/types/middleware/config-sync-mode.d.ts.map +1 -0
  17. package/dist/types/middleware/index.d.ts +3 -1
  18. package/dist/types/middleware/index.d.ts.map +1 -1
  19. package/dist/types/middleware/protect-synced.d.ts +1 -1
  20. package/dist/types/middleware/protect-synced.d.ts.map +1 -1
  21. package/dist/types/middleware/settings-inheritance.d.ts +20 -2
  22. package/dist/types/middleware/settings-inheritance.d.ts.map +1 -1
  23. package/dist/types/operations/detach.d.ts +85 -0
  24. package/dist/types/operations/detach.d.ts.map +1 -0
  25. package/dist/types/operations/enqueue.d.ts +8 -1
  26. package/dist/types/operations/enqueue.d.ts.map +1 -1
  27. package/dist/types/operations/index.d.ts +7 -1
  28. package/dist/types/operations/index.d.ts.map +1 -1
  29. package/dist/types/operations/recorder.d.ts +2 -0
  30. package/dist/types/operations/recorder.d.ts.map +1 -1
  31. package/dist/types/operations/sync-defaults.d.ts +58 -0
  32. package/dist/types/operations/sync-defaults.d.ts.map +1 -0
  33. package/dist/types/operations/tenant-members-request.d.ts +97 -0
  34. package/dist/types/operations/tenant-members-request.d.ts.map +1 -0
  35. package/dist/types/operations/types.d.ts +2 -0
  36. package/dist/types/operations/types.d.ts.map +1 -1
  37. package/dist/types/rollout/index.d.ts +2 -0
  38. package/dist/types/rollout/index.d.ts.map +1 -1
  39. package/dist/types/rollout/payload.d.ts +15 -0
  40. package/dist/types/rollout/payload.d.ts.map +1 -1
  41. package/dist/types/rollout/resolved-sync.d.ts +112 -0
  42. package/dist/types/rollout/resolved-sync.d.ts.map +1 -0
  43. package/dist/types/rollouts/advance.d.ts +44 -0
  44. package/dist/types/rollouts/advance.d.ts.map +1 -0
  45. package/dist/types/rollouts/config.d.ts +54 -0
  46. package/dist/types/rollouts/config.d.ts.map +1 -0
  47. package/dist/types/rollouts/controller.d.ts +29 -0
  48. package/dist/types/rollouts/controller.d.ts.map +1 -0
  49. package/dist/types/rollouts/enumerate.d.ts +25 -0
  50. package/dist/types/rollouts/enumerate.d.ts.map +1 -0
  51. package/dist/types/rollouts/hashes.d.ts +10 -0
  52. package/dist/types/rollouts/hashes.d.ts.map +1 -0
  53. package/dist/types/rollouts/index.d.ts +21 -0
  54. package/dist/types/rollouts/index.d.ts.map +1 -0
  55. package/dist/types/rollouts/plan.d.ts +29 -0
  56. package/dist/types/rollouts/plan.d.ts.map +1 -0
  57. package/dist/types/rollouts/reconcile.d.ts +38 -0
  58. package/dist/types/rollouts/reconcile.d.ts.map +1 -0
  59. package/dist/types/rollouts/status.d.ts +28 -0
  60. package/dist/types/rollouts/status.d.ts.map +1 -0
  61. package/dist/types/rollouts/trigger.d.ts +52 -0
  62. package/dist/types/rollouts/trigger.d.ts.map +1 -0
  63. package/dist/types/rollouts/types.d.ts +25 -0
  64. package/dist/types/rollouts/types.d.ts.map +1 -0
  65. package/dist/types/rollouts/verify.d.ts +50 -0
  66. package/dist/types/rollouts/verify.d.ts.map +1 -0
  67. package/dist/types/routes/tenants.d.ts.map +1 -1
  68. package/dist/types/types.d.ts +20 -0
  69. package/dist/types/types.d.ts.map +1 -1
  70. package/dist/types/utils/tenant-settings.d.ts +13 -0
  71. package/dist/types/utils/tenant-settings.d.ts.map +1 -0
  72. package/dist/types/utils/tenant-tree.d.ts +2 -1
  73. package/dist/types/utils/tenant-tree.d.ts.map +1 -1
  74. package/package.json +5 -5
@@ -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 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;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("hono"),t=require("authhero"),n=require("hono/http-exception"),r=require("@hono/zod-openapi"),i=require("@authhero/adapter-interfaces");function a(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 o(e,t,n,r){if(t===n)return!0;let i=r||e;return i?i.toLowerCase()===t.toLowerCase():!1}function s(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 c=64;function l(e){return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}function u(e){let t=l(e.id),n=Math.max(0,c-(5+t.length)),r=l(e.kind).slice(0,n),i=3+r.length+2+t.length,a=Math.max(0,c-i);return`op-${r}-${l(e.tenant_id??`fleet`).slice(0,a)}-${t}`.slice(0,c)}var d=2048;function f(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,d)}function p(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 setResult(e,n){await t.update(e,{result:n})},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:f(n),finished_at:new Date().toISOString()})}}}function m(e){return e===`succeeded`||e===`failed`||e===`cancelled`}var h={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 g(e){let t=p(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:h});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:f(r)}}),await t.markFailed(n.id,r),r}}await t.markSucceeded(n.id)}}}async function _(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,input:t.input}),i=u(r);try{await e.tenantOperations.update(r.id,{engine_instance_id:i})}catch(t){try{await p(e).markFailed(r.id,t)}catch{}throw t}return{...r,engine_instance_id:i}}async function v(e,t,n,r={}){let i=p(e),a=await _(e,n,t.engine);try{await t.start(a)}catch(t){let n=null;try{let r=await e.tenantOperations.get(a.id);r&&!m(r.status)&&await i.markFailed(a.id,t),n=await e.tenantOperations.get(a.id)}catch(e){console.warn(`Failed to record tenant operation failure:`,e)}if(r.returnFailed&&n)return n;throw t}try{return await e.tenantOperations.get(a.id)??a}catch(e){return console.warn(`Failed to re-fetch tenant operation after start:`,e),a}}async function y(e){let{tenantId:t,parentTenantId:r,getTenant:i,getChildren:a}=e,o=e.maxDepth??2;if(!r)return;if(t&&r===t)throw new n.HTTPException(400,{message:`A tenant cannot be its own parent`});let s=new Set(t?[t]:[]),c=0,l=r;for(;l;){if(s.has(l))throw new n.HTTPException(400,{message:`Setting parent_tenant_id to '${r}' would create a cycle`});s.add(l);let e=await i(l);if(!e)throw new n.HTTPException(400,{message:`Parent tenant '${l}' not found`});if(c+=1,c>o)throw new n.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 n.HTTPException(400,{message:`Moving tenant under '${r}' would make its descendant '${t[0]}' exceed the tenant tree limit of ${o} levels`});s=t}}}async function b(e){let{tenantId:t,getTenant:r,legacyControlPlane:i}=e,a=e.maxDepth??2,o=await r(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 n.HTTPException(400,{message:`Tenant chain for '${t}' contains a cycle at '${l}'`});if(c.add(l),s.length>=a)throw new n.HTTPException(400,{message:`Tenant chain for '${t}' is deeper than ${a}`});let e=await r(l);if(!e)break;s.push(l),l=e.parent_tenant_id}return s}function x(e){let t={};for(let n of e??[])n.value!==void 0&&(t[n.name]=n.value);return t}function S(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={...x(n.secrets),...x(e.secrets)};return{...e,code:n.code,secrets:Object.entries(r).map(([e,t])=>({name:e,value:t}))}}function C(e,t){if(!t)return e;let n=new Set(e.hooks.map(e=>e.hook_id)),r=t.hooks.filter(e=>F(e)&&!n.has(e.hook_id));return{connections:e.connections.map(e=>pe(e,t.connections)),resourceServers:e.resourceServers.map(e=>e.is_system?ge(e,t.resourceServers.find(t=>t.id===e.id)??null):e),hooks:[...e.hooks,...r],hookCode:e.hookCode,actions:e.actions.map(e=>S(e,t.actions)),emailProvider:e.emailProvider??t.emailProvider,branding:e.branding,promptSettings:e.promptSettings}}function w(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 T(){return{upserted:0,errors:[]}}function E(e){return{tenantId:e,connections:T(),resourceServers:T(),hooks:T(),emailProvider:T(),branding:T(),promptSettings:T()}}function ee(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function D(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 O(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 k(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await D(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 D(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)!ee(i)||!i.hook_id||await D(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 D(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 D(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await D(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function A(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=w(a),c=await O(await r(),n,s),l=await i(t),u=E(t);return await k(c,l,n,s,o,u),u}async function j(e,n){let r=await O(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}),a=new Set(i.map(e=>e.id)),o=new Set;for(let e of r.hooks){let t=e.code_id;t&&!a.has(t)&&o.add(t)}let s=[];for(let t of o){let r=await e.hookCode.get(n,t);r&&s.push(r)}return{...r,actions:i,hookCode:s}}var te=/secret|password|private_key|api_key|token/i,ne=new Set([`id`,`tenant_id`,`created_at`,`updated_at`,`scope`,`override`,`enforce`,`enabled_clients`]);async function M(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 N(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 M(n.value)}`;return t}return Promise.all(e.map(e=>N(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`&&te.test(n)?`sha256:${await M(r)}`:await N(r,n))}return t}return e}async function re(e){let t={};for(let[n,r]of Object.entries(e))ne.has(n)||(t[n]=r);return await N(t)}var P={connection:e=>`${e.strategy}:${e.name}`,resourceServer:e=>e.identifier,hook:e=>e.hook_id,action:e=>e.name},ie=new Set([`connection`,`resourceServer`,`action`,`emailProvider`,`branding`,`promptSettings`]);async function ae(e){let t=new Map,n=async(e,n,r)=>{let i=t.get(e)??new Map;i.set(n,await re(r)),t.set(e,i)};for(let[t,r]of Object.entries(P)){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 oe(e,t){let[n,r]=await Promise.all([ae(e),ae(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:ie.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 M(t),new_hash:await M(a)})}}}return i}async function se(e){let{adapters:t,tenantId:n,legacyControlPlane:r}=e,i=await b({tenantId:n,getTenant:e=>t.tenants.get(e),legacyControlPlane:r,maxDepth:e.maxDepth}),a=await j(t,n),o=await Promise.all(i.map(e=>j(t,e))),s=r&&r!==n?await j(t,r):void 0,{hidden:c,...l}=Me(o,a),u=new Set(c);return(await oe(C(a,s),l)).filter(e=>!u.has(`${e.entity}:${e.key}`))}var ce=3600*1e3,le=1e4;function ue(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 se({adapters:e,tenantId:n,legacyControlPlane:r}),a=Date.now();o.size>le&&o.clear();for(let s of i){if(s.expected&&!t.includeExpected)continue;let i=await M([n,s.entity,s.key,s.kind,s.fields.join(`,`)].join(`|`)),c=o.get(i);c!==void 0&&a-c<ce||(o.set(i,a),await de(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);if(!(c!==void 0&&o-c<r))return i.set(e,o),a.add(e),s(e,t).catch(()=>{}).finally(()=>a.delete(e))}}}async function de(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 fe(e){let{base:t,getTenant:n,controlPlaneTenantId:r}=e,i=e.ttlMs??1e4,a=e.maxEntries??1e3,o=new Map;async function s(e){if(e===r)return!1;let t=o.get(e),s=Date.now();if(t&&t.expires>s)return t.synced;try{let t=await n(e),r=t?.config_sync===`synced`||t?.config_sync===`detached`;return o.size>=a&&o.clear(),o.set(e,{synced:r,expires:s+i}),r}catch{return!1}}return{isSynced:s,invalidate(e){e?o.delete(e):o.clear()},async resolve({tenant_id:e}){let n=await t(e);return!n||n.tenantId===e?n:await s(e)?void 0:n}}}function pe(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 me(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function he(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 ge(e,t){return t?{...e,scopes:he(e.scopes,t.scopes)}:e}function _e(e,t){return t?{...e,callbacks:me(e.callbacks,t.callbacks),web_origins:me(e.web_origins,t.web_origins),allowed_logout_urls:me(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:me(e.allowed_origins,t.allowed_origins)}:e}function ve(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 ye(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:ge(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?ge(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function be(e,t){let n=ve({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:ye(e,n)}}function xe(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i,inheritanceShadow:a}=t,o=t.configSync??fe({base:ve({controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i}),getTenant:async t=>await e.tenants.get(t)??null,controlPlaneTenantId:n}),s=e=>o.resolve({tenant_id:e}),c=a?ue(e,a===!0?{}:a):void 0,l=c?async e=>{let t=await s(e);return await o.isSynced(e)||c.schedule(e,t?.tenantId),t}:s;return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:o.resolve},connections:{...e.connections,get:async(t,n)=>{let r=await e.connections.get(t,n);if(!r)return r;let i=await l(t);return!i||t===i.tenantId?r:pe(r,(await e.connections.list(i.tenantId)).connections||[])},list:async(t,n)=>{let r=await e.connections.list(t,n),i=await l(t);if(!i||t===i.tenantId)return r;let a=await e.connections.list(i.tenantId),o=r.connections.map(e=>pe(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 l(t);if(!i||t===i.tenantId)return r;let a=await e.connections.list(i.tenantId);return r.map(e=>pe(e,a.connections||[]))}},emailProviders:{...e.emailProviders,get:async t=>{let n=await e.emailProviders.get(t);if(n)return n;let r=await l(t);return!r||t===r.tenantId?null:e.emailProviders.get(r.tenantId)}},resourceServers:ye(e,l),hooks:Se(e,l)}}function F(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function Se(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(F);if(o.length===0)return i;let s=new Set((i.hooks||[]).map(e=>e.hook_id)),c=[];for(let e of o)s.has(e.hook_id)||e.hook_id&&s.has(await L(`hook`,n,e.hook_id))||c.push(e);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&&F(o)?o:null}}}function Ce(e,t){return xe(e,t)}var we=()=>({connections:[],resourceServers:[],hooks:[],hookCode:[],actions:[],emailProvider:null,branding:null,promptSettings:null});function I(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 F(t)?`shared`:`local`;default:return`local`}}function Te(e){return e.override??`fields`}var Ee=/secret|password|private_key|api_key|token/i;function De(e,t){let n={...e??{}};for(let[e,r]of Object.entries(t??{}))Ee.test(e)&&(n[e]=r);return n}function Oe(e,t){switch(Te(e)){case`none`:return{...e,id:t.id};case`secrets`:return{...e,id:t.id,options:De(e.options,t.options)};default:return{...e,...t,options:{...e.options??{},...t.options??{}}}}}function ke(e,t){switch(Te(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:he(t.scopes,e.scopes)}}}function Ae(e){return new Map((e??[]).map(e=>[e.name,e]))}function je(e,t){let n=Te(e);if(n===`none`)return{...e,id:t.id};let r=Ae(e.secrets);if(n===`secrets`||n===`fields`)for(let[e,n]of Ae(t.secrets))r.set(e,n);return{...n===`fields`&&!t.inherit?t:e,id:t.id,secrets:[...r.values()]}}function Me(e,t){let n=new Set,r=[...e].reverse().concat(t),i=(e,t,r,i)=>r?t:t.filter(t=>{let r=I(e,t);return r===`local`?!1:(r===`platform`&&n.add(`${e}:${i(t)}`),!0)}),a=we(),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?Oe(e,t):t):u.set(t.strategy,e?Oe(e,t):t)}for(let t of i(`resourceServer`,e.resourceServers,h,s)){let e=f.get(s(t));f.set(s(t),e?ke(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?je(e,t):t)}for(let t of[`emailProvider`,`branding`,`promptSettings`]){let r=e[t];r&&(h||I(t,r)!==`local`)&&(!h&&I(t,r)===`platform`&&n.add(`${t}:singleton`),a[t]=r)}});let h=new Set(r[r.length-1].connections.map(e=>e.strategy));a.connections=[...d,...[...u.values()].filter(e=>!h.has(e.strategy))],a.resourceServers=[...f.values()],a.hooks=[...p.values()];let g=new Set(a.hooks.map(e=>e.code_id).filter(e=>!!e)),_=new Map;for(let e of[...r].reverse())for(let t of e.hookCode)g.has(t.id)&&!_.has(t.id)&&_.set(t.id,t);return a.hookCode=[..._.values()],a.actions=[...m.values()],{...a,hidden:[...n]}}var Ne=[`connection`,`resourceServer`,`hookCode`,`action`,`hook`];function Pe(e){return Array.isArray(e)?`[${e.map(Pe).join(`,`)}]`:e&&typeof e==`object`?`{${Object.entries(e).filter(([,e])=>e!==void 0).sort(([e],[t])=>e<t?-1:1).map(([e,t])=>`${JSON.stringify(e)}:${Pe(t)}`).join(`,`)}}`:JSON.stringify(e)??`null`}async function Fe(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(``)}var Ie={connection:`con_`,resourceServer:`api_`,hook:`h_`,hookCode:`hc_`,action:`act_`};async function L(e,t,n){let r=await Fe(`${t}|${e}|${n}`);return`${Ie[e]}sy${r.slice(0,15)}`}function R(e,t){let n=t;switch(e){case`connection`:return`${n.strategy}:${n.name}`;case`resourceServer`:return n.identifier;case`action`:return n.name;case`hookCode`:return n.id;case`hook`:return n.hook_id}}async function Le(e,t,n={}){let r=await b({tenantId:t,getTenant:t=>e.tenants.get(t),legacyControlPlane:n.legacyControlPlane,maxDepth:n.maxDepth}),i=Me(await Promise.all(r.map(t=>j(e,t))),we()),a={version:1,chain:r,connections:i.connections,resourceServers:i.resourceServers,hookCode:i.hookCode,actions:i.actions,hooks:i.hooks,emailProvider:i.emailProvider,branding:i.branding,promptSettings:i.promptSettings,hidden:i.hidden,deletes:n.deletes??[]};return{...a,hash:await Fe(Pe(a))}}function Re(e,t){if(typeof e==`string`)e.startsWith(`enc:v1:`)&&t.add(e);else if(Array.isArray(e))for(let n of e)Re(n,t);else if(e&&typeof e==`object`)for(let n of Object.values(e))Re(n,t)}function ze(e){let t=e.slice(7),n=t.indexOf(`:`);return n===-1?`default`:t.slice(0,n)}async function Be(e,n){let r=new Set;Re(e,r);let i=new Set;for(let e of r)await(0,t.canDecrypt)(e,n)||i.add(ze(e));return[...i].sort()}var z=()=>({added:0,changed:0,unchanged:0,deleted:0,errors:[]}),B=e=>Pe(e);async function Ve(e,n,r,i={}){let{dryRun:a=!1,continueOnError:o=!0}=i;if(i.prune&&e.chain.length===0)throw Error(`Cannot prune '${r}': the block resolved no ancestors, so every synced copy would look stale. Nothing was written.`);let s={status:a?`dry-run`:`applied`,hash:e.hash,entities:{connection:z(),resourceServer:z(),hookCode:z(),action:z(),hook:z(),emailProvider:z(),branding:z(),promptSettings:z()},changes:[],rows:[]},c=await n.tenants.get(r),l=!!i.deletes&&e.deletes.length>0;if(!a&&!i.force&&!l&&!i.prune&&c?.config_sync_hash===e.hash)return{...s,status:`up-to-date`};if(i.keyRing){let t=await Be(e,i.keyRing);if(t.length>0)throw Error(`Cannot sync config to '${r}': its key ring cannot decrypt key id(s) ${t.map(e=>`"${e}"`).join(`, `)} carried by the payload. Nothing was written.`)}let u=await j(n,r),d=(a||i.prune)&&e.chain.length>0?u:null,f={connection:new Set,resourceServer:new Set,action:new Set};for(let e of u.connections)(0,t.isSyncedRowId)(e.id)||f.connection.add(R(`connection`,e));for(let e of u.resourceServers)(0,t.isSyncedRowId)(e.id)||f.resourceServer.add(R(`resourceServer`,e));for(let e of u.actions)(0,t.isSyncedRowId)(e.id)||f.action.add(R(`action`,e));let p=async(e,t,n)=>{let r=s.entities[e];try{let i=await n();r[i]+=1,i!==`unchanged`&&(s.changes.push(`${e}:${t}`),s.rows.push({entity:e,key:t,action:i}))}catch(n){let i=`${e} ${t}: ${n instanceof Error?n.message:String(n)}`;if(!o)throw Error(i,{cause:n});r.errors.push(i)}},m=async e=>e.existing?B(e.view(e.existing))===B(e.view(e.desired))?`unchanged`:(a||await e.update(),`changed`):(a||await e.create(),`added`),h=(e,t)=>L(e,r,t),g=new Map;for(let t of e.hookCode)g.set(t.id,await h(`hookCode`,R(`hookCode`,t)));for(let t of e.actions)g.set(t.id,await h(`action`,R(`action`,t)));let _,v=async e=>{if(!_){_=[];let e=await(0,t.fetchAll)(e=>n.clients.list(r,e),`clients`,{cursorField:`client_id`,pageSize:100});for(let t of e)(await n.clientConnections.listByClient(r,t.client_id)).length>0&&_.push(t.client_id)}for(let t of _)await n.clientConnections.addClientToConnection(r,e,t)},y=(e,t)=>f[e].has(t)?(s.changes.push(`skip ${e}:${t} (the tenant has its own)`),s.rows.push({entity:e,key:t,action:`skipped`}),!0):!1;for(let i of e.connections){let e=R(`connection`,i),a=await h(`connection`,e);await p(`connection`,e,async()=>{if(y(`connection`,e))return`unchanged`;let{enabled_clients:o,...s}=i,c=t.connectionInsertSchema.parse({...s,id:a}),l=await n.connections.get(r,a);return m({existing:l?t.connectionInsertSchema.parse(l):null,desired:c,create:async()=>{await n.connections.create(r,c);try{await v(a)}catch(e){throw await n.connections.remove(r,a).catch(()=>{}),e}},update:()=>n.connections.update(r,a,c),view:e=>e})})}for(let i of e.resourceServers){let e=R(`resourceServer`,i),a=await h(`resourceServer`,e);await p(`resourceServer`,e,async()=>{if(y(`resourceServer`,e))return`unchanged`;let o=t.resourceServerInsertSchema.parse({...i,id:a}),s=await n.resourceServers.get(r,a);return m({existing:s?t.resourceServerInsertSchema.parse(s):null,desired:o,create:()=>n.resourceServers.create(r,o),update:()=>n.resourceServers.update(r,a,o),view:e=>e})})}for(let i of e.hookCode){let e=R(`hookCode`,i),a=g.get(i.id);await p(`hookCode`,e,async()=>{let e=t.hookCodeInsertSchema.parse(i),o=await n.hookCode.get(r,a);return m({existing:o?t.hookCodeInsertSchema.parse(o):null,desired:e,create:()=>n.hookCode.create(r,e,{importMetadata:{id:a}}),update:()=>n.hookCode.update(r,a,e),view:e=>e})})}for(let i of e.actions){let e=R(`action`,i),a=g.get(i.id);await p(`action`,e,async()=>{if(y(`action`,e))return`unchanged`;let o=t.actionInsertSchema.parse(i),s=await n.actions.get(r,a);return m({existing:s?t.actionInsertSchema.parse(s):null,desired:o,create:()=>n.actions.create(r,o,{importMetadata:{id:a}}),update:()=>n.actions.update(r,a,o),view:e=>e})})}for(let i of e.hooks){let e=R(`hook`,i),a=await h(`hook`,e);await p(`hook`,e,async()=>{let e=i.code_id,o=t.hookInsertSchema.parse({...i,hook_id:a,...e?{code_id:g.get(e)??e}:{}}),s=await n.hooks.get(r,a);return m({existing:s?t.hookInsertSchema.parse(s):null,desired:o,create:()=>n.hooks.create(r,o),update:()=>n.hooks.update(r,a,o),view:e=>e})})}let b=e=>e.override===`none`||e.enforce===!0,x=(e,t,n)=>B(e.parse(t))===B(n),S=(e,t)=>{let n={...t};for(let[t,r]of Object.entries(e))r!=null&&n[t]===void 0&&(n[t]=null);return n};e.emailProvider&&await p(`emailProvider`,`singleton`,async()=>{let i=t.emailProviderSchema.parse(e.emailProvider),o=await n.emailProviders.get(r);if(!o)return a||await n.emailProviders.create(r,i),`added`;if(!b(i)||x(t.emailProviderSchema,o,i))return`unchanged`;if(!a){let e=t.emailProviderSchema.parse(o);await n.emailProviders.update(r,S(e,i))}return`changed`}),e.branding&&await p(`branding`,`singleton`,async()=>{let i=t.brandingSchema.parse(e.branding),o=await n.branding.get(r);if(!o)return a||await n.branding.set(r,i),`added`;if(!b(i)||x(t.brandingSchema,o,i))return`unchanged`;if(!a){let e=t.brandingSchema.parse(o),a=S(e,i);e.colors&&!i.colors&&(a.colors={primary:null}),e.font&&!i.font&&(a.font={url:null}),await n.branding.set(r,a)}return`changed`}),e.promptSettings&&b(e.promptSettings)&&await p(`promptSettings`,`singleton`,async()=>{let i=t.promptSettingSchema.parse(e.promptSettings);return x(t.promptSettingSchema,await n.promptSettings.get(r),i)?`unchanged`:(a||await n.promptSettings.set(r,i),`changed`)});for(let t of e.deletes){let e=await h(t.entity,t.key),o=`${t.entity}:${t.key}`;try{if(!await We(n,r,t.entity,e))continue;s.changes.push(`delete ${o}`),s.rows.push({entity:t.entity,key:t.key,action:`delete`}),i.deletes&&!a&&(await Ge(n,r,t.entity,e),s.entities[t.entity].deleted+=1)}catch(e){s.entities[t.entity].errors.push(`delete ${o}: ${e instanceof Error?e.message:e}`)}}let C=()=>Object.values(s.entities).some(e=>e.errors.length>0);if(d&&!C()){let t=new Set;for(let n of Ne)for(let r of He(e,n))(n===`connection`||n===`resourceServer`||n===`action`)&&f[n].has(R(n,r))||t.add(n===`hookCode`||n===`action`?g.get(r.id):await h(n,R(n,r)));for(let e of Ue(d,t)){let t=`${e.entity}:${e.label}`;try{s.changes.push(`delete ${t}`),s.rows.push({entity:e.entity,key:e.label,action:`delete`}),i.prune&&!a&&(await Ge(n,r,e.entity,e.id),s.entities[e.entity].deleted+=1)}catch(n){s.entities[e.entity].errors.push(`delete ${t}: ${n instanceof Error?n.message:n}`)}}}let w=C();return!a&&!w&&c&&await n.tenants.update(r,{config_sync_hash:e.hash,config_synced_at:new Date().toISOString()}),s}function He(e,t){switch(t){case`connection`:return e.connections;case`resourceServer`:return e.resourceServers;case`hookCode`:return e.hookCode;case`action`:return e.actions;case`hook`:return e.hooks}}function Ue(e,n){let r=e=>!!e&&(0,t.isSyncedRowId)(e)&&!n.has(e);return[...e.hooks.filter(e=>r(e.hook_id)).map(e=>({entity:`hook`,id:e.hook_id,label:e.hook_id})),...e.actions.filter(e=>r(e.id)).map(e=>({entity:`action`,id:e.id,label:e.name})),...e.hookCode.filter(e=>r(e.id)).map(e=>({entity:`hookCode`,id:e.id,label:e.id})),...e.connections.filter(e=>r(e.id)).map(e=>({entity:`connection`,id:e.id,label:`${e.strategy}:${e.name}`})),...e.resourceServers.filter(e=>r(e.id)).map(e=>({entity:`resourceServer`,id:e.id,label:e.identifier}))]}async function We(e,t,n,r){switch(n){case`connection`:return!!await e.connections.get(t,r);case`resourceServer`:return!!await e.resourceServers.get(t,r);case`hookCode`:return!!await e.hookCode.get(t,r);case`action`:return!!await e.actions.get(t,r);case`hook`:return!!await e.hooks.get(t,r)}}async function Ge(e,t,n,r){switch(n){case`connection`:await e.connections.remove(t,r);return;case`resourceServer`:await e.resourceServers.remove(t,r);return;case`hookCode`:await e.hookCode.remove(t,r);return;case`action`:await e.actions.remove(t,r);return;case`hook`:await e.hooks.remove(t,r);return}}function Ke(e){let t=e.input??{};return{dryRun:t.dry_run===!0,force:t.force===!0,prune:t.prune===!0}}function qe(e){return Object.values(e.entities).flatMap(e=>e.errors)}var Je=20,Ye=300;function Xe(e,t){return{dry_run:t.dryRun,prune:t.prune,status:e.status,hash:e.hash,changes:e.changes,rows:e.rows??[],error_messages:qe(e).slice(0,Je).map(e=>e.slice(0,Ye)),entities:Object.fromEntries(Object.entries(e.entities).map(([e,t])=>[e,{added:t.added,changed:t.changed,unchanged:t.unchanged,deleted:t.deleted,errors:t.errors.length}]))}}async function Ze(e){let{operation:t,syncConfig:n,recorder:r}=e;if(!t.tenant_id)throw Error(`sync-defaults operations require a tenant_id`);let i=Ke(t),a=await n(t.tenant_id,i),o=Xe(a,i);await r.setResult(t.id,o);let s=qe(a);if(s.length>0){let e=s.slice(0,3).join(`; `);throw Error(`sync-defaults reported ${s.length} error(s): ${e}${s.length>3?`; ...`:``}`)}return o}function Qe(e,t){return async(n,r)=>{let i=await e.tenants.get(n);if(!i)throw Error(`Tenant "${n}" not found`);if(i.config_sync===`detached`)throw Error(`Tenant "${n}" is detached from its parent: set config_sync back to "inherit-on-read" or "synced" before syncing it`);if(i.deployment_type===`wfp`)throw Error(`Tenant "${n}" has its own database: configure a dispatch sync (syncDefaults) for it`);return Ve(await Le(e,n,{legacyControlPlane:(t.resolveControlPlane?await t.resolveControlPlane({tenant_id:n}):{tenantId:t.controlPlaneTenantId})?.tenantId,maxDepth:t.maxDepth}),e,n,{dryRun:r.dryRun,force:r.force,prune:r.prune})}}function $e(e){let t=e.input??{};return{dryRun:t.dry_run===!0,clean:t.clean===!0}}var et=20,tt=300;function nt(e){return Object.entries(e.entities).flatMap(([e,t])=>t.errors.map(t=>`${e} ${t}`))}function rt(e,t){return{dry_run:t.dryRun,clean:t.clean,status:e.status,changes:e.changes,rows:e.rows??[],error_messages:nt(e).slice(0,et).map(e=>e.slice(0,tt)),entities:Object.fromEntries(Object.entries(e.entities).map(([e,t])=>[e,{converted:t.converted,removed:t.removed,skipped:t.skipped,errors:t.errors.length}]))}}async function it(e){let{operation:t,detachTenant:n,recorder:r,onDetached:i}=e;if(!t.tenant_id)throw Error(`detach operations require a tenant_id`);let a=$e(t),o=await n(t.tenant_id,a),s=rt(o,a);await r.setResult(t.id,s);let c=nt(o);if(c.length===0&&!a.dryRun&&o.status===`detached`&&i?.(t.tenant_id),c.length>0){let e=c.slice(0,3).join(`; `);throw Error(`detach reported ${c.length} error(s): ${e}${c.length>3?`; ...`:``}`)}return s}var V=()=>({converted:0,removed:0,skipped:0,errors:[]});function H(e){let{id:t,hook_id:n,scope:r,override:i,enforce:a,...o}=e;return o}function at(e){return{status:e,changes:[],rows:[],entities:{connection:V(),resourceServer:V(),hookCode:V(),action:V(),hook:V()}}}function ot(e,t){if(t.config_sync!==`synced`)throw Error(`Tenant "${e}" is not synced: sync its parent's config into it (config_sync "synced") before detaching, otherwise it would lose what it inherits`)}async function st(e,t){await e.tenants.update(t,{parent_tenant_id:null,config_sync:`detached`,config_sync_hash:null,config_synced_at:null})}async function ct(e,n,r){let i=at(r.dryRun?`dry-run`:`detached`),{dryRun:a,clean:o}=r,s=await j(e,n),c={connection:s.connections.filter(e=>(0,t.isSyncedRowId)(e.id)),resourceServer:s.resourceServers.filter(e=>(0,t.isSyncedRowId)(e.id)),hookCode:s.hookCode.filter(e=>(0,t.isSyncedRowId)(e.id)),action:s.actions.filter(e=>(0,t.isSyncedRowId)(e.id)),hook:s.hooks.filter(e=>(0,t.isSyncedRowId)(e.hook_id))},l=e=>e.scope===`platform`,u=new Set;for(let e of c.hook){let t=e.code_id;l(e)&&t&&u.add(t)}for(let e of c.action)l(e)&&u.add(e.id);let d=(e,t,n,r=``)=>{i.changes.push(`${t} ${e}:${n}${r}`),i.rows.push({entity:e,key:n,action:t===`convert`?`converted`:t===`remove`?`removed`:`kept`})},f=async(e,t,n)=>{try{await n()}catch(n){i.entities[e].errors.push(`${t}: ${n instanceof Error?n.message:String(n)}`)}},p=(e,t)=>{i.entities[e].skipped+=1,d(e,`skip`,t,` (platform: stays a copy)`)},m=[];if(o){let t=async t=>{for(let r of await e.clientConnections.listByConnection(n,t))await e.clientConnections.removeClientFromConnection(n,t,r)},r=[...c.hook.map(t=>[`hook`,t.hook_id,()=>e.hooks.remove(n,t.hook_id)]),...c.action.map(t=>[`action`,t.name,()=>e.actions.remove(n,t.id)]),...c.hookCode.map(t=>[`hookCode`,t.id,()=>e.hookCode.remove(n,t.id)]),...c.connection.map(r=>[`connection`,`${r.strategy}:${r.name}`,async()=>{await t(r.id),await e.connections.remove(n,r.id)}]),...c.resourceServer.map(t=>[`resourceServer`,t.identifier,()=>e.resourceServers.remove(n,t.id)])];for(let[e,t,n]of r)d(e,`remove`,t),await f(e,t,async()=>{a||await n(),i.entities[e].removed+=1})}else{let r=new Map,o=new Set;for(let s of c.hookCode){if(u.has(s.id)){p(`hookCode`,s.id);continue}d(`hookCode`,`convert`,s.id),o.add(s.id),await f(`hookCode`,s.id,async()=>{if(!a){let i=await e.hookCode.create(n,t.hookCodeInsertSchema.parse(H(s)));r.set(s.id,i.id),m.push(async()=>{await e.hookCode.remove(n,s.id)})}i.entities.hookCode.converted+=1})}for(let s of c.action){if(l(s)){p(`action`,s.name);continue}d(`action`,`convert`,s.name),o.add(s.id),await f(`action`,s.name,async()=>{if(!a){let i=await e.actions.create(n,t.actionInsertSchema.parse(H(s)));r.set(s.id,i.id),m.push(async()=>{await e.actions.remove(n,s.id)})}i.entities.action.converted+=1})}let s=a?[]:await(0,t.fetchAll)(t=>e.organizations.list(n,t),`organizations`,{cursorField:`id`,pageSize:100});for(let r of c.connection){let o=`${r.strategy}:${r.name}`;if(l(r)){p(`connection`,o);continue}d(`connection`,`convert`,o),await f(`connection`,o,async()=>{if(!a){let{enabled_clients:i,...a}=H(r),o=await e.connections.create(n,t.connectionInsertSchema.parse(a));for(let t of await e.clientConnections.listByConnection(n,r.id))await e.clientConnections.addClientToConnection(n,o.id,t),await e.clientConnections.removeClientFromConnection(n,r.id,t);for(let t of s){let i=(await e.organizationConnections.list(n,t.id)).find(e=>e.connection_id===r.id);if(!i)continue;let{connection_id:a,organization_id:s,...c}=i;await e.organizationConnections.create(n,t.id,{...c,connection_id:o.id}),await e.organizationConnections.remove(n,t.id,r.id)}m.push(async()=>{await e.connections.remove(n,r.id)})}i.entities.connection.converted+=1})}for(let r of c.resourceServer){if(l(r)){p(`resourceServer`,r.identifier);continue}d(`resourceServer`,`convert`,r.identifier),await f(`resourceServer`,r.identifier,async()=>{if(!a){await e.resourceServers.remove(n,r.id);try{await e.resourceServers.create(n,t.resourceServerInsertSchema.parse(H(r)))}catch(i){throw await e.resourceServers.create(n,t.resourceServerInsertSchema.parse(r)),i}}i.entities.resourceServer.converted+=1})}let h=[];for(let s of c.hook){let c=s.hook_id,u=s.code_id;if(l(s)){p(`hook`,c);continue}if(u&&!(a?o.has(u):r.has(u))){i.entities.hook.skipped+=1,d(`hook`,`skip`,c,` (its code is not converted)`);continue}d(`hook`,`convert`,c),await f(`hook`,c,async()=>{a||(await e.hooks.create(n,t.hookInsertSchema.parse({...H(s),...u?{code_id:r.get(u)}:{}})),h.push(async()=>{await e.hooks.remove(n,c)})),i.entities.hook.converted+=1})}m.unshift(...h)}if(Object.values(i.entities).some(e=>e.errors.length>0))return{...i,status:`partial`};if(a)return i;for(let e of m)try{await e()}catch(e){i.entities.hook.errors.push(`remove: ${e instanceof Error?e.message:String(e)}`)}return Object.values(i.entities).some(e=>e.errors.length>0)?{...i,status:`partial`}:i}function lt(e){return async(t,n)=>{let r=await e.tenants.get(t);if(!r)throw Error(`Tenant "${t}" not found`);if(r.deployment_type===`wfp`)throw Error(`Tenant "${t}" has its own database: configure a dispatch detach for it`);if(r.config_sync===`detached`)return at(`already-detached`);ot(t,r);let i=await ct(e,t,n);return i.status===`detached`&&await st(e,t),i}}function ut(e){if(e.tenantOperations&&e.tenantOperationEvents)return{tenantOperations:e.tenantOperations,tenantOperationEvents:e.tenantOperationEvents}}async function dt(e,t,n){let r=ut(e);if(!r){await n(void 0);return}let i=p(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 _(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:f(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 ft(e){let t=()=>{if(!e.tenantMemberRequests)throw Error(`The data adapter has no tenantMemberRequests adapter`);return e.tenantMemberRequests};return{get:(e,n)=>t().get(e,n),async report(e,n,r){return t().update(e,n,{status:r.status,result:r.result??null,error:r.error??null,finished_at:new Date().toISOString()},`pending`)},async listPending(e,{olderThan:n}){return(await t().list(e,{status:`pending`,created_before:n,per_page:100})).requests}}}function U(e){let t=e.input?.request_id;return typeof t==`string`&&t?t:void 0}var pt=300;async function mt(e){let{operation:n,store:r,getBackend:i,recorder:a}=e,o=n.tenant_id,s=U(n);if(!o||!s)throw Error(`tenant-members-request operations require a tenant_id and a request_id`);let c=await r.get(o,s);if(!c)throw Error(`Request ${s} was not found for tenant ${o}`);if(c.status!==`pending`){let e={request_id:s,outcome:`already_finished`,status:c.status};return await a.setResult(n.id,e),e}let l;try{l={status:`succeeded`,result:await(0,t.executeTenantMemberRequest)(await i(),o,c,e.executeOptions)}}catch(e){if(!(e instanceof t.TenantMemberRequestRejected))throw e;l={status:`failed`,error:f(e).slice(0,pt)}}let u=await r.report(o,s,l),d={request_id:s,outcome:l.status,reported:u,...l.status===`failed`?{reason:l.error}:{}};return await a.setResult(n.id,d),d}var ht=5;async function gt(e,t,n,r={}){let{operations:i}=await e.stores.tenantOperations.list({tenant_id:t,kind:`tenant-members-request`,per_page:100});return i.find(e=>U(e)===n&&(e.status===`pending`||e.status===`running`||e.status===`succeeded`))||v(e.stores,e.executor,{kind:`tenant-members-request`,tenant_id:t,initiated_by:r.initiatedBy,input:{request_id:n}},{returnFailed:!0})}async function _t(e){let t=e.now?.()??new Date,n=new Date(t.getTime()-(e.graceMs??5*6e4)).toISOString(),r=e.maxAttempts??5,i={checked:0,enqueued:0,gaveUp:0,unreachable:[]};for(let t of await e.tenantIds()){let a;try{a=await e.store.listPending(t,{olderThan:n})}catch(e){console.warn(`[tenant-members] could not read the requests of ${t}:`,e),i.unreachable.push(t);continue}if(a.length===0)continue;let{operations:o}=await e.stores.tenantOperations.list({tenant_id:t,kind:`tenant-members-request`,per_page:100});for(let n of a){i.checked+=1;let a=o.filter(e=>U(e)===n.id);if(!a.some(e=>e.status===`pending`||e.status===`running`)){if(a.filter(e=>e.status===`failed`).length>=r){try{await e.store.report(t,n.id,{status:`failed`,error:`The control plane could not carry out this request`})&&(i.gaveUp+=1)}catch(e){console.warn(`[tenant-members] could not report request ${n.id} as failed:`,e)}continue}try{await gt(e,t,n.id),i.enqueued+=1}catch(e){console.warn(`[tenant-members] could not enqueue request ${n.id}:`,e)}}}}return i}function vt(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function yt(e){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:vt(t.id)}:t},async afterCreate(n,r){let{accessControl:i,databaseIsolation:a}=e;if(i&&n.ctx&&await bt(n,r,i),a?.onProvision){let e=a.onProvision;a.recordProvisionOperations===!1?await e(r.id):await dt(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 bt(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 St(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await xt(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 xt(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 St(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 Ct(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 wt(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 Tt=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})}),Et=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 Dt(e){return e.metadata?.sync!==!1}function Ot(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>Dt(e)?r.resourceServers?r.resourceServers(e):!0:!1,s=e=>Dt(e)?r.roles?r.roles(e):!0:!1,c=i?Ct(e,Tt,o):void 0,l=a?Ct(e,Et,s):void 0,u=i?wt(e,Tt,o):void 0,d=a?wt(e,Et,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 W(e){return e.var.data??e.env.data}async function kt(e,t,n){let r=!n||n===t,{totals:a}=await e.list({per_page:1,include_totals:!0,...r?{}:{q:`parent_tenant_id:${(0,i.escapeLuceneValue)(t)}`}});return{is_control_plane:r,has_children:(a?.length??0)>+!!r}}var At=r.z.object({sub:r.z.string(),tenant_id:r.z.string().optional(),org_id:r.z.string().optional(),scope:r.z.string().optional(),permissions:r.z.array(r.z.string()).optional()}).passthrough();function jt(e){let t=At.safeParse(e);return t.success?t.data:void 0}function Mt(e,t,n){return t?!e||n?!1:e.tenant_id===t:!0}function Nt(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 G(e,i){let a=new r.OpenAPIHono,o=t=>{let n=jt(t.var.user);return Mt(n,e.accessControl?.controlPlaneTenantId??W(t).multiTenancyConfig?.controlPlaneTenantId,!!(n?.org_id??t.var.organization_id??t.var.org_name))},s=(t,n)=>kt(W(t).tenants,n,e.accessControl?.controlPlaneTenantId??W(t).multiTenancyConfig?.controlPlaneTenantId);if(a.openapi((0,r.createRoute)({tags:[`tenants`],method:`get`,path:`/`,request:{query:t.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:r.z.object({tenants:r.z.array(t.tenantSchema),start:r.z.number().optional(),limit:r.z.number().optional(),length:r.z.number().optional(),total:r.z.number().optional()})}},description:`List of tenants`}}}),async r=>{let{page:i,per_page:a,include_totals:o,q:s}=r.req.valid(`query`),c=r.var.user,l=c?.permissions||[];if(!(c?.org_id??r.var.organization_id)&&l.includes(`admin:organizations`)){let e=await W(r).tenants.list({page:i,per_page:a,include_totals:o,q:s});return o?r.json({tenants:e.tenants,start:e.totals?.start??0,limit:e.totals?.limit??a,length:e.tenants.length,total:e.totals?.length}):r.json({tenants:e.tenants})}let u=e.accessControl?.controlPlaneTenantId??W(r).multiTenancyConfig?.controlPlaneTenantId;if(u&&!c?.sub)throw new n.HTTPException(403,{message:`Access denied: token has no subject`});if(u&&c?.sub){let e=(await(0,t.fetchAll)(e=>W(r).userOrganizations.listUserOrganizations(u,c.sub,e),`organizations`)).map(e=>e.name);if(e.length===0)return o?r.json({tenants:[],start:0,limit:a??50,length:0,total:0}):r.json({tenants:[]});let n=e.length,l=i??0,d=a??50,f=l*d,p=e.slice(f,f+d);if(p.length===0)return o?r.json({tenants:[],start:f,limit:d,length:0,total:n}):r.json({tenants:[]});let m=p.map(e=>`id:${e}`).join(` OR `),h=s?`(${m}) AND (${s})`:m,g=await W(r).tenants.list({q:h,per_page:d,include_totals:!1});return o?r.json({tenants:g.tenants,start:f,limit:d,length:g.tenants.length,total:n}):r.json({tenants:g.tenants})}let d=await W(r).tenants.list({page:i,per_page:a,include_totals:o,q:s});return o?r.json({tenants:d.tenants,start:d.totals?.start??0,limit:d.totals?.limit??a,length:d.tenants.length,total:d.totals?.length}):r.json({tenants:d.tenants})}),a.openapi((0,r.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 t=>{if(!t.var.user?.sub)throw new n.HTTPException(401,{message:`Authentication required to create tenants`});let{config_sync_hash:r,config_synced_at:a,config_sync:s,...c}=t.req.valid(`json`),l=c;if(l.parent_tenant_id&&!o(t))throw new n.HTTPException(403,{message:`Only the control plane can set a tenant's parent`});s!==void 0&&o(t)&&(l={...l,config_sync:s});let u={adapters:W(t),ctx:t};i.tenants?.beforeCreate&&(l=await i.tenants.beforeCreate(u,l)),await y({tenantId:l.id,parentTenantId:l.parent_tenant_id,getTenant:e=>W(t).tenants.get(e)});let d=await W(t).tenants.create(l);return i.tenants?.afterCreate&&await i.tenants.afterCreate(u,d),e.onConfigSyncChange?.(d.id),t.json(d,201)}),a.openapi((0,r.createRoute)({tags:[`tenants`],method:`delete`,path:`/{id}`,request:{params:r.z.object({id:r.z.string()})},security:[{Bearer:[`delete:tenants`]}],responses:{204:{description:`Tenant deleted`},403:{description:`Access denied or cannot delete the control plane`},404:{description:`Tenant not found`}}}),async r=>{let{id:a}=r.req.valid(`param`),o=e.accessControl?.controlPlaneTenantId??W(r).multiTenancyConfig?.controlPlaneTenantId;if(o){let e=jt(r.var.user);if(!e?.sub)throw new n.HTTPException(401,{message:`Authentication required`});if(a===o)throw new n.HTTPException(403,{message:`Cannot delete the control plane`});let i=r.var.org_name,s=a.toLowerCase(),c=!!i&&i.toLowerCase()===s;if(!c){let t=!!(e.org_id??r.var.organization_id??i),n=!e.tenant_id||e.tenant_id===o;!t&&n&&Nt(e)&&(c=!0)}if(c||=(await(0,t.fetchAll)(t=>W(r).userOrganizations.listUserOrganizations(o,e.sub,t),`organizations`)).some(e=>e.name?.toLowerCase()===s),!c)throw new n.HTTPException(403,{message:`Access denied to this tenant`})}if(!await W(r).tenants.get(a))throw new n.HTTPException(404,{message:`Tenant not found`});let s={adapters:W(r),ctx:r};return i.tenants?.beforeDelete&&await i.tenants.beforeDelete(s,a),await W(r).tenants.remove(a),i.tenants?.afterDelete&&await i.tenants.afterDelete(s,a),r.body(null,204)}),e.verifyConfigSync){let t=e.verifyConfigSync;a.openapi((0,r.createRoute)({tags:[`tenants`],method:`get`,path:`/{id}/config-sync/verify`,request:{params:r.z.object({id:r.z.string()})},security:[{Bearer:[`read:tenants`]}],responses:{200:{content:{"application/json":{schema:r.z.object({tenant_id:r.z.string(),config_sync:r.z.enum([`inherit-on-read`,`synced`,`detached`]),method:r.z.enum([`read-time`,`sync-dry-run`,`not-applicable`]),ok:r.z.boolean(),differences:r.z.array(r.z.object({entity:r.z.string(),key:r.z.string(),kind:r.z.enum([`missing`,`extra`,`changed`,`stale`]),fields:r.z.array(r.z.string()).optional()})),errors:r.z.array(r.z.string())})}},description:`The tenant's config compared with what its parents publish`},403:{description:`Not allowed to verify this tenant`},404:{description:`Tenant not found`},502:{description:`The tenant's database could not be reached`}}}),async e=>{let{id:r}=e.req.valid(`param`);if(r!==e.var.tenant_id&&!o(e))throw new n.HTTPException(403,{message:`Config can only be verified for your own tenant`});let i;try{i=await t(r)}catch(e){throw console.error(`[multi-tenancy] config verify failed for "${r}":`,e),new n.HTTPException(502,{message:`Could not verify: the tenant's config could not be checked`})}if(!i)throw new n.HTTPException(404,{message:`Tenant not found`});return e.json(i)})}if(e.configSyncStatus){let t=e.configSyncStatus;a.openapi((0,r.createRoute)({tags:[`tenants`],method:`get`,path:`/{id}/config-sync`,request:{params:r.z.object({id:r.z.string()})},security:[{Bearer:[`read:tenants`]}],responses:{200:{content:{"application/json":{schema:r.z.object({tenant_id:r.z.string(),parent_tenant_id:r.z.string().nullable(),config_sync:r.z.enum([`inherit-on-read`,`synced`,`detached`]),config_sync_hash:r.z.string().nullable(),config_synced_at:r.z.string().nullable(),expected_hash:r.z.string().nullable(),drifted:r.z.boolean(),chain:r.z.array(r.z.string()),inherited:r.z.record(r.z.string(),r.z.string())})}},description:`Config sync status of the tenant`},403:{description:`Not allowed to read this tenant`},404:{description:`Tenant not found`}}}),async e=>{let{id:r}=e.req.valid(`param`);if(r!==e.var.tenant_id&&!o(e))throw new n.HTTPException(403,{message:`Config sync status is only readable for your own tenant`});let i=await t(r);if(!i)throw new n.HTTPException(404,{message:`Tenant not found`});return e.json(i)})}return a.openapi((0,r.createRoute)({tags:[`tenants`,`settings`],method:`get`,path:`/settings`,request:{headers:r.z.object({"tenant-id":r.z.string().optional()})},security:[{Bearer:[`read:tenants`]}],responses:{200:{content:{"application/json":{schema:t.tenantSchema}},description:`Current tenant settings`}}}),async e=>{let t=await W(e).tenants.get(e.var.tenant_id);if(!t)throw new n.HTTPException(404,{message:`Tenant not found`});return e.json({...t,...await s(e,t.id)})}),a.openapi((0,r.createRoute)({tags:[`tenants`,`settings`],method:`patch`,path:`/settings`,request:{headers:r.z.object({"tenant-id":r.z.string().optional()}),body:{content:{"application/json":{schema:r.z.object(t.tenantInsertSchema.shape).partial()}}}},security:[{Bearer:[`update:tenants`]}],responses:{200:{content:{"application/json":{schema:t.tenantSchema}},description:`Updated tenant settings`}}}),async r=>{let{id:i,config_sync_hash:a,config_synced_at:c,...l}=r.req.valid(`json`),u=await W(r).tenants.get(r.var.tenant_id);if(!u)throw new n.HTTPException(404,{message:`Tenant not found`});if(`config_sync`in l&&(l.config_sync??`inherit-on-read`)!==(u.config_sync??`inherit-on-read`)&&!o(r))throw new n.HTTPException(403,{message:`Only the control plane can change a tenant's config_sync mode`});if(`default_client_id`in l){let e=l.default_client_id;if(typeof e==`string`&&e.length>0){let i=await W(r).clients.get(r.var.tenant_id,e);if(!i)throw new n.HTTPException(400,{message:`Client with id '${e}' not found`});if(!(0,t.isInteractiveClient)(i))throw new n.HTTPException(400,{message:`Client '${e}' is not an interactive client and cannot be used as the default client`})}}if(`parent_tenant_id`in l){if((l.parent_tenant_id??null)!==(u.parent_tenant_id??null)&&!o(r))throw new n.HTTPException(403,{message:`Only the control plane can change a tenant's parent`});await y({tenantId:r.var.tenant_id,parentTenantId:l.parent_tenant_id,getTenant:e=>W(r).tenants.get(e),getChildren:async e=>(await(0,t.fetchAll)(e=>W(r).tenants.list(e),`tenants`)).filter(t=>t.parent_tenant_id===e).map(e=>e.id)})}let d=(0,t.deepMergePatch)(u,l);await W(r).tenants.update(r.var.tenant_id,d),`config_sync`in l&&e.onConfigSyncChange?.(r.var.tenant_id);let f=await W(r).tenants.get(r.var.tenant_id);if(!f)throw new n.HTTPException(500,{message:`Failed to retrieve updated tenant`});return r.json({...f,...await s(r,f.id)})}),a}function Pt(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 Ft(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 It(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function Lt(e){for(let{pattern:t,type:n}of[{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:`connection`},{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:`resource_server`},{pattern:/\/api\/v2\/actions\/actions\/([^/]+)$/,type:`action`},{pattern:/\/api\/v2\/hooks\/([^/]+)$/,type:`hook`},{pattern:/\/api\/v2\/hook-code\/([^/]+)$/,type:`hook_code`}]){let r=e.match(t);if(r?.[1])return{type:n,id:r[1]}}return null}async function Rt(e,t,n){try{switch(n.type){case`connection`:return await e.connections.get(t,n.id);case`resource_server`:return await e.resourceServers.get(t,n.id);case`action`:return await e.actions.get(t,n.id);case`hook`:return await e.hooks.get(t,n.id);case`hook_code`:return await e.hookCode.get(t,n.id)}}catch{return null}}var zt={connection:[`options`],resource_server:[`signing_secret`],action:[`secrets`],hook:[],hook_code:[]},Bt=new Set([`client_secret`,`app_secret`,`twilio_token`]);function Vt(e,t){let n=e=>{let{client_secret:t,...n}=e??{};return n};return Ht(n(e),n(t))}var Ht=(e,t)=>JSON.stringify(e)===JSON.stringify(t);function K(e,t){return new n.HTTPException(403,{message:`This ${e.type.replace(`_`,` `)} is synced from a parent tenant and ${t}. Make changes in the parent tenant instead.`})}async function Ut(e,t,n){let r=await Rt(W(e),t,n);if(!r)return;if(n.type===`hook_code`)throw K(n,`cannot be modified`);if(e.req.method===`DELETE`){if(r.enforce===!0)throw K(n,`cannot be deleted`);return}let i=r.override??`fields`;if(i===`none`)throw K(n,`cannot be edited`);let a={};try{let t=await e.req.raw.clone().json();t&&typeof t==`object`&&(a=t)}catch{}for(let e of[`scope`,`override`,`enforce`])if(e in a&&!Ht(a[e]??null,r[e]??null))throw K(n,`has a locked ${e}`);if(r.enforce===!0&&a.enabled===!1)throw K(n,`cannot be disabled`);if(i===`secrets`){let e=zt[n.type];for(let[t,i]of Object.entries(a))if(![`scope`,`override`,`enforce`].includes(t)&&!Ht(i,r[t])){if(!e.includes(t))throw K(n,`only allows its secrets to be changed (not ${t})`);if(t===`options`&&i&&typeof i==`object`){let e=r.options??{};for(let[t,r]of Object.entries(i))if(!Ht(r,e[t])&&!t.endsWith(`_hint`)&&!(Bt.has(t)||t===`configuration`&&Vt(r,e[t])))throw K(n,`only allows its secrets to be changed (not options.${t})`)}}}}function Wt(){return async(e,r)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return r();let i=Pt(e.req.path),a=Lt(e.req.path);if(!i&&!a)return r();let o=e.var.tenant_id||e.req.header(`x-tenant-id`)||e.req.header(`tenant-id`);if(!o)return r();if(i&&await Ft(W(e),o,i))throw new n.HTTPException(403,{message:`This ${It(i.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return a&&(0,t.isSyncedRowId)(a.id)&&await Ut(e,o,a),r()}}function Gt(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 Kt(e){return async(r,i)=>{if(!e.accessControl)return i();let{controlPlaneTenantId:a}=e.accessControl,s=r.var.org_name,c=r.var.organization_id,l=s||c,u=r.var.tenant_id,d=r.var.user,f=(d?.aud?Array.isArray(d.aud)?d.aud:[d.aud]:[]).includes(t.MANAGEMENT_API_AUDIENCE);if(!u&&l&&f&&(r.set(`tenant_id`,l),u=l),!u)throw new n.HTTPException(400,{message:`Tenant ID not found in request`});if(!o(c,u,a,s))throw new n.HTTPException(403,{message:`Access denied to tenant ${u}`});return i()}}function qt(e){return async(t,r)=>{if(!e.subdomainRouting)return r();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),r();let l=null;if(o)l=await o(c);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{let n=await W(t).organizations.get(e.accessControl.controlPlaneTenantId,c);n&&(l=n.id)}catch{}if(!l)throw new n.HTTPException(404,{message:`Tenant not found for subdomain: ${c}`});return t.set(`tenant_id`,l),r()}}function Jt(e){return async(t,r)=>{if(!e.databaseIsolation)return r();let i=t.var.tenant_id;if(!i)throw new n.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 n.HTTPException(500,{message:`Failed to resolve tenant database`})}return r()}}function Yt(e){let t=qt(e),n=Kt(e),r=Jt(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}var Xt=[10,50,100],q={canary:1,waves:Xt,failure_threshold:.1,max_concurrent:25,debounce_ms:6e4};function J(e){let t=e.config??{};return{...q,trigger:`manual`,root_tenant_id:``,...t,waves:Array.isArray(t.waves)&&t.waves.length>0?t.waves:[...Xt]}}function Zt(e,t,n){let r=Array(e).fill(0);if(e===0)return r;let i=Math.min(Math.max(t,0),e),a=[],o=i;for(let t of n){let n=Math.min(e,Math.max(o,Math.ceil(e*t/100)));n>o&&(a.push(n),o=n)}o<e&&a.push(e);let s=+(i>0),c=i;for(let e of a){for(;c<e;c++)r[c]=s;s++}return r}async function Qt(e,n,r){let i=r.maxDepth??8,a=await(0,t.fetchAll)(t=>e.tenants.list(t),`tenants`,{cursorField:`id`,pageSize:100}),o=new Map(a.map(e=>[e.id,e])),s=async e=>e.parent_tenant_id??(e.id===n?void 0:await r.resolveLegacyParent(e.id)),c=[];for(let e of a){if(e.id===n||e.config_sync!==`synced`)continue;let t=0,r=e,a=!1;for(;r&&t<=i;){let e=await s(r);if(!e)break;if(t++,e===n){a=!0;break}r=o.get(e)}a&&c.push({tenantId:e.id,depth:t,appliedHash:e.config_sync_hash??null})}return c.sort((e,t)=>e.depth-t.depth||(e.tenantId<t.tenantId?-1:1))}async function Y(e,t){return e.resolveControlPlane?(await e.resolveControlPlane({tenant_id:t}))?.tenantId:e.controlPlaneTenantId}function X(e){let t=new Map;return async n=>{let r=await Y(e,n),i=(await b({tenantId:n,getTenant:t=>e.adapters.tenants.get(t),legacyControlPlane:r,maxDepth:e.maxDepth})).join(`>`),a=t.get(i);return a||(a=Le(e.adapters,n,{legacyControlPlane:r,maxDepth:e.maxDepth}).then(e=>e.hash),t.set(i,a)),a}}var $t=[`pending`,`canary`,`rolling`,`paused`];function en(e){let{tenantOperations:t,tenantOperationEvents:n}=e.adapters;if(!t||!n)throw Error(`Fleet rollouts need the tenant operations adapters`);return{tenantOperations:t,tenantOperationEvents:n}}function Z(e){if(!e.adapters.rollouts)throw Error(`Fleet rollouts need the rollouts adapter`);return e.adapters.rollouts}async function tn(e,t,n={}){let r=Z(e),i=en(e),a=J(t),o=await Qt(e.adapters,a.root_tenant_id,{resolveLegacyParent:t=>Y(e,t),maxDepth:e.maxDepth});if(n.tenantIds){let e=new Set(n.tenantIds);o=o.filter(t=>e.has(t.tenantId))}let s=X(e),c=[];for(let e of o)(a.force||e.appliedHash!==await s(e.tenantId))&&c.push(e);let l=o.length-c.length;if(c.length===0)return a.trigger===`write`?await r.remove(t.id):await r.update(t.id,{status:`done`,finished_at:new Date(e.now?.()??Date.now()).toISOString(),config:{...a,planned:!0,tenant_count:0}}),{planned:0,upToDate:l};let u=new Set((await Q(e,t.id)).map(e=>e.tenant_id)),d=Zt(c.length,a.canary,a.waves);for(let[n,r]of c.entries())u.has(r.tenantId)||await _(i,{kind:`sync-defaults`,tenant_id:r.tenantId,rollout_id:t.id,initiated_by:`rollout:${t.id}`,input:{wave:d[n],...a.dry_run?{dry_run:!0}:{},...a.force?{force:!0}:{}}},e.executor.engine);return await r.update(t.id,{status:`canary`,config:{...a,planned:!0,tenant_count:c.length}}),{planned:c.length,upToDate:l}}async function Q(e,t){let{tenantOperations:n}=en(e),r=[];for(let e=0;;e++){let{operations:i}=await n.list({rollout_id:t,page:e,per_page:200});if(r.push(...i),i.length<200)break}return r.sort((e,t)=>e.created_at===t.created_at?e.id<t.id?-1:1:e.created_at<t.created_at?-1:1)}var $=e=>{let t=e.input?.wave;return typeof t==`number`?t:0},nn=e=>e.status===`failed`||e.status===`cancelled`;function rn(e,t,n){let r=t.filter(e=>$(e)===n),i=r.filter(nn).length,a=n===0&&e.canary>0,o=a?0:e.failure_threshold;return r.length===0||i===0||i/r.length<=o?null:`${a?`canary`:`wave ${n}`} failed for ${i} of ${r.length} tenant(s)`}async function an(e,t){let n=Z(e),r=e.now?.()??Date.now(),i=typeof t==`string`?await n.get(t):t;if(!i||i.kind!==`config-sync`)return{rolloutId:String(i?.id??t),outcome:`skipped`,started:0};let a=i.id;if(!$t.includes(i.status)||i.status===`paused`)return{rolloutId:a,outcome:`skipped`,started:0};let o=J(i);if(!o.planned){if(r-Date.parse(i.updated_at)<o.debounce_ms)return{rolloutId:a,outcome:`waiting`,started:0};let{planned:t}=await tn(e,i);if(t===0)return{rolloutId:a,outcome:`planned-empty`,started:0};i=await n.get(a)??i,o=J(i)}let s=await Q(e,a),c=s.filter(e=>!m(e.status));if(c.length===0){let e=Math.max(0,...s.map($)),t=s.length>0&&e>(o.accepted_through??-1)?rn(o,s,e):null;return await n.update(a,{status:t?`failed`:`done`,...t?{paused_reason:t}:{},finished_at:new Date(r).toISOString()}),{rolloutId:a,outcome:`done`,started:0}}let l=Math.min(...c.map($)),u=l-1;if(u>=0&&u>(o.accepted_through??-1)){let e=rn(o,s,u);if(e)return await n.update(a,{status:`paused`,paused_reason:e}),{rolloutId:a,outcome:`paused`,started:0,wave:l}}let d=l===0?`canary`:`rolling`;i.status!==d&&await n.update(a,{status:d});let f=c.filter(e=>$(e)===l),h=f.filter(e=>e.status===`running`).length,g=Math.max(0,o.max_concurrent-h),{tenantOperations:_,tenantOperationEvents:v}=en(e),y=p({tenantOperations:_,tenantOperationEvents:v}),b=0;for(let t of f.filter(e=>e.status===`pending`).slice(0,g)){try{await y.markRunning(t.id),await e.executor.start(t)}catch(e){try{let n=await _.get(t.id);n&&!m(n.status)&&await y.markFailed(t.id,e)}catch{}}b++}return{rolloutId:a,outcome:b>0?`started`:`running`,started:b,wave:l}}async function on(e,t={}){let{rollouts:n}=await Z(e).list({kind:`config-sync`,status:[`pending`,`canary`,`rolling`],per_page:t.limit??20}),r=[];for(let i of n)try{r.push(await an(e,i))}catch(e){t.logger?.warn(`Advancing rollout ${i.id} failed:`,e)}return r}async function sn(e,t,n=`paused by an operator`){let r=Z(e),i=await r.get(t);return!i||i.kind!==`config-sync`?null:i.status===`done`||i.status===`failed`?i:(await r.update(t,{status:`paused`,paused_reason:n}),r.get(t))}async function cn(e,t){let n=Z(e),r=await n.get(t);if(!r||r.kind!==`config-sync`)return null;if(r.status!==`paused`)return r;let i=J(r),a=(await Q(e,t)).filter(e=>!m(e.status)),o=a.length>0?Math.min(...a.map($)):0;return await n.update(t,{status:o===0?`canary`:`rolling`,paused_reason:null,config:{...i,accepted_through:Math.max(i.accepted_through??-1,o-1)}}),n.get(t)}var ln={added:`missing`,changed:`changed`,delete:`stale`};function un(e){return(e.rows??e.changes.flatMap(e=>{if(e.startsWith(`skip `))return[];let t=/^delete ([^:\s]+):(.*)$/.exec(e);if(t)return[{entity:t[1],key:t[2],action:`delete`}];let n=/^([^:\s]+):(.*)$/.exec(e);return n?[{entity:n[1],key:n[2],action:`changed`}]:[]})).flatMap(e=>{let t=ln[e.action];return t?[{entity:e.entity,key:e.key,kind:t}]:[]})}async function dn(e,t){let n=await e.adapters.tenants.get(t);if(!n)return null;let r=n.config_sync??`inherit-on-read`,i={tenant_id:t,config_sync:r,errors:[]};if(r===`detached`)return{...i,method:`not-applicable`,ok:!0,differences:[]};if(r===`inherit-on-read`){let n=(await se({adapters:e.adapters,tenantId:t,legacyControlPlane:await Y(e,t),maxDepth:e.maxDepth})).filter(e=>!e.expected).map(e=>({entity:e.entity,key:e.key,kind:e.kind,...e.fields.length>0?{fields:e.fields}:{}}));return{...i,method:`read-time`,ok:n.length===0,differences:n}}let a=await e.syncConfig(t,{dryRun:!0,force:!1,prune:!1}),o=un(a),s=Object.entries(a.entities).filter(([,e])=>e.errors.length>0).map(([e,t])=>`${e}: the sync dry run reported ${t.errors.length} error(s)`);return{...i,method:`sync-dry-run`,ok:o.length===0&&s.length===0,differences:o,errors:s.slice(0,20)}}async function fn(e,n){let r=await e.adapters.tenants.get(n);if(!r)return null;if(r.config_sync===`detached`)return{tenant_id:n,parent_tenant_id:null,config_sync:`detached`,config_sync_hash:null,config_synced_at:null,expected_hash:null,drifted:!1,chain:[],inherited:{}};let i=r.config_sync===`synced`,a=await b({tenantId:n,getTenant:t=>e.adapters.tenants.get(t),legacyControlPlane:await Y(e,n),maxDepth:e.maxDepth}),o=i?await X(e)(n):null,s=r.config_sync_hash??null,c={};for(let r of[...a].reverse()){let i=await j(e.adapters,r),a=(e,t)=>I(e,t)===`shared`,o=async(e,i,o)=>{for(let s of i){if(!a(o,s))continue;let i=await L(e,n,R(e,s)),l=s.id??s.hook_id;l&&(0,t.isSyncedRowId)(l)&&c[i]||(c[i]=r)}};await o(`connection`,i.connections,`connection`),await o(`resourceServer`,i.resourceServers,`resourceServer`),await o(`action`,i.actions,`action`),await o(`hook`,i.hooks,`hook`),i.emailProvider&&a(`emailProvider`,i.emailProvider)&&(c.emailProvider=r),i.branding&&a(`branding`,i.branding)&&(c.branding=r),i.promptSettings&&a(`promptSettings`,i.promptSettings)&&(c.promptSettings=r)}return{tenant_id:n,parent_tenant_id:r.parent_tenant_id??null,config_sync:i?`synced`:`inherit-on-read`,config_sync_hash:s,config_synced_at:r.config_synced_at??null,expected_hash:o,drifted:i&&o!==s,chain:a,inherited:c}}async function pn(e,n={}){let r=Z(e),i=n.rootTenantId??e.controlPlaneTenantId,a=n.limit??500,o=await Qt(e.adapters,i,{resolveLegacyParent:t=>Y(e,t),maxDepth:e.maxDepth}),s=X(e),c=[];for(let e of o){if(c.length>=a)break;try{let t=await s(e.tenantId);e.appliedHash!==t&&c.push({tenantId:e.tenantId,expected:t,applied:e.appliedHash})}catch(t){n.logger?.warn(`Could not compute the expected hash of ${e.tenantId}:`,t)}}let l={checked:o.length,drifted:c.length,alreadyCovered:0,recentlyFailed:0};if(c.length===0)return l;let u=new Set,{rollouts:d}=await r.list({kind:`config-sync`,status:[...$t],per_page:100});for(let t of d)for(let n of await Q(e,t.id))n.tenant_id&&!m(n.status)&&u.add(n.tenant_id);for(let r of c)try{await e.adapters.logs.create(r.tenantId,{type:t.LogTypes.CONFIG_DRIFT,date:new Date(e.now?.()??Date.now()).toISOString(),isMobile:!1,description:r.applied?`hash-mismatch: applied config differs from what the parent chain publishes`:`never-synced: no config has been applied to this synced tenant`,details:{reason:r.applied?`hash-mismatch`:`never-synced`,applied_hash:r.applied,expected_hash:r.expected,covered_by_open_rollout:u.has(r.tenantId),trigger:`reconcile`}})}catch(e){n.logger?.warn(`Could not record drift for ${r.tenantId}:`,e)}let f=c.filter(e=>!u.has(e.tenantId));l.alreadyCovered=c.length-f.length;let{tenantOperations:p}=en(e),h=e.now?.()??Date.now(),g=n.retryAfterMs??36e5,_=[];for(let e of f){try{let{operations:t}=await p.list({tenant_id:e.tenantId,kind:`sync-defaults`,per_page:5}),n=t.sort((e,t)=>e.created_at===t.created_at?e.id<t.id?1:-1:e.created_at<t.created_at?1:-1)[0];if(n?.status===`failed`&&h-Date.parse(n.updated_at)<g){l.recentlyFailed++;continue}}catch(t){n.logger?.warn(`Could not read the latest sync of ${e.tenantId}:`,t)}_.push(e)}if(_.length===0)return l;let v=await r.create({kind:`config-sync`,initiated_by:`reconcile`,config:{...q,trigger:`reconcile`,root_tenant_id:i,planned:!1}});return await tn(e,v,{tenantIds:_.map(e=>e.tenantId)}),l.rolloutId=v.id,l}function mn(e,t){return e===`hookCode`?!0:!t||typeof t!=`object`?!1:I(e,t)!==`local`}async function hn(e,t,n){let r=Z(e),{rollouts:i}=await r.list({kind:`config-sync`,status:`pending`,per_page:100}),a=i.find(e=>{let n=J(e);return n.trigger===`write`&&n.planned!==!0&&n.origin_tenant_id===t});return a?(await r.update(a.id,{}),await r.get(a.id)??a):r.create({kind:`config-sync`,initiated_by:n??`write:${t}`,config:{...q,trigger:`write`,root_tenant_id:t,origin_tenant_id:t,planned:!1}})}async function gn(e,t){if(t===e.controlPlaneTenantId)return!0;try{let{tenants:n}=await e.adapters.tenants.list({q:`parent_tenant_id:${t}`,per_page:1});return n.some(e=>e.parent_tenant_id===t)}catch{return!0}}function _n(e,t={}){let n=async n=>{try{await gn(e,n)&&await hn(e,n)}catch(e){t.logger?.warn(`Could not record a config change for ${n}:`,e)}},r=e=>({afterCreate:async(t,r)=>{mn(e,r)&&await n(t.tenantId)},afterUpdate:async(t,r,i)=>{mn(e,i)&&await n(t.tenantId)},afterDelete:async e=>n(e.tenantId)});return{actions:r(`action`),hooks:r(`hook`),hookCode:r(`hookCode`),connections:r(`connection`),resourceServers:r(`resourceServer`)}}function vn(e){return{async create(t){let n={...q,waves:t.waves??[...q.waves],canary:t.canary??q.canary,failure_threshold:t.failureThreshold??q.failure_threshold,max_concurrent:t.maxConcurrent??q.max_concurrent,trigger:`manual`,root_tenant_id:t.rootTenantId??e.controlPlaneTenantId,dry_run:t.dryRun,force:t.force,planned:!1},r=Z(e),i=await r.create({kind:`config-sync`,initiated_by:t.initiatedBy,config:n});return await tn(e,i,{tenantIds:t.tenantIds}),await an(e,i.id),await r.get(i.id)??i},pause:(t,n)=>sn(e,t,n),resume:t=>cn(e,t)}}function yn(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,inheritanceShadow:s,syncDefaults:c,detachTenant:l,tenantMemberRequests:u,rolloutExecutor:d,sync:f={resourceServers:!0,roles:!0},defaultPermissions:m=[`tenant:admin`],requireOrganizationMatch:h=!1,managementApiExtensions:_=[],entityHooks:y,getChildTenantIds:b,getAdapters:x,...S}=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 C=n,w=n,T;if(r){let t=fe({base:ve({controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),getTenant:async e=>await n.tenants.get(e)??null,controlPlaneTenantId:i,ttlMs:e.configSyncCacheTtlMs});T=e=>t.invalidate(e),C=Ce(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o,inheritanceShadow:s,configSync:t}),w={...be(n,{controlPlaneTenantId:i,resolveControlPlane:t.resolve}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:t.resolve}}}let E=S.tenantOperationExecutor,ee,D;if(n.tenantOperations&&n.tenantOperationEvents){let e={tenantOperations:n.tenantOperations,tenantOperationEvents:n.tenantOperationEvents},r=S.tenantUpgrade,a=p(e),s=c??Qe(n,{controlPlaneTenantId:i,resolveControlPlane:o}),d=l??lt(n),f=u?u.store??ft(n):void 0,m=g({stores:e,definitions:{detach:e=>[{name:`detach`,run:()=>it({operation:e,detachTenant:d,recorder:a,onDetached:e=>T?.(e)})}],...r?{upgrade:e=>[{name:`upgrade`,async run(){if(!e.tenant_id)throw Error(`upgrade operations require a tenant_id`);await r(e.tenant_id)}}]}:{},"sync-defaults":e=>[{name:`sync-defaults`,run:()=>Ze({operation:e,syncConfig:s,recorder:a})}],...f&&u?{"tenant-members-request":e=>[{name:`tenant-members-request`,run:()=>mt({operation:e,store:f,getBackend:u.getBackend,recorder:a,executeOptions:{isRequesterAllowed:u.isRequesterAllowed}})}]}:{}}});if(ee=m,f){let r={stores:e,executor:m};D={enqueue:(e,t)=>gt(r,e,t),reconcile:(e={})=>_t({...r,store:f,tenantIds:e.tenantIds??(async()=>(await(0,t.fetchAll)(e=>n.tenants.list(e),`tenants`,{cursorField:`id`,pageSize:100})).map(e=>e.id).filter(e=>e!==i)),graceMs:e.graceMs,maxAttempts:e.maxAttempts})}}E??={engine:m.engine,kinds:r?[`upgrade`,`sync-defaults`,`detach`]:[`sync-defaults`,`detach`],enqueue:t=>v(e,m,{...t,tenant_id:t.tenant_id},{returnFailed:t.kind===`sync-defaults`||t.kind===`detach`})}}if(u&&!D)throw Error("initMultiTenant: `tenantMemberRequests` requires the `tenantOperations` and `tenantOperationEvents` adapters on the data adapter, which run the `tenant-members-request` operation.");let O=d??ee,k=O&&n.rollouts&&n.tenantOperations&&n.tenantOperationEvents?{adapters:n,executor:O,controlPlaneTenantId:i,resolveControlPlane:o}:void 0,A=k?vn(k):void 0,j=k?_n(k,{logger:console}):void 0,te=f!==!1,ne=te?{resourceServers:f.resourceServers??!0,roles:f.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:M,tenantHooks:N}=Ot({controlPlaneTenantId:i,getChildTenantIds:b??(async()=>(await(0,t.fetchAll)(e=>C.tenants.list(e),`tenants`,{cursorField:`id`,pageSize:100})).filter(e=>e.id!==i).map(e=>e.id)),getAdapters:x??(async()=>C),getControlPlaneAdapters:async()=>C,sync:ne}),re={resourceServers:[M.resourceServers,j?.resourceServers,...y?.resourceServers??[]],roles:[M.roles,...y?.roles??[]],connections:[j?.connections,...y?.connections??[]],tenants:y?.tenants??[],rolePermissions:y?.rolePermissions??[],actions:[j?.actions,...y?.actions??[]],hooks:[j?.hooks,...y?.hooks??[]],hookCode:[j?.hookCode,...y?.hookCode??[]]},P=yt({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:h,defaultPermissions:m}}),ie=G({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:h,defaultPermissions:m},onConfigSyncChange:e=>T?.(e),configSyncStatus:e=>fn({adapters:n,controlPlaneTenantId:i,resolveControlPlane:o},e),verifyConfigSync:e=>dn({adapters:n,controlPlaneTenantId:i,resolveControlPlane:o,syncConfig:c??Qe(n,{controlPlaneTenantId:i,resolveControlPlane:o})},e)},{tenants:{async beforeCreate(e,t){return P.beforeCreate&&(t=await P.beforeCreate(e,t)),N.beforeCreate&&(t=await N.beforeCreate(e,t)),t},async afterCreate(e,t){await P.afterCreate?.(e,t),await N.afterCreate?.(e,t)},async beforeDelete(e,t){await P.beforeDelete?.(e,t),await N.beforeDelete?.(e,t)}}}),{app:ae}=(0,t.init)({dataAdapter:C,managementDataAdapter:w,...S,tenantOperationExecutor:E,...A?{rolloutController:A}:{},entityHooks:re,managementApiExtensions:[..._,{path:`/tenants`,router:ie}],managementApiMiddleware:[...S.managementApiMiddleware??[],...te?[Wt()]:[]]});return{app:ae,controlPlaneTenantId:i,rollouts:k,memberRequests:D}}function bn(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function xn(e,n,r={},i){let a=w(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await O(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(bn):[],u=s?await Sn(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(ee),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function Sn(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 Cn(e,n,r){let i=T();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 D(i,`signing_key ${t.kid}`,r,async()=>{let e=bn(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function wn(e,t,n){let r=T();for(let i of e)await D(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 Tn(e,n,r,i={}){let a=i.continueOnError??!1,o=w(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 wn(e.tenants??[],n,a):T(),d=E(r);await k(l,n,r,o,a,d);let f=s?await Cn(e.signingKeys,n,a):T(),p=e.resolved&&i.resolved?await Ve(e.resolved,n,i.resolved.tenantId,{continueOnError:a,...i.resolved}):void 0;return{...d,signingKeys:f,tenants:u,...p?{resolved:p}:{}}}function En(e){return{syncDefaults:t=>A(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await A(e,r));return n}}}function Dn(e){let t=On(e);return{name:`multi-tenancy`,middleware:Yt(e),hooks:t,routes:[{path:`/management`,handler:G(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 On(e){let t=e.accessControl?a(e.accessControl):{},n=e.databaseIsolation?s(e.databaseIsolation):{},r=yt(e);return{...t,...n,tenants:r}}function kn(t){let n=new e.Hono,r=On(t);return n.route(`/tenants`,G(t,r)),n}function An(e){return{hooks:On(e),middleware:Yt(e),app:kn(e),config:e,wrapAdapters:(t,n)=>Ce(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.DEFAULT_ROLLOUT_SETTINGS=q,exports.DEFAULT_ROLLOUT_WAVES=Xt,exports.MAX_MEMBER_REQUEST_ATTEMPTS=ht,exports.advanceRollout=an,exports.advanceRollouts=on,exports.applyControlPlaneDefaultsPayload=Tn,exports.applyResolvedConfigBlock=Ve,exports.assertDetachEligible=ot,exports.assignWaves=Zt,exports.buildControlPlaneDefaultsPayload=xn,exports.buildEngineInstanceId=u,exports.buildResolvedConfigBlock=Le,exports.compareShadow=se,exports.computeLegacyConfig=C,exports.createAccessControlHooks=a,exports.createAccessControlMiddleware=Kt,exports.createConfigSyncResolver=fe,exports.createControlPlaneTenantMiddleware=Gt,exports.createDatabaseHooks=s,exports.createDatabaseMiddleware=Jt,exports.createDirectRolloutAdapter=En,exports.createExpectedHash=X,exports.createInProcessDetach=lt,exports.createInProcessMemberRequestStore=ft,exports.createInProcessSyncConfig=Qe,exports.createInlineExecutor=g,exports.createMultiTenancy=kn,exports.createMultiTenancyHooks=On,exports.createMultiTenancyMiddleware=Yt,exports.createMultiTenancyPlugin=Dn,exports.createOperationRecorder=p,exports.createOperationRow=_,exports.createProtectSyncedMiddleware=Wt,exports.createProvisioningHooks=yt,exports.createRolloutController=vn,exports.createRolloutWriteHooks=_n,exports.createRuntimeFallbackAdapter=xe,exports.createShadowReporter=ue,exports.createSubdomainMiddleware=qt,exports.createSyncHooks=Ot,exports.createTenantsOpenAPIRouter=G,exports.detachErrors=nt,exports.detachOptionsOf=$e,exports.detachTenantRows=ct,exports.diffConfig=oe,exports.effectiveOverride=Te,exports.effectiveScope=I,exports.emptyDetachResult=at,exports.enqueueTenantMemberRequest=gt,exports.enqueueTenantOperation=v,exports.errorToMessage=f,exports.findUndecryptableKeyIds=Be,exports.getConfigSyncStatus=fn,exports.initMultiTenant=yn,exports.inlineStepRunner=h,exports.isPublishedRow=mn,exports.isTerminalStatus=m,exports.listRolloutOperations=Q,exports.listSyncedDescendants=Qt,exports.markTenantDetached=st,exports.memberRequestIdOf=U,exports.mergeClientWithFallback=_e,exports.mergeConfig=Me,exports.pauseRollout=sn,exports.planRollout=tn,exports.projectControlPlaneDefaults=A,exports.readConfigRows=j,exports.readRolloutConfig=J,exports.reconcileConfigDrift=pn,exports.reconcileTenantMemberRequests=_t,exports.requestRollout=hn,exports.resolveTenantChain=b,exports.resumeRollout=cn,exports.runDetachStep=it,exports.runRecordedTenantOperation=dt,exports.runSyncDefaultsStep=Ze,exports.runTenantMembersRequestStep=mt,exports.setupMultiTenancy=An,exports.summarizeDetachResult=rt,exports.summarizeSyncResult=Xe,exports.syncErrors=qe,exports.syncOptionsOf=Ke,exports.syncedRowId=L,exports.validateTenantAccess=o,exports.verifyTenantConfig=dn,exports.withRuntimeFallback=Ce,exports.withSystemResourceServerInheritance=be;