@authhero/multi-tenancy 15.3.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.
- package/dist/multi-tenancy.cjs +1 -1
- package/dist/multi-tenancy.mjs +1366 -621
- package/dist/types/inheritance/report.d.ts +6 -2
- package/dist/types/inheritance/report.d.ts.map +1 -1
- package/dist/types/init.d.ts +57 -2
- package/dist/types/init.d.ts.map +1 -1
- package/dist/types/middleware/config-sync-mode.d.ts +4 -1
- package/dist/types/middleware/config-sync-mode.d.ts.map +1 -1
- package/dist/types/operations/detach.d.ts +85 -0
- package/dist/types/operations/detach.d.ts.map +1 -0
- package/dist/types/operations/index.d.ts +4 -0
- package/dist/types/operations/index.d.ts.map +1 -1
- package/dist/types/operations/sync-defaults.d.ts +4 -1
- package/dist/types/operations/sync-defaults.d.ts.map +1 -1
- package/dist/types/operations/tenant-members-request.d.ts +97 -0
- package/dist/types/operations/tenant-members-request.d.ts.map +1 -0
- package/dist/types/rollout/resolved-sync.d.ts +21 -0
- package/dist/types/rollout/resolved-sync.d.ts.map +1 -1
- package/dist/types/rollouts/index.d.ts +2 -0
- package/dist/types/rollouts/index.d.ts.map +1 -1
- package/dist/types/rollouts/status.d.ts +1 -1
- package/dist/types/rollouts/status.d.ts.map +1 -1
- package/dist/types/rollouts/verify.d.ts +50 -0
- package/dist/types/rollouts/verify.d.ts.map +1 -0
- package/dist/types/routes/tenants.d.ts.map +1 -1
- package/dist/types/types.d.ts +9 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/tenant-settings.d.ts +13 -0
- package/dist/types/utils/tenant-settings.d.ts.map +1 -0
- package/package.json +5 -5
package/dist/multi-tenancy.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("hono"),t=require("authhero"),n=require("hono/http-exception"),r=require("@hono/zod-openapi");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 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: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,input:t.input}),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,r={}){let i=f(e),a=await g(e,n,t.engine);try{await t.start(a)}catch(t){let n=null;try{let r=await e.tenantOperations.get(a.id);r&&!p(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 v(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 y(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 b(e){let t={};for(let n of e??[])n.value!==void 0&&(t[n.name]=n.value);return t}function x(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={...b(n.secrets),...b(e.secrets)};return{...e,code:n.code,secrets:Object.entries(r).map(([e,t])=>({name:e,value:t}))}}function ee(e,t){if(!t)return e;let n=new Set(e.hooks.map(e=>e.hook_id)),r=t.hooks.filter(e=>be(e)&&!n.has(e.hook_id));return{connections:e.connections.map(e=>P(e,t.connections)),resourceServers:e.resourceServers.map(e=>e.is_system?me(e,t.resourceServers.find(t=>t.id===e.id)??null):e),hooks:[...e.hooks,...r],hookCode:e.hookCode,actions:e.actions.map(e=>x(e,t.actions)),emailProvider:e.emailProvider??t.emailProvider,branding:e.branding,promptSettings:e.promptSettings}}function S(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 C(){return{upserted:0,errors:[]}}function w(e){return{tenantId:e,connections:C(),resourceServers:C(),hooks:C(),emailProvider:C(),branding:C(),promptSettings:C()}}function T(e){let t=e.metadata;return!!(t&&t.inheritable===!0)}async function E(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 D(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 O(e,n,r,i,a,o){if(i.connections)for(let i of e.connections){let e=i.id;e&&await E(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 E(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)!T(i)||!i.hook_id||await E(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 E(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 E(o.branding,`branding`,a,async()=>{await n.branding.set(r,e.branding),o.branding.upserted+=1}),i.promptSettings&&e.promptSettings&&await E(o.promptSettings,`prompt_settings`,a,async()=>{await n.promptSettings.set(r,e.promptSettings),o.promptSettings.upserted+=1})}async function k(e,t){let{controlPlaneTenantId:n,getControlPlaneAdapters:r,getAdapters:i,entities:a,continueOnError:o=!1}=e,s=S(a),c=await D(await r(),n,s),l=await i(t),u=w(t);return await O(c,l,n,s,o,u),u}async function A(e,n){let r=await D(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,j=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 ne(e){let t={};for(let[n,r]of Object.entries(e))j.has(n)||(t[n]=r);return await N(t)}var re={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 ne(r)),t.set(e,i)};for(let[t,r]of Object.entries(re)){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 y({tenantId:n,getTenant:e=>t.tenants.get(e),legacyControlPlane:r,maxDepth:e.maxDepth}),a=await A(t,n),o=await Promise.all(i.map(e=>A(t,e))),s=r&&r!==n?await A(t,r):void 0,{hidden:c,...l}=Ae(o,a),u=new Set(c);return(await oe(ee(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);c!==void 0&&o-c<r||(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??3e4,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))?.config_sync===`synced`;return o.size>=a&&o.clear(),o.set(e,{synced:t,expires:s+i}),t}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 P(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 F(e,t){let n=[...t||[],...e||[]];return[...new Set(n)]}function pe(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 me(e,t){return t?{...e,scopes:pe(e.scopes,t.scopes)}:e}function he(e,t){return t?{...e,callbacks:F(e.callbacks,t.callbacks),web_origins:F(e.web_origins,t.web_origins),allowed_logout_urls:F(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:F(e.allowed_origins,t.allowed_origins)}:e}function ge(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 _e(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:me(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?me(e,c.get(e.id)??null):e);return{...i,resource_servers:l}}}}function ve(e,t){let n=ge({controlPlaneTenantId:t.controlPlaneTenantId,resolveControlPlane:t.resolveControlPlane});return{...e,resourceServers:_e(e,n)}}function ye(e,t){let{controlPlaneTenantId:n,controlPlaneClientId:r,resolveControlPlane:i,inheritanceShadow:a}=t,o=t.configSync??fe({base:ge({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:P(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=>P(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=>P(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:_e(e,l),hooks:xe(e,l)}}function be(e){if(!e||typeof e!=`object`)return!1;let t=e.metadata;return!t||typeof t!=`object`?!1:t.inheritable===!0}function xe(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(be);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 z(`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&&be(o)?o:null}}}function Se(e,t){return ye(e,t)}var Ce=()=>({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 be(t)?`shared`:`local`;default:return`local`}}function L(e){return e.override??`fields`}var we=/secret|password|private_key|api_key|token/i;function Te(e,t){let n={...e??{}};for(let[e,r]of Object.entries(t??{}))we.test(e)&&(n[e]=r);return n}function Ee(e,t){switch(L(e)){case`none`:return{...e,id:t.id};case`secrets`:return{...e,id:t.id,options:Te(e.options,t.options)};default:return{...e,...t,options:{...e.options??{},...t.options??{}}}}}function De(e,t){switch(L(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:pe(t.scopes,e.scopes)}}}function Oe(e){return new Map((e??[]).map(e=>[e.name,e]))}function ke(e,t){let n=L(e);if(n===`none`)return{...e,id:t.id};let r=Oe(e.secrets);if(n===`secrets`||n===`fields`)for(let[e,n]of Oe(t.secrets))r.set(e,n);return{...n===`fields`&&!t.inherit?t:e,id:t.id,secrets:[...r.values()]}}function Ae(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=Ce(),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?Ee(e,t):t):u.set(t.strategy,e?Ee(e,t):t)}for(let t of i(`resourceServer`,e.resourceServers,h,s)){let e=f.get(s(t));f.set(s(t),e?De(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?ke(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]}}function R(e){return Array.isArray(e)?`[${e.map(R).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)}:${R(t)}`).join(`,`)}}`:JSON.stringify(e)??`null`}async function je(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 Me={connection:`con_`,resourceServer:`api_`,hook:`h_`,hookCode:`hc_`,action:`act_`};async function z(e,t,n){let r=await je(`${t}|${e}|${n}`);return`${Me[e]}sy${r.slice(0,15)}`}function B(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 Ne(e,t,n={}){let r=await y({tenantId:t,getTenant:t=>e.tenants.get(t),legacyControlPlane:n.legacyControlPlane,maxDepth:n.maxDepth}),i=Ae(await Promise.all(r.map(t=>A(e,t))),Ce()),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 je(R(a))}}function Pe(e,t){if(typeof e==`string`)e.startsWith(`enc:v1:`)&&t.add(e);else if(Array.isArray(e))for(let n of e)Pe(n,t);else if(e&&typeof e==`object`)for(let n of Object.values(e))Pe(n,t)}function Fe(e){let t=e.slice(7),n=t.indexOf(`:`);return n===-1?`default`:t.slice(0,n)}async function Ie(e,n){let r=new Set;Pe(e,r);let i=new Set;for(let e of r)await(0,t.canDecrypt)(e,n)||i.add(Fe(e));return[...i].sort()}var V=()=>({added:0,changed:0,unchanged:0,deleted:0,errors:[]}),Le=e=>R(e);async function Re(e,n,r,i={}){let{dryRun:a=!1,continueOnError:o=!0}=i,s={status:a?`dry-run`:`applied`,hash:e.hash,entities:{connection:V(),resourceServer:V(),hookCode:V(),action:V(),hook:V(),emailProvider:V(),branding:V(),promptSettings:V()},changes:[]},c=await n.tenants.get(r),l=!!i.deletes&&e.deletes.length>0;if(!a&&!i.force&&!l&&c?.config_sync_hash===e.hash)return{...s,status:`up-to-date`};if(i.keyRing){let t=await Ie(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=async(e,t,n)=>{let r=s.entities[e];try{let i=await n();r[i]+=1,i!==`unchanged`&&s.changes.push(`${e}:${t}`)}catch(n){let i=`${e} ${t}: ${n instanceof Error?n.message:String(n)}`;if(!o)throw Error(i,{cause:n});r.errors.push(i)}},d=async e=>e.existing?Le(e.view(e.existing))===Le(e.view(e.desired))?`unchanged`:(a||await e.update(),`changed`):(a||await e.create(),`added`),f=(e,t)=>z(e,r,t),p=new Map;for(let t of e.hookCode)p.set(t.id,await f(`hookCode`,B(`hookCode`,t)));for(let t of e.actions)p.set(t.id,await f(`action`,B(`action`,t)));for(let i of e.connections){let e=B(`connection`,i),a=await f(`connection`,e);await u(`connection`,e,async()=>{let{enabled_clients:e,...o}=i,s=t.connectionInsertSchema.parse({...o,id:a}),c=await n.connections.get(r,a);return d({existing:c?t.connectionInsertSchema.parse(c):null,desired:s,create:()=>n.connections.create(r,s),update:()=>n.connections.update(r,a,s),view:e=>e})})}for(let i of e.resourceServers){let e=B(`resourceServer`,i),a=await f(`resourceServer`,e);await u(`resourceServer`,e,async()=>{let e=t.resourceServerInsertSchema.parse({...i,id:a}),o=await n.resourceServers.get(r,a);return d({existing:o?t.resourceServerInsertSchema.parse(o):null,desired:e,create:()=>n.resourceServers.create(r,e),update:()=>n.resourceServers.update(r,a,e),view:e=>e})})}for(let i of e.hookCode){let e=B(`hookCode`,i),a=p.get(i.id);await u(`hookCode`,e,async()=>{let e=t.hookCodeInsertSchema.parse(i),o=await n.hookCode.get(r,a);return d({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=B(`action`,i),a=p.get(i.id);await u(`action`,e,async()=>{let e=t.actionInsertSchema.parse(i),o=await n.actions.get(r,a);return d({existing:o?t.actionInsertSchema.parse(o):null,desired:e,create:()=>n.actions.create(r,e,{importMetadata:{id:a}}),update:()=>n.actions.update(r,a,e),view:e=>e})})}for(let i of e.hooks){let e=B(`hook`,i),a=await f(`hook`,e);await u(`hook`,e,async()=>{let e=i.code_id,o=t.hookInsertSchema.parse({...i,hook_id:a,...e?{code_id:p.get(e)??e}:{}}),s=await n.hooks.get(r,a);return d({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})})}e.emailProvider&&await u(`emailProvider`,`singleton`,async()=>{let i=t.emailProviderSchema.parse(e.emailProvider);return await n.emailProviders.get(r)?`unchanged`:(a||await n.emailProviders.create(r,i),`added`)}),e.branding&&await u(`branding`,`singleton`,async()=>{let i=t.brandingSchema.parse(e.branding);return await n.branding.get(r)?`unchanged`:(a||await n.branding.set(r,i),`added`)});for(let t of e.deletes){let e=await f(t.entity,t.key),o=`${t.entity}:${t.key}`;try{if(!await ze(n,r,t.entity,e))continue;s.changes.push(`delete ${o}`),i.deletes&&!a&&(await Be(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 m=Object.values(s.entities).some(e=>e.errors.length>0);return!a&&!m&&c&&await n.tenants.update(r,{config_sync_hash:e.hash,config_synced_at:new Date().toISOString()}),s}async function ze(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 Be(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 Ve(e){let t=e.input??{};return{dryRun:t.dry_run===!0,force:t.force===!0}}function He(e){return Object.values(e.entities).flatMap(e=>e.errors)}function Ue(e,t){return{dry_run:t.dryRun,status:e.status,hash:e.hash,changes:e.changes,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 We(e){let{operation:t,syncConfig:n,recorder:r}=e;if(!t.tenant_id)throw Error(`sync-defaults operations require a tenant_id`);let i=Ve(t),a=await n(t.tenant_id,i),o=Ue(a,i);await r.setResult(t.id,o);let s=He(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 Ge(e,t){return async(n,r)=>{let i=await e.tenants.get(n);if(!i)throw Error(`Tenant "${n}" not found`);if(i.deployment_type===`wfp`)throw Error(`Tenant "${n}" has its own database: configure a dispatch sync (syncDefaults) for it`);return Re(await Ne(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})}}function Ke(e){if(e.tenantOperations&&e.tenantOperationEvents)return{tenantOperations:e.tenantOperations,tenantOperationEvents:e.tenantOperationEvents}}async function qe(e,t,n){let r=Ke(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 Je(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function Ye(e){return{async beforeCreate(e,t){return!t.audience&&t.id?{...t,audience:Je(t.id)}:t},async afterCreate(n,r){let{accessControl:i,databaseIsolation:a}=e;if(i&&n.ctx&&await Xe(n,r,i),a?.onProvision){let e=a.onProvision;a.recordProvisionOperations===!1?await e(r.id):await qe(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 Xe(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 Qe(e,r,s,c)),l&&e.ctx){let t=e.ctx.var.user;if(t?.sub&&!await Ze(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 Ze(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 Qe(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 $e(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 et(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})}),nt=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 rt(e){return e.metadata?.sync!==!1}function it(e){let{sync:n={},filters:r={}}=e,i=n.resourceServers??!0,a=n.roles??!0,o=e=>rt(e)?r.resourceServers?r.resourceServers(e):!0:!1,s=e=>rt(e)?r.roles?r.roles(e):!0:!1,c=i?$e(e,tt,o):void 0,l=a?$e(e,nt,s):void 0,u=i?et(e,tt,o):void 0,d=a?et(e,nt,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 H(e){return e.var.data??e.env.data}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 ot(e){let t=at.safeParse(e);return t.success?t.data:void 0}function st(e,t,n){return t?!e||n?!1:e.tenant_id===t:!0}function ct(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 U(e,i){let a=new r.OpenAPIHono,o=t=>{let n=ot(t.var.user);return st(n,e.accessControl?.controlPlaneTenantId??H(t).multiTenancyConfig?.controlPlaneTenantId,!!(n?.org_id??t.var.organization_id??t.var.org_name))};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 H(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??H(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=>H(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 H(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 H(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:H(t),ctx:t};i.tenants?.beforeCreate&&(l=await i.tenants.beforeCreate(u,l)),await v({tenantId:l.id,parentTenantId:l.parent_tenant_id,getTenant:e=>H(t).tenants.get(e)});let d=await H(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??H(r).multiTenancyConfig?.controlPlaneTenantId;if(o){let e=ot(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&&ct(e)&&(c=!0)}if(c||=(await(0,t.fetchAll)(t=>H(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 H(r).tenants.get(a))throw new n.HTTPException(404,{message:`Tenant not found`});let s={adapters:H(r),ctx:r};return i.tenants?.beforeDelete&&await i.tenants.beforeDelete(s,a),await H(r).tenants.remove(a),i.tenants?.afterDelete&&await i.tenants.afterDelete(s,a),r.body(null,204)}),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`]),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 H(e).tenants.get(e.var.tenant_id);if(!t)throw new n.HTTPException(404,{message:`Tenant not found`});return e.json(t)}),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:s,...c}=r.req.valid(`json`),l=await H(r).tenants.get(r.var.tenant_id);if(!l)throw new n.HTTPException(404,{message:`Tenant not found`});if(`config_sync`in c&&(c.config_sync??`inherit-on-read`)!==(l.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 c){let e=c.default_client_id;if(typeof e==`string`&&e.length>0){let i=await H(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 c){if((c.parent_tenant_id??null)!==(l.parent_tenant_id??null)&&!o(r))throw new n.HTTPException(403,{message:`Only the control plane can change a tenant's parent`});await v({tenantId:r.var.tenant_id,parentTenantId:c.parent_tenant_id,getTenant:e=>H(r).tenants.get(e),getChildren:async e=>(await(0,t.fetchAll)(e=>H(r).tenants.list(e),`tenants`)).filter(t=>t.parent_tenant_id===e).map(e=>e.id)})}let u=(0,t.deepMergePatch)(l,c);await H(r).tenants.update(r.var.tenant_id,u),`config_sync`in c&&e.onConfigSyncChange?.(r.var.tenant_id);let d=await H(r).tenants.get(r.var.tenant_id);if(!d)throw new n.HTTPException(500,{message:`Failed to retrieve updated tenant`});return r.json(d)}),a}function lt(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 ut(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 dt(e){return{resource_server:`resource server`,role:`role`,connection:`connection`}[e]}function ft(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 pt(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 mt={connection:[`options`],resource_server:[`signing_secret`],action:[`secrets`],hook:[],hook_code:[]},ht=new Set([`client_secret`,`app_secret`,`twilio_token`]);function gt(e,t){let n=e=>{let{client_secret:t,...n}=e??{};return n};return W(n(e),n(t))}var W=(e,t)=>JSON.stringify(e)===JSON.stringify(t);function G(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 _t(e,t,n){let r=await pt(H(e),t,n);if(!r)return;if(n.type===`hook_code`)throw G(n,`cannot be modified`);if(e.req.method===`DELETE`){if(r.enforce===!0)throw G(n,`cannot be deleted`);return}let i=r.override??`fields`;if(i===`none`)throw G(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&&!W(a[e]??null,r[e]??null))throw G(n,`has a locked ${e}`);if(r.enforce===!0&&a.enabled===!1)throw G(n,`cannot be disabled`);if(i===`secrets`){let e=mt[n.type];for(let[t,i]of Object.entries(a))if(![`scope`,`override`,`enforce`].includes(t)&&!W(i,r[t])){if(!e.includes(t))throw G(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(!W(r,e[t])&&!t.endsWith(`_hint`)&&!(ht.has(t)||t===`configuration`&>(r,e[t])))throw G(n,`only allows its secrets to be changed (not options.${t})`)}}}}function vt(){return async(e,r)=>{if(![`PATCH`,`PUT`,`DELETE`].includes(e.req.method))return r();let i=lt(e.req.path),a=ft(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 ut(H(e),o,i))throw new n.HTTPException(403,{message:`This ${dt(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 _t(e,o,a),r()}}function yt(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 bt(e){return async(r,i)=>{if(!e.accessControl)return i();let{controlPlaneTenantId:o}=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(!a(c,u,o,s))throw new n.HTTPException(403,{message:`Access denied to tenant ${u}`});return i()}}function xt(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 H(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 St(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 Ct(e){let t=xt(e),n=bt(e),r=St(e);return async(e,i)=>(await t(e,async()=>{}),await n(e,async()=>{}),await r(e,async()=>{}),i())}var wt=[10,50,100],K={canary:1,waves:wt,failure_threshold:.1,max_concurrent:25,debounce_ms:6e4};function q(e){let t=e.config??{};return{...K,trigger:`manual`,root_tenant_id:``,...t,waves:Array.isArray(t.waves)&&t.waves.length>0?t.waves:[...wt]}}function Tt(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 Et(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 J(e,t){return e.resolveControlPlane?(await e.resolveControlPlane({tenant_id:t}))?.tenantId:e.controlPlaneTenantId}function Y(e){let t=new Map;return async n=>{let r=await J(e,n),i=(await y({tenantId:n,getTenant:t=>e.adapters.tenants.get(t),legacyControlPlane:r,maxDepth:e.maxDepth})).join(`>`),a=t.get(i);return a||(a=Ne(e.adapters,n,{legacyControlPlane:r,maxDepth:e.maxDepth}).then(e=>e.hash),t.set(i,a)),a}}var Dt=[`pending`,`canary`,`rolling`,`paused`];function X(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 Ot(e,t,n={}){let r=Z(e),i=X(e),a=q(t),o=await Et(e.adapters,a.root_tenant_id,{resolveLegacyParent:t=>J(e,t),maxDepth:e.maxDepth});if(n.tenantIds){let e=new Set(n.tenantIds);o=o.filter(t=>e.has(t.tenantId))}let s=Y(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=Tt(c.length,a.canary,a.waves);for(let[n,r]of c.entries())u.has(r.tenantId)||await g(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}=X(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},kt=e=>e.status===`failed`||e.status===`cancelled`;function At(e,t,n){let r=t.filter(e=>$(e)===n),i=r.filter(kt).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 jt(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(!Dt.includes(i.status)||i.status===`paused`)return{rolloutId:a,outcome:`skipped`,started:0};let o=q(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 Ot(e,i);if(t===0)return{rolloutId:a,outcome:`planned-empty`,started:0};i=await n.get(a)??i,o=q(i)}let s=await Q(e,a),c=s.filter(e=>!p(e.status));if(c.length===0){let e=Math.max(0,...s.map($)),t=s.length>0&&e>(o.accepted_through??-1)?At(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=At(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 m=c.filter(e=>$(e)===l),h=m.filter(e=>e.status===`running`).length,g=Math.max(0,o.max_concurrent-h),{tenantOperations:_,tenantOperationEvents:v}=X(e),y=f({tenantOperations:_,tenantOperationEvents:v}),b=0;for(let t of m.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&&!p(n.status)&&await y.markFailed(t.id,e)}catch{}}b++}return{rolloutId:a,outcome:b>0?`started`:`running`,started:b,wave:l}}async function Mt(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 jt(e,i))}catch(e){t.logger?.warn(`Advancing rollout ${i.id} failed:`,e)}return r}async function Nt(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 Pt(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=q(r),a=(await Q(e,t)).filter(e=>!p(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)}async function Ft(e,n){let r=await e.adapters.tenants.get(n);if(!r)return null;let i=r.config_sync===`synced`,a=await y({tenantId:n,getTenant:t=>e.adapters.tenants.get(t),legacyControlPlane:await J(e,n),maxDepth:e.maxDepth}),o=i?await Y(e)(n):null,s=r.config_sync_hash??null,c={};for(let r of[...a].reverse()){let i=await A(e.adapters,r),a=(e,t)=>I(e,t)===`shared`,o=async(e,i,o)=>{for(let s of i){let i=s.id??s.hook_id;i&&(0,t.isSyncedRowId)(i)||a(o,s)&&(c[await z(e,n,B(e,s))]=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 It(e,n={}){let r=Z(e),i=n.rootTenantId??e.controlPlaneTenantId,a=n.limit??500,o=await Et(e.adapters,i,{resolveLegacyParent:t=>J(e,t),maxDepth:e.maxDepth}),s=Y(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:[...Dt],per_page:100});for(let t of d)for(let n of await Q(e,t.id))n.tenant_id&&!p(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:m}=X(e),h=e.now?.()??Date.now(),g=n.retryAfterMs??36e5,_=[];for(let e of f){try{let{operations:t}=await m.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:{...K,trigger:`reconcile`,root_tenant_id:i,planned:!1}});return await Ot(e,v,{tenantIds:_.map(e=>e.tenantId)}),l.rolloutId=v.id,l}function Lt(e,t){return e===`hookCode`?!0:!t||typeof t!=`object`?!1:I(e,t)!==`local`}async function Rt(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=q(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:{...K,trigger:`write`,root_tenant_id:t,origin_tenant_id:t,planned:!1}})}async function zt(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 Bt(e,t={}){let n=async n=>{try{await zt(e,n)&&await Rt(e,n)}catch(e){t.logger?.warn(`Could not record a config change for ${n}:`,e)}},r=e=>({afterCreate:async(t,r)=>{Lt(e,r)&&await n(t.tenantId)},afterUpdate:async(t,r,i)=>{Lt(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 Vt(e){return{async create(t){let n={...K,waves:t.waves??[...K.waves],canary:t.canary??K.canary,failure_threshold:t.failureThreshold??K.failure_threshold,max_concurrent:t.maxConcurrent??K.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 Ot(e,i,{tenantIds:t.tenantIds}),await jt(e,i.id),await r.get(i.id)??i},pause:(t,n)=>Nt(e,t,n),resume:t=>Pt(e,t)}}function Ht(e){let{dataAdapter:n,controlPlane:r,controlPlane:{tenantId:i=`control_plane`,clientId:a}={},resolveControlPlane:o,inheritanceShadow:s,syncDefaults:c,rolloutExecutor:l,sync:u={resourceServers:!0,roles:!0},defaultPermissions:d=[`tenant:admin`],requireOrganizationMatch:p=!1,managementApiExtensions:m=[],entityHooks:g,getChildTenantIds:v,getAdapters:y,...b}=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 x=n,ee=n,S;if(r){let e=fe({base:ge({controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o}),getTenant:async e=>await n.tenants.get(e)??null,controlPlaneTenantId:i});S=t=>e.invalidate(t),x=Se(n,{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:o,inheritanceShadow:s,configSync:e}),ee={...ve(n,{controlPlaneTenantId:i,resolveControlPlane:e.resolve}),multiTenancyConfig:{controlPlaneTenantId:i,controlPlaneClientId:a,resolveControlPlane:e.resolve}}}let C=b.tenantOperationExecutor,w;if(n.tenantOperations&&n.tenantOperationEvents){let e={tenantOperations:n.tenantOperations,tenantOperationEvents:n.tenantOperationEvents},t=b.tenantUpgrade,r=f(e),a=c??Ge(n,{controlPlaneTenantId:i,resolveControlPlane:o}),s=h({stores:e,definitions:{...t?{upgrade:e=>[{name:`upgrade`,async run(){if(!e.tenant_id)throw Error(`upgrade operations require a tenant_id`);await t(e.tenant_id)}}]}:{},"sync-defaults":e=>[{name:`sync-defaults`,run:()=>We({operation:e,syncConfig:a,recorder:r})}]}});w=s,C??={engine:s.engine,kinds:t?[`upgrade`,`sync-defaults`]:[`sync-defaults`],enqueue:t=>_(e,s,{...t,tenant_id:t.tenant_id},{returnFailed:t.kind===`sync-defaults`})}}let T=l??w,E=T&&n.rollouts&&n.tenantOperations&&n.tenantOperationEvents?{adapters:n,executor:T,controlPlaneTenantId:i,resolveControlPlane:o}:void 0,D=E?Vt(E):void 0,O=E?Bt(E,{logger:console}):void 0,k=u!==!1,A=k?{resourceServers:u.resourceServers??!0,roles:u.roles??!0}:{resourceServers:!1,roles:!1},{entityHooks:te,tenantHooks:j}=it({controlPlaneTenantId:i,getChildTenantIds:v??(async()=>(await(0,t.fetchAll)(e=>x.tenants.list(e),`tenants`,{cursorField:`id`,pageSize:100})).filter(e=>e.id!==i).map(e=>e.id)),getAdapters:y??(async()=>x),getControlPlaneAdapters:async()=>x,sync:A}),M={resourceServers:[te.resourceServers,O?.resourceServers,...g?.resourceServers??[]],roles:[te.roles,...g?.roles??[]],connections:[O?.connections,...g?.connections??[]],tenants:g?.tenants??[],rolePermissions:g?.rolePermissions??[],actions:[O?.actions,...g?.actions??[]],hooks:[O?.hooks,...g?.hooks??[]],hookCode:[O?.hookCode,...g?.hookCode??[]]},N=Ye({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:p,defaultPermissions:d}}),ne=U({accessControl:{controlPlaneTenantId:i,requireOrganizationMatch:p,defaultPermissions:d},onConfigSyncChange:e=>S?.(e),configSyncStatus:e=>Ft({adapters:n,controlPlaneTenantId:i,resolveControlPlane:o},e)},{tenants:{async beforeCreate(e,t){return N.beforeCreate&&(t=await N.beforeCreate(e,t)),j.beforeCreate&&(t=await j.beforeCreate(e,t)),t},async afterCreate(e,t){await N.afterCreate?.(e,t),await j.afterCreate?.(e,t)},async beforeDelete(e,t){await N.beforeDelete?.(e,t),await j.beforeDelete?.(e,t)}}}),{app:re}=(0,t.init)({dataAdapter:x,managementDataAdapter:ee,...b,tenantOperationExecutor:C,...D?{rolloutController:D}:{},entityHooks:M,managementApiExtensions:[...m,{path:`/tenants`,router:ne}],managementApiMiddleware:[...b.managementApiMiddleware??[],...k?[vt()]:[]]});return{app:re,controlPlaneTenantId:i,rollouts:E}}function Ut(e){let{pkcs7:t,tenant_id:n,...r}=e;return r}async function Wt(e,n,r={},i){let a=S(r),o=r.signingKeys??!0,s=r.tenants??!0,c=await D(e,n,a),l=o?(await(0,t.listControlPlaneKeys)(e.keys)).map(Ut):[],u=s?await Gt(e,n,i):[];return{connections:c.connections,resourceServers:c.resourceServers.filter(e=>e.is_system),hooks:c.hooks.filter(T),emailProvider:c.emailProvider,branding:c.branding,promptSettings:c.promptSettings,signingKeys:l,tenants:u}}async function Gt(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 Kt(e,n,r){let i=C();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 E(i,`signing_key ${t.kid}`,r,async()=>{let e=Ut(t);o.has(e.kid)||(await n.keys.create(e),o.add(e.kid),i.upserted+=1)});return i}async function qt(e,t,n){let r=C();for(let i of e)await E(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 Jt(e,n,r,i={}){let a=i.continueOnError??!1,o=S(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 qt(e.tenants??[],n,a):C(),d=w(r);await O(l,n,r,o,a,d);let f=s?await Kt(e.signingKeys,n,a):C(),p=e.resolved&&i.resolved?await Re(e.resolved,n,i.resolved.tenantId,{continueOnError:a,...i.resolved}):void 0;return{...d,signingKeys:f,tenants:u,...p?{resolved:p}:{}}}function Yt(e){return{syncDefaults:t=>k(e,t),syncDefaultsToTenants:async t=>{let n=[];for(let r of t)n.push(await k(e,r));return n}}}function Xt(e){let t=Zt(e);return{name:`multi-tenancy`,middleware:Ct(e),hooks:t,routes:[{path:`/management`,handler:U(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 Zt(e){let t=e.accessControl?i(e.accessControl):{},n=e.databaseIsolation?o(e.databaseIsolation):{},r=Ye(e);return{...t,...n,tenants:r}}function Qt(t){let n=new e.Hono,r=Zt(t);return n.route(`/tenants`,U(t,r)),n}function $t(e){return{hooks:Zt(e),middleware:Ct(e),app:Qt(e),config:e,wrapAdapters:(t,n)=>Se(t,{controlPlaneTenantId:e.accessControl?.controlPlaneTenantId,controlPlaneClientId:n?.controlPlaneClientId})}}exports.DEFAULT_ROLLOUT_SETTINGS=K,exports.DEFAULT_ROLLOUT_WAVES=wt,exports.advanceRollout=jt,exports.advanceRollouts=Mt,exports.applyControlPlaneDefaultsPayload=Jt,exports.applyResolvedConfigBlock=Re,exports.assignWaves=Tt,exports.buildControlPlaneDefaultsPayload=Wt,exports.buildEngineInstanceId=l,exports.buildResolvedConfigBlock=Ne,exports.compareShadow=se,exports.computeLegacyConfig=ee,exports.createAccessControlHooks=i,exports.createAccessControlMiddleware=bt,exports.createConfigSyncResolver=fe,exports.createControlPlaneTenantMiddleware=yt,exports.createDatabaseHooks=o,exports.createDatabaseMiddleware=St,exports.createDirectRolloutAdapter=Yt,exports.createExpectedHash=Y,exports.createInProcessSyncConfig=Ge,exports.createInlineExecutor=h,exports.createMultiTenancy=Qt,exports.createMultiTenancyHooks=Zt,exports.createMultiTenancyMiddleware=Ct,exports.createMultiTenancyPlugin=Xt,exports.createOperationRecorder=f,exports.createOperationRow=g,exports.createProtectSyncedMiddleware=vt,exports.createProvisioningHooks=Ye,exports.createRolloutController=Vt,exports.createRolloutWriteHooks=Bt,exports.createRuntimeFallbackAdapter=ye,exports.createShadowReporter=ue,exports.createSubdomainMiddleware=xt,exports.createSyncHooks=it,exports.createTenantsOpenAPIRouter=U,exports.diffConfig=oe,exports.effectiveOverride=L,exports.effectiveScope=I,exports.enqueueTenantOperation=_,exports.errorToMessage=d,exports.findUndecryptableKeyIds=Ie,exports.getConfigSyncStatus=Ft,exports.initMultiTenant=Ht,exports.inlineStepRunner=m,exports.isPublishedRow=Lt,exports.isTerminalStatus=p,exports.listRolloutOperations=Q,exports.listSyncedDescendants=Et,exports.mergeClientWithFallback=he,exports.mergeConfig=Ae,exports.pauseRollout=Nt,exports.planRollout=Ot,exports.projectControlPlaneDefaults=k,exports.readConfigRows=A,exports.readRolloutConfig=q,exports.reconcileConfigDrift=It,exports.requestRollout=Rt,exports.resolveTenantChain=y,exports.resumeRollout=Pt,exports.runRecordedTenantOperation=qe,exports.runSyncDefaultsStep=We,exports.setupMultiTenancy=$t,exports.summarizeSyncResult=Ue,exports.syncErrors=He,exports.syncOptionsOf=Ve,exports.syncedRowId=z,exports.validateTenantAccess=a,exports.withRuntimeFallback=Se,exports.withSystemResourceServerInheritance=ve;
|
|
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;
|