@authhero/multi-tenancy 15.2.0 → 15.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/multi-tenancy.cjs +1 -1
  2. package/dist/multi-tenancy.mjs +2251 -1204
  3. package/dist/types/index.d.ts +5 -2
  4. package/dist/types/index.d.ts.map +1 -1
  5. package/dist/types/inheritance/legacy.d.ts.map +1 -1
  6. package/dist/types/inheritance/merge.d.ts +1 -0
  7. package/dist/types/inheritance/merge.d.ts.map +1 -1
  8. package/dist/types/inheritance/read.d.ts.map +1 -1
  9. package/dist/types/inheritance/types.d.ts +3 -1
  10. package/dist/types/inheritance/types.d.ts.map +1 -1
  11. package/dist/types/init.d.ts +28 -0
  12. package/dist/types/init.d.ts.map +1 -1
  13. package/dist/types/middleware/config-sync-mode.d.ts +36 -0
  14. package/dist/types/middleware/config-sync-mode.d.ts.map +1 -0
  15. package/dist/types/middleware/index.d.ts +3 -1
  16. package/dist/types/middleware/index.d.ts.map +1 -1
  17. package/dist/types/middleware/protect-synced.d.ts +1 -1
  18. package/dist/types/middleware/protect-synced.d.ts.map +1 -1
  19. package/dist/types/middleware/settings-inheritance.d.ts +20 -2
  20. package/dist/types/middleware/settings-inheritance.d.ts.map +1 -1
  21. package/dist/types/operations/enqueue.d.ts +8 -1
  22. package/dist/types/operations/enqueue.d.ts.map +1 -1
  23. package/dist/types/operations/index.d.ts +3 -1
  24. package/dist/types/operations/index.d.ts.map +1 -1
  25. package/dist/types/operations/recorder.d.ts +2 -0
  26. package/dist/types/operations/recorder.d.ts.map +1 -1
  27. package/dist/types/operations/sync-defaults.d.ts +55 -0
  28. package/dist/types/operations/sync-defaults.d.ts.map +1 -0
  29. package/dist/types/operations/types.d.ts +2 -0
  30. package/dist/types/operations/types.d.ts.map +1 -1
  31. package/dist/types/rollout/index.d.ts +2 -0
  32. package/dist/types/rollout/index.d.ts.map +1 -1
  33. package/dist/types/rollout/payload.d.ts +15 -0
  34. package/dist/types/rollout/payload.d.ts.map +1 -1
  35. package/dist/types/rollout/resolved-sync.d.ts +91 -0
  36. package/dist/types/rollout/resolved-sync.d.ts.map +1 -0
  37. package/dist/types/rollouts/advance.d.ts +44 -0
  38. package/dist/types/rollouts/advance.d.ts.map +1 -0
  39. package/dist/types/rollouts/config.d.ts +54 -0
  40. package/dist/types/rollouts/config.d.ts.map +1 -0
  41. package/dist/types/rollouts/controller.d.ts +29 -0
  42. package/dist/types/rollouts/controller.d.ts.map +1 -0
  43. package/dist/types/rollouts/enumerate.d.ts +25 -0
  44. package/dist/types/rollouts/enumerate.d.ts.map +1 -0
  45. package/dist/types/rollouts/hashes.d.ts +10 -0
  46. package/dist/types/rollouts/hashes.d.ts.map +1 -0
  47. package/dist/types/rollouts/index.d.ts +19 -0
  48. package/dist/types/rollouts/index.d.ts.map +1 -0
  49. package/dist/types/rollouts/plan.d.ts +29 -0
  50. package/dist/types/rollouts/plan.d.ts.map +1 -0
  51. package/dist/types/rollouts/reconcile.d.ts +38 -0
  52. package/dist/types/rollouts/reconcile.d.ts.map +1 -0
  53. package/dist/types/rollouts/status.d.ts +28 -0
  54. package/dist/types/rollouts/status.d.ts.map +1 -0
  55. package/dist/types/rollouts/trigger.d.ts +52 -0
  56. package/dist/types/rollouts/trigger.d.ts.map +1 -0
  57. package/dist/types/rollouts/types.d.ts +25 -0
  58. package/dist/types/rollouts/types.d.ts.map +1 -0
  59. package/dist/types/routes/tenants.d.ts.map +1 -1
  60. package/dist/types/types.d.ts +12 -0
  61. package/dist/types/types.d.ts.map +1 -1
  62. package/dist/types/utils/tenant-tree.d.ts +2 -1
  63. package/dist/types/utils/tenant-tree.d.ts.map +1 -1
  64. package/package.json +5 -5
@@ -1,9 +1,9 @@
1
1
  import { Hono as e } from "hono";
2
- import { LogTypes as t, MANAGEMENT_API_AUDIENCE as n, MANAGEMENT_API_SCOPES as r, auth0QuerySchema as i, brandingSchema as a, connectionInsertSchema as o, connectionOptionsSchema as s, connectionSchema as c, deepMergePatch as l, emailProviderSchema as u, escapeLuceneValue as d, fetchAll as f, hookInsertSchema as p, init as m, isInteractiveClient as h, listControlPlaneKeys as g, promptSettingSchema as _, provisionDefaultClients as v, resourceServerInsertSchema as y, tenantInsertSchema as b, tenantSchema as x } from "authhero";
3
- import { OpenAPIHono as S, createRoute as C, z as w } from "@hono/zod-openapi";
4
- import { HTTPException as T } from "hono/http-exception";
2
+ import { LogTypes as t, MANAGEMENT_API_AUDIENCE as n, MANAGEMENT_API_SCOPES as r, actionInsertSchema as i, auth0QuerySchema as a, brandingSchema as o, canDecrypt as s, connectionInsertSchema as c, connectionOptionsSchema as l, connectionSchema as u, deepMergePatch as d, emailProviderSchema as f, escapeLuceneValue as p, fetchAll as m, hookCodeInsertSchema as h, hookInsertSchema as g, init as _, isInteractiveClient as v, isSyncedRowId as y, listControlPlaneKeys as b, promptSettingSchema as ee, provisionDefaultClients as te, resourceServerInsertSchema as x, tenantInsertSchema as S, tenantSchema as C } from "authhero";
3
+ import { HTTPException as w } from "hono/http-exception";
4
+ import { OpenAPIHono as T, createRoute as E, z as D } from "@hono/zod-openapi";
5
5
  //#region src/hooks/access-control.ts
6
- function E(e) {
6
+ function ne(e) {
7
7
  let { controlPlaneTenantId: t, requireOrganizationMatch: n = !0 } = e;
8
8
  return { async onTenantAccessValidation(e, r) {
9
9
  if (r === t) return !0;
@@ -14,14 +14,14 @@ function E(e) {
14
14
  return !0;
15
15
  } };
16
16
  }
17
- function D(e, t, n, r) {
17
+ function O(e, t, n, r) {
18
18
  if (t === n) return !0;
19
19
  let i = r || e;
20
20
  return i ? i.toLowerCase() === t.toLowerCase() : !1;
21
21
  }
22
22
  //#endregion
23
23
  //#region src/hooks/database.ts
24
- function ee(e) {
24
+ function re(e) {
25
25
  return { async resolveDataAdapters(t) {
26
26
  try {
27
27
  return await e.getAdapters(t);
@@ -33,18 +33,18 @@ function ee(e) {
33
33
  }
34
34
  //#endregion
35
35
  //#region src/operations/instance-id.ts
36
- var O = 64;
37
- function k(e) {
36
+ var k = 64;
37
+ function ie(e) {
38
38
  return e.replace(/[^a-zA-Z0-9_-]/g, "-");
39
39
  }
40
- function A(e) {
41
- let t = k(e.id), n = Math.max(0, O - (5 + t.length)), r = k(e.kind).slice(0, n), i = 3 + r.length + 2 + t.length, a = Math.max(0, O - i);
42
- return `op-${r}-${k(e.tenant_id ?? "fleet").slice(0, a)}-${t}`.slice(0, O);
40
+ function ae(e) {
41
+ let t = ie(e.id), n = Math.max(0, k - (5 + t.length)), r = ie(e.kind).slice(0, n), i = 3 + r.length + 2 + t.length, a = Math.max(0, k - i);
42
+ return `op-${r}-${ie(e.tenant_id ?? "fleet").slice(0, a)}-${t}`.slice(0, k);
43
43
  }
44
44
  //#endregion
45
45
  //#region src/operations/recorder.ts
46
- var te = 2048;
47
- function j(e) {
46
+ var oe = 2048;
47
+ function se(e) {
48
48
  let t;
49
49
  if (e instanceof Error) t = e.message;
50
50
  else try {
@@ -52,9 +52,9 @@ function j(e) {
52
52
  } catch {
53
53
  t = Object.prototype.toString.call(e);
54
54
  }
55
- return t.slice(0, te);
55
+ return t.slice(0, oe);
56
56
  }
57
- function M(e) {
57
+ function A(e) {
58
58
  let { tenantOperations: t, tenantOperationEvents: n } = e;
59
59
  return {
60
60
  async markRunning(e, n) {
@@ -75,6 +75,9 @@ function M(e) {
75
75
  attempt: t.attempt ?? 1
76
76
  });
77
77
  },
78
+ async setResult(e, n) {
79
+ await t.update(e, { result: n });
80
+ },
78
81
  async markSucceeded(e) {
79
82
  await t.update(e, {
80
83
  status: "succeeded",
@@ -85,24 +88,24 @@ function M(e) {
85
88
  async markFailed(e, n) {
86
89
  await t.update(e, {
87
90
  status: "failed",
88
- error: j(n),
91
+ error: se(n),
89
92
  finished_at: (/* @__PURE__ */ new Date()).toISOString()
90
93
  });
91
94
  }
92
95
  };
93
96
  }
94
- function ne(e) {
97
+ function j(e) {
95
98
  return e === "succeeded" || e === "failed" || e === "cancelled";
96
99
  }
97
100
  //#endregion
98
101
  //#region src/operations/inline-executor.ts
99
- var re = { async do(e, t, n) {
102
+ var ce = { async do(e, t, n) {
100
103
  let r = typeof t == "function" ? t : n;
101
104
  if (!r) throw Error("StepRunner.do called without a function");
102
105
  return r();
103
106
  } };
104
- function ie(e) {
105
- let t = M(e.stores);
107
+ function le(e) {
108
+ let t = A(e.stores);
106
109
  return {
107
110
  engine: "inline",
108
111
  async start(n) {
@@ -121,7 +124,7 @@ function ie(e) {
121
124
  try {
122
125
  let r = await e.run({
123
126
  operation: n,
124
- step: re
127
+ step: ce
125
128
  });
126
129
  await t.appendEvent(n.id, {
127
130
  step: e.name,
@@ -132,7 +135,7 @@ function ie(e) {
132
135
  throw await t.appendEvent(n.id, {
133
136
  step: e.name,
134
137
  outcome: "failed",
135
- detail: { message: j(r) }
138
+ detail: { message: se(r) }
136
139
  }), await t.markFailed(n.id, r), r;
137
140
  }
138
141
  }
@@ -142,7 +145,7 @@ function ie(e) {
142
145
  }
143
146
  //#endregion
144
147
  //#region src/operations/enqueue.ts
145
- async function ae(e, t, n) {
148
+ async function M(e, t, n) {
146
149
  let r = await e.tenantOperations.create({
147
150
  tenant_id: t.tenant_id,
148
151
  rollout_id: t.rollout_id,
@@ -150,13 +153,14 @@ async function ae(e, t, n) {
150
153
  engine: n,
151
154
  initiated_by: t.initiated_by,
152
155
  target_worker_version: t.target_worker_version,
153
- target_database_version: t.target_database_version
154
- }), i = A(r);
156
+ target_database_version: t.target_database_version,
157
+ input: t.input
158
+ }), i = ae(r);
155
159
  try {
156
160
  await e.tenantOperations.update(r.id, { engine_instance_id: i });
157
161
  } catch (t) {
158
162
  try {
159
- await M(e).markFailed(r.id, t);
163
+ await A(e).markFailed(r.id, t);
160
164
  } catch {}
161
165
  throw t;
162
166
  }
@@ -165,713 +169,635 @@ async function ae(e, t, n) {
165
169
  engine_instance_id: i
166
170
  };
167
171
  }
168
- async function oe(e, t, n) {
169
- let r = M(e), i = await ae(e, n, t.engine);
172
+ async function ue(e, t, n, r = {}) {
173
+ let i = A(e), a = await M(e, n, t.engine);
170
174
  try {
171
- await t.start(i);
175
+ await t.start(a);
172
176
  } catch (t) {
177
+ let n = null;
173
178
  try {
174
- let n = await e.tenantOperations.get(i.id);
175
- n && !ne(n.status) && await r.markFailed(i.id, t);
179
+ let r = await e.tenantOperations.get(a.id);
180
+ r && !j(r.status) && await i.markFailed(a.id, t), n = await e.tenantOperations.get(a.id);
176
181
  } catch (e) {
177
182
  console.warn("Failed to record tenant operation failure:", e);
178
183
  }
184
+ if (r.returnFailed && n) return n;
179
185
  throw t;
180
186
  }
181
187
  try {
182
- return await e.tenantOperations.get(i.id) ?? i;
188
+ return await e.tenantOperations.get(a.id) ?? a;
183
189
  } catch (e) {
184
- return console.warn("Failed to re-fetch tenant operation after start:", e), i;
190
+ return console.warn("Failed to re-fetch tenant operation after start:", e), a;
185
191
  }
186
192
  }
187
- //#endregion
188
- //#region src/operations/record-provision.ts
189
- function se(e) {
190
- if (e.tenantOperations && e.tenantOperationEvents) return {
191
- tenantOperations: e.tenantOperations,
192
- tenantOperationEvents: e.tenantOperationEvents
193
- };
194
- }
195
- async function ce(e, t, n) {
196
- let r = se(e);
197
- if (!r) {
198
- await n(void 0);
199
- return;
193
+ async function de(e) {
194
+ let { tenantId: t, parentTenantId: n, getTenant: r, getChildren: i } = e, a = e.maxDepth ?? 2;
195
+ if (!n) return;
196
+ if (t && n === t) throw new w(400, { message: "A tenant cannot be its own parent" });
197
+ let o = new Set(t ? [t] : []), s = 0, c = n;
198
+ for (; c;) {
199
+ if (o.has(c)) throw new w(400, { message: `Setting parent_tenant_id to '${n}' would create a cycle` });
200
+ o.add(c);
201
+ let e = await r(c);
202
+ if (!e) throw new w(400, { message: `Parent tenant '${c}' not found` });
203
+ if (s += 1, s > a) throw new w(400, { message: `Tenant tree is limited to ${a} levels above a tenant` });
204
+ c = e.parent_tenant_id;
200
205
  }
201
- let i = M(r), a = async (e) => {
202
- try {
203
- await e();
204
- } catch (e) {
205
- console.warn("Failed to record tenant operation progress:", e);
206
+ if (t && i) {
207
+ let e = new Set([t]), r = 0, o = [t];
208
+ for (; o.length > 0;) {
209
+ let t = [];
210
+ for (let n of o) for (let r of await i(n)) e.has(r) || (e.add(r), t.push(r));
211
+ if (t.length > 0 && (r += 1, s + r > a)) throw new w(400, { message: `Moving tenant under '${n}' would make its descendant '${t[0]}' exceed the tenant tree limit of ${a} levels` });
212
+ o = t;
206
213
  }
207
- }, o;
208
- if (await a(async () => {
209
- let e = await ae(r, t, "inline");
210
- o = e.id, await i.markRunning(e.id);
211
- }), !o) {
212
- await n(void 0);
213
- return;
214
214
  }
215
- let s = o, c = !1, l = async (e, t, n) => {
216
- c = !0, await a(async () => {
217
- t === "started" && await i.setCurrentStep(s, e), await i.appendEvent(s, {
218
- step: e,
219
- outcome: t,
220
- detail: n
221
- });
222
- });
223
- };
224
- try {
225
- await n(l);
226
- } catch (e) {
227
- throw await a(async () => {
228
- c || await i.appendEvent(s, {
229
- step: t.kind,
230
- outcome: "failed",
231
- detail: { message: j(e) }
232
- }), await i.markFailed(s, e);
233
- }), e;
215
+ }
216
+ //#endregion
217
+ //#region src/inheritance/chain.ts
218
+ async function N(e) {
219
+ let { tenantId: t, getTenant: n, legacyControlPlane: r } = e, i = e.maxDepth ?? 2, a = await n(t);
220
+ if (!a?.parent_tenant_id) return r && r !== t ? [r] : [];
221
+ let o = [], s = new Set([t]), c = a.parent_tenant_id;
222
+ for (; c;) {
223
+ if (s.has(c)) throw new w(400, { message: `Tenant chain for '${t}' contains a cycle at '${c}'` });
224
+ if (s.add(c), o.length >= i) throw new w(400, { message: `Tenant chain for '${t}' is deeper than ${i}` });
225
+ let e = await n(c);
226
+ if (!e) break;
227
+ o.push(c), c = e.parent_tenant_id;
234
228
  }
235
- await a(async () => {
236
- c || await i.appendEvent(s, {
237
- step: t.kind,
238
- outcome: "succeeded"
239
- }), await i.markSucceeded(s);
240
- });
229
+ return o;
241
230
  }
242
231
  //#endregion
243
- //#region src/hooks/provisioning.ts
244
- function le(e) {
245
- return `urn:authhero:tenant:${e.toLowerCase()}`;
232
+ //#region src/inheritance/legacy.ts
233
+ function fe(e) {
234
+ let t = {};
235
+ for (let n of e ?? []) n.value !== void 0 && (t[n.name] = n.value);
236
+ return t;
246
237
  }
247
- function N(e) {
238
+ function pe(e, t) {
239
+ if (!e.inherit) return e;
240
+ let n = t.find((t) => t.name === e.name && t.is_system);
241
+ if (!n) return e;
242
+ let r = {
243
+ ...fe(n.secrets),
244
+ ...fe(e.secrets)
245
+ };
248
246
  return {
249
- async beforeCreate(e, t) {
250
- return !t.audience && t.id ? {
251
- ...t,
252
- audience: le(t.id)
253
- } : t;
254
- },
255
- async afterCreate(t, i) {
256
- let { accessControl: a, databaseIsolation: o } = e;
257
- if (a && t.ctx && await ue(t, i, a), o?.onProvision) {
258
- let e = o.onProvision;
259
- o.recordProvisionOperations === !1 ? await e(i.id) : await ce(t.adapters, {
260
- kind: "provision",
261
- tenant_id: i.id,
262
- initiated_by: t.ctx?.var.user?.sub
263
- }, (t) => e(i.id, t));
264
- } else try {
265
- await v(t.adapters, i.id, {
266
- managementApiIdentifier: n,
267
- managementApiScopes: r
268
- });
269
- } catch (e) {
270
- throw console.warn(`Failed to provision default clients for tenant ${i.id}:`, e), e;
271
- }
272
- },
273
- async beforeDelete(t, n) {
274
- let { accessControl: r, databaseIsolation: i } = e;
275
- if (r) try {
276
- let e = (await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find((e) => e.name === n);
277
- e && await t.adapters.organizations.remove(r.controlPlaneTenantId, e.id);
278
- } catch (e) {
279
- console.warn(`Failed to remove organization for tenant ${n}:`, e);
280
- }
281
- if (i?.onDeprovision) try {
282
- await i.onDeprovision(n);
283
- } catch (e) {
284
- console.warn(`Failed to deprovision database for tenant ${n}:`, e);
285
- }
286
- }
247
+ ...e,
248
+ code: n.code,
249
+ secrets: Object.entries(r).map(([e, t]) => ({
250
+ name: e,
251
+ value: t
252
+ }))
287
253
  };
288
254
  }
289
- async function ue(e, t, n) {
290
- let { controlPlaneTenantId: r, defaultPermissions: i, defaultRoles: a, issuer: o, adminRoleName: s = "Tenant Admin", adminRoleDescription: c = "Full access to all tenant management operations", addCreatorToOrganization: l = !0 } = n, u = await e.adapters.organizations.create(r, {
291
- name: t.id,
292
- display_name: t.friendly_name || t.id
293
- }), d;
294
- if (o && (d = await fe(e, r, s, c)), l && e.ctx) {
295
- let t = e.ctx.var.user;
296
- if (t?.sub && !await de(e, r, t.sub)) try {
297
- await e.adapters.userOrganizations.create(r, {
298
- user_id: t.sub,
299
- organization_id: u.id
300
- }), d && await e.adapters.userRoles.create(r, t.sub, d, u.id);
301
- } catch (e) {
302
- console.warn(`Failed to add creator ${t.sub} to organization ${u.id}:`, e);
303
- }
304
- }
305
- a && a.length > 0 && console.log(`Would assign roles ${a.join(", ")} to organization ${u.id}`), i && i.length > 0 && console.log(`Would grant permissions ${i.join(", ")} to organization ${u.id}`);
306
- }
307
- async function de(e, t, r) {
308
- let i = await e.adapters.userRoles.list(t, r, void 0, "");
309
- for (let r of i) if ((await e.adapters.rolePermissions.list(t, r.id, { per_page: 1e3 })).some((e) => e.permission_name === "admin:organizations" && e.resource_server_identifier === n)) return !0;
310
- return !1;
311
- }
312
- async function fe(e, t, i, a) {
313
- let o = (await e.adapters.roles.list(t, {})).roles.find((e) => e.name === i);
314
- if (o) return o.id;
315
- let s = await e.adapters.roles.create(t, {
316
- name: i,
317
- description: a
318
- }), c = n, l = r.map((e) => ({
319
- role_id: s.id,
320
- resource_server_identifier: c,
321
- permission_name: e.value
322
- }));
323
- return await e.adapters.rolePermissions.assign(t, s.id, l), s.id;
255
+ function me(e, t) {
256
+ if (!t) return e;
257
+ let n = new Set(e.hooks.map((e) => e.hook_id)), r = t.hooks.filter((e) => B(e) && !n.has(e.hook_id));
258
+ return {
259
+ connections: e.connections.map((e) => R(e, t.connections)),
260
+ resourceServers: e.resourceServers.map((e) => e.is_system ? Ie(e, t.resourceServers.find((t) => t.id === e.id) ?? null) : e),
261
+ hooks: [...e.hooks, ...r],
262
+ hookCode: e.hookCode,
263
+ actions: e.actions.map((e) => pe(e, t.actions)),
264
+ emailProvider: e.emailProvider ?? t.emailProvider,
265
+ branding: e.branding,
266
+ promptSettings: e.promptSettings
267
+ };
324
268
  }
325
269
  //#endregion
326
- //#region src/hooks/sync.ts
327
- function pe(e, t, n = () => !0) {
328
- let { controlPlaneTenantId: r, getChildTenantIds: i, getAdapters: a } = e, o = /* @__PURE__ */ new Map();
329
- async function s(e, n, r) {
330
- return (await t(e).list(n, {
331
- q: `name:${d(r)}`,
332
- per_page: 1
333
- }))[0] ?? null;
334
- }
335
- async function c(e) {
336
- let n = await i(), o = t(await a(r));
337
- await Promise.all(n.map(async (n) => {
338
- try {
339
- let r = await a(n), i = t(r), c = {
340
- ...o.transform(e),
341
- is_system: !0
342
- }, l = await s(r, n, e.name), u = l ? i.getId(l) : void 0;
343
- if (l && u) {
344
- let e = i.preserveOnUpdate ? i.preserveOnUpdate(l, c) : c;
345
- await i.update(n, u, e);
346
- } else await i.create(n, c);
347
- } catch (t) {
348
- console.error(`Failed to sync ${o.listKey} "${e.name}" to tenant "${n}":`, t);
349
- }
350
- }));
351
- }
352
- async function l(e) {
353
- let n = await i();
354
- await Promise.all(n.map(async (n) => {
355
- try {
356
- let r = await a(n), i = t(r), o = await s(r, n, e), c = o ? i.getId(o) : void 0;
357
- o && c && await i.remove(n, c);
358
- } catch (t) {
359
- console.error(`Failed to delete entity "${e}" from tenant "${n}":`, t);
360
- }
361
- }));
362
- }
270
+ //#region src/rollout/defaults-projection.ts
271
+ function he(e = {}) {
363
272
  return {
364
- afterCreate: async (e, t) => {
365
- e.tenantId === r && n(t) && await c(t);
366
- },
367
- afterUpdate: async (e, t, i) => {
368
- e.tenantId === r && n(i) && await c(i);
369
- },
370
- beforeDelete: async (e, i) => {
371
- if (e.tenantId !== r) return;
372
- let a = await t(e.adapters).get(e.tenantId, i);
373
- a && n(a) && o.set(i, a);
374
- },
375
- afterDelete: async (e, t) => {
376
- if (e.tenantId !== r) return;
377
- let n = o.get(t);
378
- n && (o.delete(t), await l(n.name));
379
- }
273
+ connections: e.connections ?? !0,
274
+ resourceServers: e.resourceServers ?? !0,
275
+ hooks: e.hooks ?? !0,
276
+ emailProvider: e.emailProvider ?? !0,
277
+ branding: e.branding ?? !0,
278
+ promptSettings: e.promptSettings ?? !0
380
279
  };
381
280
  }
382
- function me(e, t, n = () => !0) {
383
- let { controlPlaneTenantId: r, getControlPlaneAdapters: i, getAdapters: a } = e;
384
- return { async afterCreate(e, o) {
385
- if (o.id !== r) try {
386
- let e = await i(), s = await a(o.id), c = t(e), l = t(s), u = await f((e) => c.listPaginated(r, e), c.listKey, {
387
- cursorField: "id",
388
- pageSize: 100
389
- });
390
- await Promise.all(u.filter((e) => n(e)).map(async (e) => {
391
- try {
392
- let t = c.transform(e);
393
- await l.create(o.id, {
394
- ...t,
395
- is_system: !0
396
- });
397
- } catch (e) {
398
- console.error(`Failed to sync entity to new tenant "${o.id}":`, e);
399
- }
400
- }));
401
- } catch (e) {
402
- console.error(`Failed to sync entities to new tenant "${o.id}":`, e);
403
- }
404
- } };
281
+ function P() {
282
+ return {
283
+ upserted: 0,
284
+ errors: []
285
+ };
286
+ }
287
+ function ge(e) {
288
+ return {
289
+ tenantId: e,
290
+ connections: P(),
291
+ resourceServers: P(),
292
+ hooks: P(),
293
+ emailProvider: P(),
294
+ branding: P(),
295
+ promptSettings: P()
296
+ };
405
297
  }
406
- var he = (e) => ({
407
- list: async (t, n) => (await e.resourceServers.list(t, n)).resource_servers,
408
- listPaginated: (t, n) => e.resourceServers.list(t, n),
409
- get: (t, n) => e.resourceServers.get(t, n),
410
- create: (t, n) => e.resourceServers.create(t, n),
411
- update: (t, n, r) => e.resourceServers.update(t, n, r),
412
- remove: (t, n) => e.resourceServers.remove(t, n),
413
- listKey: "resource_servers",
414
- getId: (e) => e.id,
415
- transform: (e) => ({
416
- id: e.id,
417
- name: e.name,
418
- identifier: e.identifier,
419
- scopes: e.scopes,
420
- signing_alg: e.signing_alg,
421
- token_lifetime: e.token_lifetime,
422
- token_lifetime_for_web: e.token_lifetime_for_web
423
- })
424
- }), ge = (e) => ({
425
- list: async (t, n) => (await e.roles.list(t, n)).roles,
426
- listPaginated: (t, n) => e.roles.list(t, n),
427
- get: (t, n) => e.roles.get(t, n),
428
- create: (t, n) => e.roles.create(t, n),
429
- update: (t, n, r) => e.roles.update(t, n, r),
430
- remove: (t, n) => e.roles.remove(t, n),
431
- listKey: "roles",
432
- getId: (e) => e.id,
433
- transform: (e) => ({
434
- id: e.id,
435
- name: e.name,
436
- description: e.description
437
- })
438
- });
439
298
  function _e(e) {
440
- return e.metadata?.sync !== !1;
299
+ let t = e.metadata;
300
+ return !!(t && t.inheritable === !0);
441
301
  }
442
- function ve(e) {
443
- let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) => _e(e) ? n.resourceServers ? n.resourceServers(e) : !0 : !1, o = (e) => _e(e) ? n.roles ? n.roles(e) : !0 : !1, s = r ? pe(e, he, a) : void 0, c = i ? pe(e, ge, o) : void 0, l = r ? me(e, he, a) : void 0, u = i ? me(e, ge, o) : void 0, p = i ? { async afterCreate(t, r) {
444
- if (r.id !== e.controlPlaneTenantId) {
445
- await u?.afterCreate?.(t, r);
446
- try {
447
- let t = await e.getControlPlaneAdapters(), i = await e.getAdapters(r.id), a = await f((n) => t.roles.list(e.controlPlaneTenantId, n), "roles", {
448
- cursorField: "id",
449
- pageSize: 100
450
- }), o = /* @__PURE__ */ new Map();
451
- for (let e of a.filter((e) => n.roles?.(e) ?? !0)) {
452
- let t = await m(i, r.id, e.name);
453
- t && o.set(e.name, t.id);
454
- }
455
- for (let s of a.filter((e) => n.roles?.(e) ?? !0)) {
456
- let n = o.get(s.name);
457
- if (n) try {
458
- let a = await t.rolePermissions.list(e.controlPlaneTenantId, s.id, {});
459
- a.length > 0 && await i.rolePermissions.assign(r.id, n, a.map((e) => ({
460
- role_id: n,
461
- resource_server_identifier: e.resource_server_identifier,
462
- permission_name: e.permission_name
463
- })));
464
- } catch (e) {
465
- console.error(`Failed to sync permissions for role "${s.name}" to tenant "${r.id}":`, e);
466
- }
467
- }
468
- } catch (e) {
469
- console.error(`Failed to sync role permissions to tenant "${r.id}":`, e);
470
- }
471
- }
472
- } } : void 0;
473
- async function m(e, t, n) {
474
- return (await e.roles.list(t, {
475
- q: `name:${d(n)}`,
476
- per_page: 1
477
- })).roles[0] ?? null;
302
+ async function F(e, t, n, r) {
303
+ try {
304
+ await r();
305
+ } catch (r) {
306
+ let i = `${t}: ${r instanceof Error ? r.message : String(r)}`;
307
+ if (!n) throw Error(i, { cause: r });
308
+ e.errors.push(i);
478
309
  }
310
+ }
311
+ async function ve(e, t, n) {
479
312
  return {
480
- entityHooks: {
481
- resourceServers: s,
482
- roles: c
483
- },
484
- tenantHooks: { async afterCreate(e, t) {
485
- let n = [l?.afterCreate, p?.afterCreate ?? u?.afterCreate], r = [];
486
- for (let i of n) if (i) try {
487
- await i(e, t);
488
- } catch (e) {
489
- r.push(e instanceof Error ? e : Error(String(e)));
490
- }
491
- if (r.length === 1) throw r[0];
492
- if (r.length > 1) throw AggregateError(r, r.map((e) => e.message).join("; "));
493
- } }
313
+ connections: n.connections ? await m((n) => e.connections.list(t, n), "connections", {
314
+ cursorField: "id",
315
+ pageSize: 100
316
+ }) : [],
317
+ resourceServers: n.resourceServers ? await m((n) => e.resourceServers.list(t, n), "resource_servers", {
318
+ cursorField: "id",
319
+ pageSize: 100
320
+ }) : [],
321
+ hooks: n.hooks ? await m((n) => e.hooks.list(t, n), "hooks", {
322
+ cursorField: "hook_id",
323
+ pageSize: 100
324
+ }) : [],
325
+ emailProvider: n.emailProvider ? await e.emailProviders.get(t) ?? null : null,
326
+ branding: n.branding ? await e.branding.get(t) ?? null : null,
327
+ promptSettings: n.promptSettings ? await e.promptSettings.get(t) ?? null : null
494
328
  };
495
329
  }
330
+ async function ye(e, t, n, r, i, a) {
331
+ if (r.connections) for (let r of e.connections) {
332
+ let e = r.id;
333
+ e && await F(a.connections, `connection ${e}`, i, async () => {
334
+ let i = c.parse(r);
335
+ await t.connections.get(n, e) ? await t.connections.update(n, e, i) : await t.connections.create(n, i), a.connections.upserted += 1;
336
+ });
337
+ }
338
+ if (r.resourceServers) for (let r of e.resourceServers) !r.is_system || !r.id || await F(a.resourceServers, `resource_server ${r.id}`, i, async () => {
339
+ let e = x.parse(r);
340
+ await t.resourceServers.get(n, r.id) ? await t.resourceServers.update(n, r.id, e) : await t.resourceServers.create(n, e), a.resourceServers.upserted += 1;
341
+ });
342
+ if (r.hooks) for (let r of e.hooks) !_e(r) || !r.hook_id || await F(a.hooks, `hook ${r.hook_id}`, i, async () => {
343
+ let e = g.parse(r);
344
+ await t.hooks.get(n, r.hook_id) ? await t.hooks.update(n, r.hook_id, e) : await t.hooks.create(n, e), a.hooks.upserted += 1;
345
+ });
346
+ r.emailProvider && e.emailProvider && await F(a.emailProvider, "email_provider", i, async () => {
347
+ let r = e.emailProvider;
348
+ await t.emailProviders.get(n) ? await t.emailProviders.update(n, r) : await t.emailProviders.create(n, r), a.emailProvider.upserted += 1;
349
+ }), r.branding && e.branding && await F(a.branding, "branding", i, async () => {
350
+ await t.branding.set(n, e.branding), a.branding.upserted += 1;
351
+ }), r.promptSettings && e.promptSettings && await F(a.promptSettings, "prompt_settings", i, async () => {
352
+ await t.promptSettings.set(n, e.promptSettings), a.promptSettings.upserted += 1;
353
+ });
354
+ }
355
+ async function be(e, t) {
356
+ let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s = he(a), c = await ve(await r(), n, s), l = await i(t), u = ge(t);
357
+ return await ye(c, l, n, s, o, u), u;
358
+ }
496
359
  //#endregion
497
- //#region src/middleware/request-data.ts
498
- function P(e) {
499
- return e.var.data ?? e.env.data;
360
+ //#region src/inheritance/read.ts
361
+ async function I(e, t) {
362
+ let n = await ve(e, t, {
363
+ connections: !0,
364
+ resourceServers: !0,
365
+ hooks: !0,
366
+ emailProvider: !0,
367
+ branding: !0,
368
+ promptSettings: !0
369
+ }), r = await m((n) => e.actions.list(t, n), "actions", {
370
+ cursorField: "id",
371
+ pageSize: 100
372
+ }), i = new Set(r.map((e) => e.id)), a = /* @__PURE__ */ new Set();
373
+ for (let e of n.hooks) {
374
+ let t = e.code_id;
375
+ t && !i.has(t) && a.add(t);
376
+ }
377
+ let o = [];
378
+ for (let n of a) {
379
+ let r = await e.hookCode.get(t, n);
380
+ r && o.push(r);
381
+ }
382
+ return {
383
+ ...n,
384
+ actions: r,
385
+ hookCode: o
386
+ };
500
387
  }
501
- async function ye(e) {
502
- let { tenantId: t, parentTenantId: n, getTenant: r, getChildren: i } = e, a = e.maxDepth ?? 2;
503
- if (!n) return;
504
- if (t && n === t) throw new T(400, { message: "A tenant cannot be its own parent" });
505
- let o = new Set(t ? [t] : []), s = 0, c = n;
506
- for (; c;) {
507
- if (o.has(c)) throw new T(400, { message: `Setting parent_tenant_id to '${n}' would create a cycle` });
508
- o.add(c);
509
- let e = await r(c);
510
- if (!e) throw new T(400, { message: `Parent tenant '${c}' not found` });
511
- if (s += 1, s > a) throw new T(400, { message: `Tenant tree is limited to ${a} levels above a tenant` });
512
- c = e.parent_tenant_id;
388
+ //#endregion
389
+ //#region src/inheritance/shadow.ts
390
+ var xe = /secret|password|private_key|api_key|token/i, Se = new Set([
391
+ "id",
392
+ "tenant_id",
393
+ "created_at",
394
+ "updated_at",
395
+ "scope",
396
+ "override",
397
+ "enforce",
398
+ "enabled_clients"
399
+ ]);
400
+ async function L(e) {
401
+ let t = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e));
402
+ return [...new Uint8Array(t)].map((e) => e.toString(16).padStart(2, "0")).join("").slice(0, 16);
403
+ }
404
+ async function Ce(e, t = "") {
405
+ if (Array.isArray(e)) {
406
+ if (t === "secrets") {
407
+ let t = {};
408
+ for (let n of e) t[n.name] = n.value === void 0 ? null : `sha256:${await L(n.value)}`;
409
+ return t;
410
+ }
411
+ return Promise.all(e.map((e) => Ce(e, t)));
513
412
  }
514
- if (t && i) {
515
- let e = new Set([t]), r = 0, o = [t];
516
- for (; o.length > 0;) {
517
- let t = [];
518
- for (let n of o) for (let r of await i(n)) e.has(r) || (e.add(r), t.push(r));
519
- if (t.length > 0 && (r += 1, s + r > a)) throw new T(400, { message: `Moving tenant under '${n}' would make its descendant '${t[0]}' exceed the tenant tree limit of ${a} levels` });
520
- o = t;
413
+ if (e && typeof e == "object") {
414
+ let t = {};
415
+ for (let n of Object.keys(e).sort()) {
416
+ let r = e[n];
417
+ r != null && (t[n] = typeof r == "string" && xe.test(n) ? `sha256:${await L(r)}` : await Ce(r, n));
521
418
  }
419
+ return t;
522
420
  }
421
+ return e;
523
422
  }
524
- //#endregion
525
- //#region src/routes/tenants.ts
526
- var be = w.object({
527
- sub: w.string(),
528
- tenant_id: w.string().optional(),
529
- org_id: w.string().optional(),
530
- scope: w.string().optional(),
531
- permissions: w.array(w.string()).optional()
532
- }).passthrough();
533
- function xe(e) {
534
- let t = be.safeParse(e);
535
- return t.success ? t.data : void 0;
423
+ async function we(e) {
424
+ let t = {};
425
+ for (let [n, r] of Object.entries(e)) Se.has(n) || (t[n] = r);
426
+ return await Ce(t);
536
427
  }
537
- function Se(e) {
538
- let t = e.permissions ?? [], n = e.scope ? e.scope.split(" ").filter(Boolean) : [], r = new Set([...t, ...n]);
539
- return r.has("delete:tenants") || r.has("admin:organizations");
428
+ var Te = {
429
+ connection: (e) => `${e.strategy}:${e.name}`,
430
+ resourceServer: (e) => e.identifier,
431
+ hook: (e) => e.hook_id,
432
+ action: (e) => e.name
433
+ }, Ee = new Set([
434
+ "connection",
435
+ "resourceServer",
436
+ "action",
437
+ "emailProvider",
438
+ "branding",
439
+ "promptSettings"
440
+ ]);
441
+ async function De(e) {
442
+ let t = /* @__PURE__ */ new Map(), n = async (e, n, r) => {
443
+ let i = t.get(e) ?? /* @__PURE__ */ new Map();
444
+ i.set(n, await we(r)), t.set(e, i);
445
+ };
446
+ for (let [t, r] of Object.entries(Te)) {
447
+ let i = e[{
448
+ connection: "connections",
449
+ resourceServer: "resourceServers",
450
+ hook: "hooks",
451
+ action: "actions"
452
+ }[t]];
453
+ for (let e of i) await n(t, r(e), e);
454
+ }
455
+ for (let t of [
456
+ "emailProvider",
457
+ "branding",
458
+ "promptSettings"
459
+ ]) e[t] && await n(t, "singleton", e[t]);
460
+ return t;
540
461
  }
541
- function F(e, t) {
542
- let n = new S();
543
- return n.openapi(C({
544
- tags: ["tenants"],
545
- method: "get",
546
- path: "/",
547
- request: { query: i },
548
- security: [{ Bearer: [] }],
549
- responses: { 200: {
550
- content: { "application/json": { schema: w.object({
551
- tenants: w.array(x),
552
- start: w.number().optional(),
553
- limit: w.number().optional(),
554
- length: w.number().optional(),
555
- total: w.number().optional()
556
- }) } },
557
- description: "List of tenants"
558
- } }
559
- }), async (t) => {
560
- let { page: n, per_page: r, include_totals: i, q: a } = t.req.valid("query"), o = t.var.user, s = o?.permissions || [];
561
- if (!(o?.org_id ?? t.var.organization_id) && s.includes("admin:organizations")) {
562
- let e = await P(t).tenants.list({
563
- page: n,
564
- per_page: r,
565
- include_totals: i,
566
- q: a
462
+ async function Oe(e, t) {
463
+ let [n, r] = await Promise.all([De(e), De(t)]), i = [], a = new Set([...n.keys(), ...r.keys()]);
464
+ for (let e of a) {
465
+ let t = n.get(e) ?? /* @__PURE__ */ new Map(), a = r.get(e) ?? /* @__PURE__ */ new Map();
466
+ for (let n of new Set([...t.keys(), ...a.keys()])) {
467
+ let r = t.get(n), o = a.get(n);
468
+ if (r && !o) i.push({
469
+ entity: e,
470
+ key: n,
471
+ kind: "missing",
472
+ fields: [],
473
+ expected: !1
567
474
  });
568
- return i ? t.json({
569
- tenants: e.tenants,
570
- start: e.totals?.start ?? 0,
571
- limit: e.totals?.limit ?? r,
572
- length: e.tenants.length,
573
- total: e.totals?.length
574
- }) : t.json({ tenants: e.tenants });
475
+ else if (!r && o) i.push({
476
+ entity: e,
477
+ key: n,
478
+ kind: "extra",
479
+ fields: [],
480
+ expected: Ee.has(e)
481
+ });
482
+ else if (r && o) {
483
+ let t = JSON.stringify(r), a = JSON.stringify(o);
484
+ if (t === a) continue;
485
+ let s = [...new Set([...Object.keys(r), ...Object.keys(o)])].filter((e) => JSON.stringify(r[e]) !== JSON.stringify(o[e])).sort();
486
+ i.push({
487
+ entity: e,
488
+ key: n,
489
+ kind: "changed",
490
+ fields: s,
491
+ expected: !1,
492
+ legacy_hash: await L(t),
493
+ new_hash: await L(a)
494
+ });
495
+ }
575
496
  }
576
- let c = e.accessControl?.controlPlaneTenantId ?? P(t).multiTenancyConfig?.controlPlaneTenantId;
577
- if (c && !o?.sub) throw new T(403, { message: "Access denied: token has no subject" });
578
- if (c && o?.sub) {
579
- let e = (await f((e) => P(t).userOrganizations.listUserOrganizations(c, o.sub, e), "organizations")).map((e) => e.name);
580
- if (e.length === 0) return i ? t.json({
581
- tenants: [],
582
- start: 0,
583
- limit: r ?? 50,
584
- length: 0,
585
- total: 0
586
- }) : t.json({ tenants: [] });
587
- let s = e.length, l = n ?? 0, u = r ?? 50, d = l * u, p = e.slice(d, d + u);
588
- if (p.length === 0) return i ? t.json({
589
- tenants: [],
590
- start: d,
591
- limit: u,
592
- length: 0,
593
- total: s
594
- }) : t.json({ tenants: [] });
595
- let m = p.map((e) => `id:${e}`).join(" OR "), h = a ? `(${m}) AND (${a})` : m, g = await P(t).tenants.list({
596
- q: h,
597
- per_page: u,
598
- include_totals: !1
599
- });
600
- return i ? t.json({
601
- tenants: g.tenants,
602
- start: d,
603
- limit: u,
604
- length: g.tenants.length,
605
- total: s
606
- }) : t.json({ tenants: g.tenants });
607
- }
608
- let l = await P(t).tenants.list({
609
- page: n,
610
- per_page: r,
611
- include_totals: i,
612
- q: a
613
- });
614
- return i ? t.json({
615
- tenants: l.tenants,
616
- start: l.totals?.start ?? 0,
617
- limit: l.totals?.limit ?? r,
618
- length: l.tenants.length,
619
- total: l.totals?.length
620
- }) : t.json({ tenants: l.tenants });
621
- }), n.openapi(C({
622
- tags: ["tenants"],
623
- method: "post",
624
- path: "/",
625
- request: { body: { content: { "application/json": { schema: b } } } },
626
- security: [{ Bearer: [] }],
627
- responses: {
628
- 201: {
629
- content: { "application/json": { schema: x } },
630
- description: "Tenant created"
631
- },
632
- 400: { description: "Validation error" },
633
- 409: { description: "Tenant with this ID already exists" }
634
- }
635
- }), async (e) => {
636
- if (!e.var.user?.sub) throw new T(401, { message: "Authentication required to create tenants" });
637
- let n = e.req.valid("json"), r = {
638
- adapters: P(e),
639
- ctx: e
640
- };
641
- t.tenants?.beforeCreate && (n = await t.tenants.beforeCreate(r, n)), await ye({
642
- tenantId: n.id,
643
- parentTenantId: n.parent_tenant_id,
644
- getTenant: (t) => P(e).tenants.get(t)
645
- });
646
- let i = await P(e).tenants.create(n);
647
- return t.tenants?.afterCreate && await t.tenants.afterCreate(r, i), e.json(i, 201);
648
- }), n.openapi(C({
649
- tags: ["tenants"],
650
- method: "delete",
651
- path: "/{id}",
652
- request: { params: w.object({ id: w.string() }) },
653
- security: [{ Bearer: ["delete:tenants"] }],
654
- responses: {
655
- 204: { description: "Tenant deleted" },
656
- 403: { description: "Access denied or cannot delete the control plane" },
657
- 404: { description: "Tenant not found" }
658
- }
659
- }), async (n) => {
660
- let { id: r } = n.req.valid("param"), i = e.accessControl?.controlPlaneTenantId ?? P(n).multiTenancyConfig?.controlPlaneTenantId;
661
- if (i) {
662
- let e = xe(n.var.user);
663
- if (!e?.sub) throw new T(401, { message: "Authentication required" });
664
- if (r === i) throw new T(403, { message: "Cannot delete the control plane" });
665
- let t = n.var.org_name, a = r.toLowerCase(), o = !!t && t.toLowerCase() === a;
666
- if (!o) {
667
- let r = !!(e.org_id ?? n.var.organization_id ?? t), a = !e.tenant_id || e.tenant_id === i;
668
- !r && a && Se(e) && (o = !0);
669
- }
670
- if (o ||= (await f((t) => P(n).userOrganizations.listUserOrganizations(i, e.sub, t), "organizations")).some((e) => e.name?.toLowerCase() === a), !o) throw new T(403, { message: "Access denied to this tenant" });
671
- }
672
- if (!await P(n).tenants.get(r)) throw new T(404, { message: "Tenant not found" });
673
- let a = {
674
- adapters: P(n),
675
- ctx: n
676
- };
677
- return t.tenants?.beforeDelete && await t.tenants.beforeDelete(a, r), await P(n).tenants.remove(r), t.tenants?.afterDelete && await t.tenants.afterDelete(a, r), n.body(null, 204);
678
- }), n.openapi(C({
679
- tags: ["tenants", "settings"],
680
- method: "get",
681
- path: "/settings",
682
- request: { headers: w.object({ "tenant-id": w.string().optional() }) },
683
- security: [{ Bearer: ["read:tenants"] }],
684
- responses: { 200: {
685
- content: { "application/json": { schema: x } },
686
- description: "Current tenant settings"
687
- } }
688
- }), async (e) => {
689
- let t = await P(e).tenants.get(e.var.tenant_id);
690
- if (!t) throw new T(404, { message: "Tenant not found" });
691
- return e.json(t);
692
- }), n.openapi(C({
693
- tags: ["tenants", "settings"],
694
- method: "patch",
695
- path: "/settings",
696
- request: {
697
- headers: w.object({ "tenant-id": w.string().optional() }),
698
- body: { content: { "application/json": { schema: w.object(b.shape).partial() } } }
699
- },
700
- security: [{ Bearer: ["update:tenants"] }],
701
- responses: { 200: {
702
- content: { "application/json": { schema: x } },
703
- description: "Updated tenant settings"
704
- } }
705
- }), async (e) => {
706
- let { id: t, ...n } = e.req.valid("json"), r = await P(e).tenants.get(e.var.tenant_id);
707
- if (!r) throw new T(404, { message: "Tenant not found" });
708
- if ("default_client_id" in n) {
709
- let t = n.default_client_id;
710
- if (typeof t == "string" && t.length > 0) {
711
- let n = await P(e).clients.get(e.var.tenant_id, t);
712
- if (!n) throw new T(400, { message: `Client with id '${t}' not found` });
713
- if (!h(n)) throw new T(400, { message: `Client '${t}' is not an interactive client and cannot be used as the default client` });
714
- }
715
- }
716
- "parent_tenant_id" in n && await ye({
717
- tenantId: e.var.tenant_id,
718
- parentTenantId: n.parent_tenant_id,
719
- getTenant: (t) => P(e).tenants.get(t),
720
- getChildren: async (t) => (await f((t) => P(e).tenants.list(t), "tenants")).filter((e) => e.parent_tenant_id === t).map((e) => e.id)
721
- });
722
- let i = l(r, n);
723
- await P(e).tenants.update(e.var.tenant_id, i);
724
- let a = await P(e).tenants.get(e.var.tenant_id);
725
- if (!a) throw new T(500, { message: "Failed to retrieve updated tenant" });
726
- return e.json(a);
727
- }), n;
497
+ }
498
+ return i;
499
+ }
500
+ async function ke(e) {
501
+ let { adapters: t, tenantId: n, legacyControlPlane: r } = e, i = await N({
502
+ tenantId: n,
503
+ getTenant: (e) => t.tenants.get(e),
504
+ legacyControlPlane: r,
505
+ maxDepth: e.maxDepth
506
+ }), a = await I(t, n), o = await Promise.all(i.map((e) => I(t, e))), s = r && r !== n ? await I(t, r) : void 0, { hidden: c, ...l } = Ze(o, a), u = new Set(c);
507
+ return (await Oe(me(a, s), l)).filter((e) => !u.has(`${e.entity}:${e.key}`));
728
508
  }
729
509
  //#endregion
730
- //#region src/middleware/protect-synced.ts
731
- function Ce(e) {
732
- for (let { pattern: t, type: n } of [
733
- {
734
- pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
735
- type: "resource_server"
736
- },
737
- {
738
- pattern: /\/api\/v2\/roles\/([^/]+)$/,
739
- type: "role"
740
- },
741
- {
742
- pattern: /\/api\/v2\/connections\/([^/]+)$/,
743
- type: "connection"
510
+ //#region src/inheritance/report.ts
511
+ var Ae = 3600 * 1e3, je = 1e4;
512
+ function Me(e, t) {
513
+ let n = t.sample ?? 1, r = t.intervalMs ?? 6e4, i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map();
514
+ async function s(n, r) {
515
+ let i = await ke({
516
+ adapters: e,
517
+ tenantId: n,
518
+ legacyControlPlane: r
519
+ }), a = Date.now();
520
+ o.size > je && o.clear();
521
+ for (let s of i) {
522
+ if (s.expected && !t.includeExpected) continue;
523
+ let i = await L([
524
+ n,
525
+ s.entity,
526
+ s.key,
527
+ s.kind,
528
+ s.fields.join(",")
529
+ ].join("|")), c = o.get(i);
530
+ c !== void 0 && a - c < Ae || (o.set(i, a), await Ne(e, n, s, r));
744
531
  }
745
- ]) {
746
- let r = e.match(t);
747
- if (r && r[1]) return {
748
- type: n,
749
- id: r[1]
750
- };
751
532
  }
752
- return null;
533
+ return { schedule(e, t) {
534
+ if (a.has(e) || n < 1 && Math.random() >= n) return;
535
+ let o = Date.now(), c = i.get(e);
536
+ c !== void 0 && o - c < r || (i.set(e, o), a.add(e), s(e, t).catch(() => {}).finally(() => a.delete(e)));
537
+ } };
753
538
  }
754
- async function we(e, t, n) {
755
- try {
756
- switch (n.type) {
757
- case "resource_server": return (await e.resourceServers.get(t, n.id))?.is_system === !0;
758
- case "role": return (await e.roles.get(t, n.id))?.is_system === !0;
759
- case "connection": return (await e.connections.get(t, n.id))?.is_system === !0;
760
- default: return !1;
539
+ async function Ne(e, n, r, i) {
540
+ await e.logs.create(n, {
541
+ type: t.CONFIG_INHERITANCE_DIFF,
542
+ date: (/* @__PURE__ */ new Date()).toISOString(),
543
+ isMobile: !1,
544
+ description: `${r.kind} ${r.entity} ${r.key}`,
545
+ details: {
546
+ shadow: "config-inheritance",
547
+ legacy_control_plane: i,
548
+ ...r
761
549
  }
762
- } catch {
763
- return !1;
764
- }
550
+ });
765
551
  }
766
- function Te(e) {
552
+ //#endregion
553
+ //#region src/middleware/config-sync-mode.ts
554
+ function Pe(e) {
555
+ let { base: t, getTenant: n, controlPlaneTenantId: r } = e, i = e.ttlMs ?? 3e4, a = e.maxEntries ?? 1e3, o = /* @__PURE__ */ new Map();
556
+ async function s(e) {
557
+ if (e === r) return !1;
558
+ let t = o.get(e), s = Date.now();
559
+ if (t && t.expires > s) return t.synced;
560
+ try {
561
+ let t = (await n(e))?.config_sync === "synced";
562
+ return o.size >= a && o.clear(), o.set(e, {
563
+ synced: t,
564
+ expires: s + i
565
+ }), t;
566
+ } catch {
567
+ return !1;
568
+ }
569
+ }
767
570
  return {
768
- resource_server: "resource server",
769
- role: "role",
770
- connection: "connection"
771
- }[e];
772
- }
773
- function Ee() {
774
- return async (e, t) => {
775
- if (![
776
- "PATCH",
777
- "PUT",
778
- "DELETE"
779
- ].includes(e.req.method)) return t();
780
- let n = Ce(e.req.path);
781
- if (!n) return t();
782
- let r = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
783
- if (!r) return t();
784
- if (await we(P(e), r, n)) throw new T(403, { message: `This ${Te(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.` });
785
- return t();
571
+ isSynced: s,
572
+ invalidate(e) {
573
+ e ? o.delete(e) : o.clear();
574
+ },
575
+ async resolve({ tenant_id: e }) {
576
+ let n = await t(e);
577
+ return !n || n.tenantId === e ? n : await s(e) ? void 0 : n;
578
+ }
786
579
  };
787
580
  }
788
581
  //#endregion
789
- //#region src/inheritance/chain.ts
790
- async function De(e) {
791
- let { tenantId: t, getTenant: n, legacyControlPlane: r } = e, i = e.maxDepth ?? 2, a = await n(t);
792
- if (!a?.parent_tenant_id) return r && r !== t ? [r] : [];
793
- let o = [], s = new Set([t]), c = a.parent_tenant_id;
794
- for (; c;) {
795
- if (s.has(c)) throw new T(400, { message: `Tenant chain for '${t}' contains a cycle at '${c}'` });
796
- if (s.add(c), o.length >= i) throw new T(400, { message: `Tenant chain for '${t}' is deeper than ${i}` });
797
- let e = await n(c);
798
- if (!e) break;
799
- o.push(c), c = e.parent_tenant_id;
800
- }
801
- return o;
582
+ //#region src/middleware/settings-inheritance.ts
583
+ function R(e, t) {
584
+ let n = t.find((t) => t.strategy === e.strategy);
585
+ if (!n?.options) return e;
586
+ let r = u.passthrough().parse({
587
+ ...n,
588
+ ...e
589
+ });
590
+ return r.options = l.passthrough().parse({
591
+ ...n.options || {},
592
+ ...e.options
593
+ }), r;
802
594
  }
803
- //#endregion
804
- //#region src/inheritance/legacy.ts
805
- function Oe(e) {
806
- let t = {};
807
- for (let n of e ?? []) n.value !== void 0 && (t[n.name] = n.value);
808
- return t;
595
+ function z(e, t) {
596
+ let n = [...t || [], ...e || []];
597
+ return [...new Set(n)];
809
598
  }
810
- function ke(e, t) {
811
- if (!e.inherit) return e;
812
- let n = t.find((t) => t.name === e.name && t.is_system);
813
- if (!n) return e;
814
- let r = {
815
- ...Oe(n.secrets),
816
- ...Oe(e.secrets)
817
- };
818
- return {
599
+ function Fe(e, t) {
600
+ if (!t?.length) return e || [];
601
+ if (!e?.length) return t;
602
+ let n = /* @__PURE__ */ new Map();
603
+ for (let e of t) n.set(e.value, e);
604
+ for (let t of e) n.set(t.value, t);
605
+ return Array.from(n.values());
606
+ }
607
+ function Ie(e, t) {
608
+ return t ? {
819
609
  ...e,
820
- code: n.code,
821
- secrets: Object.entries(r).map(([e, t]) => ({
822
- name: e,
823
- value: t
824
- }))
825
- };
610
+ scopes: Fe(e.scopes, t.scopes)
611
+ } : e;
826
612
  }
827
- function Ae(e, t) {
828
- if (!t) return e;
829
- let n = new Set(e.hooks.map((e) => e.hook_id)), r = t.hooks.filter((e) => X(e) && !n.has(e.hook_id));
830
- return {
831
- connections: e.connections.map((e) => q(e, t.connections)),
832
- resourceServers: e.resourceServers.map((e) => e.is_system ? Y(e, t.resourceServers.find((t) => t.id === e.id) ?? null) : e),
833
- hooks: [...e.hooks, ...r],
834
- actions: e.actions.map((e) => ke(e, t.actions)),
835
- emailProvider: e.emailProvider ?? t.emailProvider,
836
- branding: e.branding,
837
- promptSettings: e.promptSettings
613
+ function Le(e, t) {
614
+ return t ? {
615
+ ...e,
616
+ callbacks: z(e.callbacks, t.callbacks),
617
+ web_origins: z(e.web_origins, t.web_origins),
618
+ allowed_logout_urls: z(e.allowed_logout_urls, t.allowed_logout_urls),
619
+ allowed_origins: z(e.allowed_origins, t.allowed_origins)
620
+ } : e;
621
+ }
622
+ function Re(e) {
623
+ let { controlPlaneTenantId: t, controlPlaneClientId: n, resolveControlPlane: r } = e;
624
+ if (r) return async (e) => r({ tenant_id: e });
625
+ if (!t) return async () => void 0;
626
+ let i = {
627
+ tenantId: t,
628
+ clientId: n
838
629
  };
630
+ return async () => i;
839
631
  }
840
- //#endregion
841
- //#region src/inheritance/types.ts
842
- var je = () => ({
843
- connections: [],
844
- resourceServers: [],
845
- hooks: [],
846
- actions: [],
847
- emailProvider: null,
848
- branding: null,
849
- promptSettings: null
850
- });
851
- //#endregion
852
- //#region src/inheritance/merge.ts
853
- function I(e, t) {
854
- if (t.scope) return t.scope;
855
- switch (e) {
632
+ function ze(e, t) {
633
+ return {
634
+ ...e.resourceServers,
635
+ get: async (n, r) => {
636
+ let i = await e.resourceServers.get(n, r);
637
+ if (!i) return i;
638
+ let a = await t(n);
639
+ return !a || n === a.tenantId || !i.is_system ? i : Ie(i, await e.resourceServers.get(a.tenantId, r));
640
+ },
641
+ list: async (n, r) => {
642
+ let i = await e.resourceServers.list(n, r), a = await t(n);
643
+ if (!a || n === a.tenantId) return i;
644
+ let o = a.tenantId, s = i.resource_servers.filter((e) => !!(e.is_system && e.id)).map((e) => e.id);
645
+ if (s.length === 0) return i;
646
+ let c = /* @__PURE__ */ new Map();
647
+ await Promise.all(s.map(async (t) => {
648
+ let n = await e.resourceServers.get(o, t);
649
+ n && c.set(t, n);
650
+ }));
651
+ let l = i.resource_servers.map((e) => e.is_system && e.id ? Ie(e, c.get(e.id) ?? null) : e);
652
+ return {
653
+ ...i,
654
+ resource_servers: l
655
+ };
656
+ }
657
+ };
658
+ }
659
+ function Be(e, t) {
660
+ let n = Re({
661
+ controlPlaneTenantId: t.controlPlaneTenantId,
662
+ resolveControlPlane: t.resolveControlPlane
663
+ });
664
+ return {
665
+ ...e,
666
+ resourceServers: ze(e, n)
667
+ };
668
+ }
669
+ function Ve(e, t) {
670
+ let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i, inheritanceShadow: a } = t, o = t.configSync ?? Pe({
671
+ base: Re({
672
+ controlPlaneTenantId: n,
673
+ controlPlaneClientId: r,
674
+ resolveControlPlane: i
675
+ }),
676
+ getTenant: async (t) => await e.tenants.get(t) ?? null,
677
+ controlPlaneTenantId: n
678
+ }), s = (e) => o.resolve({ tenant_id: e }), c = a ? Me(e, a === !0 ? {} : a) : void 0, l = c ? async (e) => {
679
+ let t = await s(e);
680
+ return await o.isSynced(e) || c.schedule(e, t?.tenantId), t;
681
+ } : s;
682
+ return {
683
+ ...e,
684
+ multiTenancyConfig: {
685
+ controlPlaneTenantId: n,
686
+ controlPlaneClientId: r,
687
+ resolveControlPlane: o.resolve
688
+ },
689
+ connections: {
690
+ ...e.connections,
691
+ get: async (t, n) => {
692
+ let r = await e.connections.get(t, n);
693
+ if (!r) return r;
694
+ let i = await l(t);
695
+ return !i || t === i.tenantId ? r : R(r, (await e.connections.list(i.tenantId)).connections || []);
696
+ },
697
+ list: async (t, n) => {
698
+ let r = await e.connections.list(t, n), i = await l(t);
699
+ if (!i || t === i.tenantId) return r;
700
+ let a = await e.connections.list(i.tenantId), o = r.connections.map((e) => R(e, a.connections || []));
701
+ return {
702
+ ...r,
703
+ connections: o
704
+ };
705
+ }
706
+ },
707
+ clientConnections: {
708
+ ...e.clientConnections,
709
+ listByClient: async (t, n) => {
710
+ let r = await e.clientConnections.listByClient(t, n);
711
+ r.length === 0 && (r = (await e.connections.list(t)).connections || []);
712
+ let i = await l(t);
713
+ if (!i || t === i.tenantId) return r;
714
+ let a = await e.connections.list(i.tenantId);
715
+ return r.map((e) => R(e, a.connections || []));
716
+ }
717
+ },
718
+ emailProviders: {
719
+ ...e.emailProviders,
720
+ get: async (t) => {
721
+ let n = await e.emailProviders.get(t);
722
+ if (n) return n;
723
+ let r = await l(t);
724
+ return !r || t === r.tenantId ? null : e.emailProviders.get(r.tenantId);
725
+ }
726
+ },
727
+ resourceServers: ze(e, l),
728
+ hooks: He(e, l)
729
+ };
730
+ }
731
+ function B(e) {
732
+ if (!e || typeof e != "object") return !1;
733
+ let t = e.metadata;
734
+ return !t || typeof t != "object" ? !1 : t.inheritable === !0;
735
+ }
736
+ function He(e, t) {
737
+ return {
738
+ ...e.hooks,
739
+ list: async (n, r) => {
740
+ let i = await e.hooks.list(n, r), a = await t(n);
741
+ if (!a || n === a.tenantId) return i;
742
+ let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(B);
743
+ if (o.length === 0) return i;
744
+ let s = new Set((i.hooks || []).map((e) => e.hook_id)), c = [];
745
+ for (let e of o) s.has(e.hook_id) || e.hook_id && s.has(await W("hook", n, e.hook_id)) || c.push(e);
746
+ return {
747
+ ...i,
748
+ hooks: [...i.hooks || [], ...c],
749
+ length: typeof i.length == "number" ? i.length + c.length : i.length
750
+ };
751
+ },
752
+ get: async (n, r) => {
753
+ let i = await e.hooks.get(n, r);
754
+ if (i) return i;
755
+ let a = await t(n);
756
+ if (!a || n === a.tenantId) return i;
757
+ let o = await e.hooks.get(a.tenantId, r);
758
+ return o && B(o) ? o : null;
759
+ }
760
+ };
761
+ }
762
+ function Ue(e, t) {
763
+ return Ve(e, t);
764
+ }
765
+ //#endregion
766
+ //#region src/inheritance/types.ts
767
+ var We = () => ({
768
+ connections: [],
769
+ resourceServers: [],
770
+ hooks: [],
771
+ hookCode: [],
772
+ actions: [],
773
+ emailProvider: null,
774
+ branding: null,
775
+ promptSettings: null
776
+ });
777
+ //#endregion
778
+ //#region src/inheritance/merge.ts
779
+ function V(e, t) {
780
+ if (t.scope) return t.scope;
781
+ switch (e) {
856
782
  case "connection":
857
783
  case "emailProvider": return "shared";
858
784
  case "resourceServer":
859
785
  case "action": return t.is_system ? "shared" : "local";
860
- case "hook": return X(t) ? "shared" : "local";
786
+ case "hook": return B(t) ? "shared" : "local";
861
787
  default: return "local";
862
788
  }
863
789
  }
864
- function L(e) {
790
+ function H(e) {
865
791
  return e.override ?? "fields";
866
792
  }
867
- var Me = /secret|password|private_key|api_key|token/i;
868
- function Ne(e, t) {
793
+ var Ge = /secret|password|private_key|api_key|token/i;
794
+ function Ke(e, t) {
869
795
  let n = { ...e ?? {} };
870
- for (let [e, r] of Object.entries(t ?? {})) Me.test(e) && (n[e] = r);
796
+ for (let [e, r] of Object.entries(t ?? {})) Ge.test(e) && (n[e] = r);
871
797
  return n;
872
798
  }
873
- function R(e, t) {
874
- switch (L(e)) {
799
+ function qe(e, t) {
800
+ switch (H(e)) {
875
801
  case "none": return {
876
802
  ...e,
877
803
  id: t.id
@@ -879,7 +805,7 @@ function R(e, t) {
879
805
  case "secrets": return {
880
806
  ...e,
881
807
  id: t.id,
882
- options: Ne(e.options, t.options)
808
+ options: Ke(e.options, t.options)
883
809
  };
884
810
  default: return {
885
811
  ...e,
@@ -891,8 +817,8 @@ function R(e, t) {
891
817
  };
892
818
  }
893
819
  }
894
- function Pe(e, t) {
895
- switch (L(e)) {
820
+ function Je(e, t) {
821
+ switch (H(e)) {
896
822
  case "none": return {
897
823
  ...e,
898
824
  id: t.id
@@ -904,46 +830,46 @@ function Pe(e, t) {
904
830
  };
905
831
  default: return {
906
832
  ...t,
907
- scopes: $e(t.scopes, e.scopes)
833
+ scopes: Fe(t.scopes, e.scopes)
908
834
  };
909
835
  }
910
836
  }
911
- function Fe(e) {
837
+ function Ye(e) {
912
838
  return new Map((e ?? []).map((e) => [e.name, e]));
913
839
  }
914
- function Ie(e, t) {
915
- let n = L(e);
840
+ function Xe(e, t) {
841
+ let n = H(e);
916
842
  if (n === "none") return {
917
843
  ...e,
918
844
  id: t.id
919
845
  };
920
- let r = Fe(e.secrets);
921
- if (n === "secrets" || n === "fields") for (let [e, n] of Fe(t.secrets)) r.set(e, n);
846
+ let r = Ye(e.secrets);
847
+ if (n === "secrets" || n === "fields") for (let [e, n] of Ye(t.secrets)) r.set(e, n);
922
848
  return {
923
849
  ...n === "fields" && !t.inherit ? t : e,
924
850
  id: t.id,
925
851
  secrets: [...r.values()]
926
852
  };
927
853
  }
928
- function Le(e, t) {
854
+ function Ze(e, t) {
929
855
  let n = /* @__PURE__ */ new Set(), r = [...e].reverse().concat(t), i = (e, t, r, i) => r ? t : t.filter((t) => {
930
- let r = I(e, t);
856
+ let r = V(e, t);
931
857
  return r === "local" ? !1 : (r === "platform" && n.add(`${e}:${i(t)}`), !0);
932
- }), a = je(), o = (e) => `${e.strategy}:${e.name}`, s = (e) => e.identifier, c = (e) => e.hook_id ?? "", l = (e) => e.name, u = /* @__PURE__ */ new Map(), d = [], f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map();
858
+ }), a = We(), o = (e) => `${e.strategy}:${e.name}`, s = (e) => e.identifier, c = (e) => e.hook_id ?? "", l = (e) => e.name, u = /* @__PURE__ */ new Map(), d = [], f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map();
933
859
  r.forEach((e, t) => {
934
860
  let h = t === r.length - 1;
935
861
  for (let t of i("connection", e.connections, h, o)) {
936
862
  let e = u.get(t.strategy);
937
- h ? d.push(e ? R(e, t) : t) : u.set(t.strategy, e ? R(e, t) : t);
863
+ h ? d.push(e ? qe(e, t) : t) : u.set(t.strategy, e ? qe(e, t) : t);
938
864
  }
939
865
  for (let t of i("resourceServer", e.resourceServers, h, s)) {
940
866
  let e = f.get(s(t));
941
- f.set(s(t), e ? Pe(e, t) : t);
867
+ f.set(s(t), e ? Je(e, t) : t);
942
868
  }
943
869
  for (let t of i("hook", e.hooks, h, c)) p.set(c(t), t);
944
870
  for (let t of i("action", e.actions, h, l)) {
945
871
  let e = m.get(l(t));
946
- m.set(l(t), e ? Ie(e, t) : t);
872
+ m.set(l(t), e ? Xe(e, t) : t);
947
873
  }
948
874
  for (let t of [
949
875
  "emailProvider",
@@ -951,485 +877,1059 @@ function Le(e, t) {
951
877
  "promptSettings"
952
878
  ]) {
953
879
  let r = e[t];
954
- r && (h || I(t, r) !== "local") && (!h && I(t, r) === "platform" && n.add(`${t}:singleton`), a[t] = r);
880
+ r && (h || V(t, r) !== "local") && (!h && V(t, r) === "platform" && n.add(`${t}:singleton`), a[t] = r);
955
881
  }
956
882
  });
957
883
  let h = new Set(r[r.length - 1].connections.map((e) => e.strategy));
958
- return a.connections = [...d, ...[...u.values()].filter((e) => !h.has(e.strategy))], a.resourceServers = [...f.values()], a.hooks = [...p.values()], a.actions = [...m.values()], {
884
+ a.connections = [...d, ...[...u.values()].filter((e) => !h.has(e.strategy))], a.resourceServers = [...f.values()], a.hooks = [...p.values()];
885
+ let g = new Set(a.hooks.map((e) => e.code_id).filter((e) => !!e)), _ = /* @__PURE__ */ new Map();
886
+ for (let e of [...r].reverse()) for (let t of e.hookCode) g.has(t.id) && !_.has(t.id) && _.set(t.id, t);
887
+ return a.hookCode = [..._.values()], a.actions = [...m.values()], {
959
888
  ...a,
960
889
  hidden: [...n]
961
890
  };
962
891
  }
963
892
  //#endregion
964
- //#region src/rollout/defaults-projection.ts
965
- function z(e = {}) {
966
- return {
967
- connections: e.connections ?? !0,
968
- resourceServers: e.resourceServers ?? !0,
969
- hooks: e.hooks ?? !0,
970
- emailProvider: e.emailProvider ?? !0,
971
- branding: e.branding ?? !0,
972
- promptSettings: e.promptSettings ?? !0
973
- };
974
- }
975
- function B() {
976
- return {
977
- upserted: 0,
978
- errors: []
979
- };
980
- }
981
- function Re(e) {
982
- return {
983
- tenantId: e,
984
- connections: B(),
985
- resourceServers: B(),
986
- hooks: B(),
987
- emailProvider: B(),
988
- branding: B(),
989
- promptSettings: B()
990
- };
991
- }
992
- function ze(e) {
993
- let t = e.metadata;
994
- return !!(t && t.inheritable === !0);
893
+ //#region src/rollout/resolved-sync.ts
894
+ function U(e) {
895
+ return Array.isArray(e) ? `[${e.map(U).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)}:${U(t)}`).join(",")}}` : JSON.stringify(e) ?? "null";
995
896
  }
996
- async function V(e, t, n, r) {
997
- try {
998
- await r();
999
- } catch (r) {
1000
- let i = `${t}: ${r instanceof Error ? r.message : String(r)}`;
1001
- if (!n) throw Error(i, { cause: r });
1002
- e.errors.push(i);
897
+ async function Qe(e) {
898
+ let t = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e));
899
+ return [...new Uint8Array(t)].map((e) => e.toString(16).padStart(2, "0")).join("");
900
+ }
901
+ var $e = {
902
+ connection: "con_",
903
+ resourceServer: "api_",
904
+ hook: "h_",
905
+ hookCode: "hc_",
906
+ action: "act_"
907
+ };
908
+ async function W(e, t, n) {
909
+ let r = await Qe(`${t}|${e}|${n}`);
910
+ return `${$e[e]}sy${r.slice(0, 15)}`;
911
+ }
912
+ function G(e, t) {
913
+ let n = t;
914
+ switch (e) {
915
+ case "connection": return `${n.strategy}:${n.name}`;
916
+ case "resourceServer": return n.identifier;
917
+ case "action": return n.name;
918
+ case "hookCode": return n.id;
919
+ case "hook": return n.hook_id;
1003
920
  }
1004
921
  }
1005
- async function H(e, t, n) {
922
+ async function et(e, t, n = {}) {
923
+ let r = await N({
924
+ tenantId: t,
925
+ getTenant: (t) => e.tenants.get(t),
926
+ legacyControlPlane: n.legacyControlPlane,
927
+ maxDepth: n.maxDepth
928
+ }), i = Ze(await Promise.all(r.map((t) => I(e, t))), We()), a = {
929
+ version: 1,
930
+ chain: r,
931
+ connections: i.connections,
932
+ resourceServers: i.resourceServers,
933
+ hookCode: i.hookCode,
934
+ actions: i.actions,
935
+ hooks: i.hooks,
936
+ emailProvider: i.emailProvider,
937
+ branding: i.branding,
938
+ promptSettings: i.promptSettings,
939
+ hidden: i.hidden,
940
+ deletes: n.deletes ?? []
941
+ };
1006
942
  return {
1007
- connections: n.connections ? await f((n) => e.connections.list(t, n), "connections", {
1008
- cursorField: "id",
1009
- pageSize: 100
1010
- }) : [],
1011
- resourceServers: n.resourceServers ? await f((n) => e.resourceServers.list(t, n), "resource_servers", {
1012
- cursorField: "id",
1013
- pageSize: 100
1014
- }) : [],
1015
- hooks: n.hooks ? await f((n) => e.hooks.list(t, n), "hooks", {
1016
- cursorField: "hook_id",
1017
- pageSize: 100
1018
- }) : [],
1019
- emailProvider: n.emailProvider ? await e.emailProviders.get(t) ?? null : null,
1020
- branding: n.branding ? await e.branding.get(t) ?? null : null,
1021
- promptSettings: n.promptSettings ? await e.promptSettings.get(t) ?? null : null
943
+ ...a,
944
+ hash: await Qe(U(a))
1022
945
  };
1023
946
  }
1024
- async function Be(e, t, n, r, i, a) {
1025
- if (r.connections) for (let r of e.connections) {
1026
- let e = r.id;
1027
- e && await V(a.connections, `connection ${e}`, i, async () => {
1028
- let i = o.parse(r);
1029
- await t.connections.get(n, e) ? await t.connections.update(n, e, i) : await t.connections.create(n, i), a.connections.upserted += 1;
947
+ function tt(e, t) {
948
+ if (typeof e == "string") e.startsWith("enc:v1:") && t.add(e);
949
+ else if (Array.isArray(e)) for (let n of e) tt(n, t);
950
+ else if (e && typeof e == "object") for (let n of Object.values(e)) tt(n, t);
951
+ }
952
+ function nt(e) {
953
+ let t = e.slice(7), n = t.indexOf(":");
954
+ return n === -1 ? "default" : t.slice(0, n);
955
+ }
956
+ async function rt(e, t) {
957
+ let n = /* @__PURE__ */ new Set();
958
+ tt(e, n);
959
+ let r = /* @__PURE__ */ new Set();
960
+ for (let e of n) await s(e, t) || r.add(nt(e));
961
+ return [...r].sort();
962
+ }
963
+ var K = () => ({
964
+ added: 0,
965
+ changed: 0,
966
+ unchanged: 0,
967
+ deleted: 0,
968
+ errors: []
969
+ }), it = (e) => U(e);
970
+ async function at(e, t, n, r = {}) {
971
+ let { dryRun: a = !1, continueOnError: s = !0 } = r, l = {
972
+ status: a ? "dry-run" : "applied",
973
+ hash: e.hash,
974
+ entities: {
975
+ connection: K(),
976
+ resourceServer: K(),
977
+ hookCode: K(),
978
+ action: K(),
979
+ hook: K(),
980
+ emailProvider: K(),
981
+ branding: K(),
982
+ promptSettings: K()
983
+ },
984
+ changes: []
985
+ }, u = await t.tenants.get(n), d = !!r.deletes && e.deletes.length > 0;
986
+ if (!a && !r.force && !d && u?.config_sync_hash === e.hash) return {
987
+ ...l,
988
+ status: "up-to-date"
989
+ };
990
+ if (r.keyRing) {
991
+ let t = await rt(e, r.keyRing);
992
+ if (t.length > 0) throw Error(`Cannot sync config to '${n}': its key ring cannot decrypt key id(s) ${t.map((e) => `"${e}"`).join(", ")} carried by the payload. Nothing was written.`);
993
+ }
994
+ let p = async (e, t, n) => {
995
+ let r = l.entities[e];
996
+ try {
997
+ let i = await n();
998
+ r[i] += 1, i !== "unchanged" && l.changes.push(`${e}:${t}`);
999
+ } catch (n) {
1000
+ let i = `${e} ${t}: ${n instanceof Error ? n.message : String(n)}`;
1001
+ if (!s) throw Error(i, { cause: n });
1002
+ r.errors.push(i);
1003
+ }
1004
+ }, m = async (e) => e.existing ? it(e.view(e.existing)) === it(e.view(e.desired)) ? "unchanged" : (a || await e.update(), "changed") : (a || await e.create(), "added"), _ = (e, t) => W(e, n, t), v = /* @__PURE__ */ new Map();
1005
+ for (let t of e.hookCode) v.set(t.id, await _("hookCode", G("hookCode", t)));
1006
+ for (let t of e.actions) v.set(t.id, await _("action", G("action", t)));
1007
+ for (let r of e.connections) {
1008
+ let e = G("connection", r), i = await _("connection", e);
1009
+ await p("connection", e, async () => {
1010
+ let { enabled_clients: e, ...a } = r, o = c.parse({
1011
+ ...a,
1012
+ id: i
1013
+ }), s = await t.connections.get(n, i);
1014
+ return m({
1015
+ existing: s ? c.parse(s) : null,
1016
+ desired: o,
1017
+ create: () => t.connections.create(n, o),
1018
+ update: () => t.connections.update(n, i, o),
1019
+ view: (e) => e
1020
+ });
1030
1021
  });
1031
1022
  }
1032
- if (r.resourceServers) for (let r of e.resourceServers) !r.is_system || !r.id || await V(a.resourceServers, `resource_server ${r.id}`, i, async () => {
1033
- let e = y.parse(r);
1034
- await t.resourceServers.get(n, r.id) ? await t.resourceServers.update(n, r.id, e) : await t.resourceServers.create(n, e), a.resourceServers.upserted += 1;
1035
- });
1036
- if (r.hooks) for (let r of e.hooks) !ze(r) || !r.hook_id || await V(a.hooks, `hook ${r.hook_id}`, i, async () => {
1037
- let e = p.parse(r);
1038
- await t.hooks.get(n, r.hook_id) ? await t.hooks.update(n, r.hook_id, e) : await t.hooks.create(n, e), a.hooks.upserted += 1;
1039
- });
1040
- r.emailProvider && e.emailProvider && await V(a.emailProvider, "email_provider", i, async () => {
1041
- let r = e.emailProvider;
1042
- await t.emailProviders.get(n) ? await t.emailProviders.update(n, r) : await t.emailProviders.create(n, r), a.emailProvider.upserted += 1;
1043
- }), r.branding && e.branding && await V(a.branding, "branding", i, async () => {
1044
- await t.branding.set(n, e.branding), a.branding.upserted += 1;
1045
- }), r.promptSettings && e.promptSettings && await V(a.promptSettings, "prompt_settings", i, async () => {
1046
- await t.promptSettings.set(n, e.promptSettings), a.promptSettings.upserted += 1;
1023
+ for (let r of e.resourceServers) {
1024
+ let e = G("resourceServer", r), i = await _("resourceServer", e);
1025
+ await p("resourceServer", e, async () => {
1026
+ let e = x.parse({
1027
+ ...r,
1028
+ id: i
1029
+ }), a = await t.resourceServers.get(n, i);
1030
+ return m({
1031
+ existing: a ? x.parse(a) : null,
1032
+ desired: e,
1033
+ create: () => t.resourceServers.create(n, e),
1034
+ update: () => t.resourceServers.update(n, i, e),
1035
+ view: (e) => e
1036
+ });
1037
+ });
1038
+ }
1039
+ for (let r of e.hookCode) {
1040
+ let e = G("hookCode", r), i = v.get(r.id);
1041
+ await p("hookCode", e, async () => {
1042
+ let e = h.parse(r), a = await t.hookCode.get(n, i);
1043
+ return m({
1044
+ existing: a ? h.parse(a) : null,
1045
+ desired: e,
1046
+ create: () => t.hookCode.create(n, e, { importMetadata: { id: i } }),
1047
+ update: () => t.hookCode.update(n, i, e),
1048
+ view: (e) => e
1049
+ });
1050
+ });
1051
+ }
1052
+ for (let r of e.actions) {
1053
+ let e = G("action", r), a = v.get(r.id);
1054
+ await p("action", e, async () => {
1055
+ let e = i.parse(r), o = await t.actions.get(n, a);
1056
+ return m({
1057
+ existing: o ? i.parse(o) : null,
1058
+ desired: e,
1059
+ create: () => t.actions.create(n, e, { importMetadata: { id: a } }),
1060
+ update: () => t.actions.update(n, a, e),
1061
+ view: (e) => e
1062
+ });
1063
+ });
1064
+ }
1065
+ for (let r of e.hooks) {
1066
+ let e = G("hook", r), i = await _("hook", e);
1067
+ await p("hook", e, async () => {
1068
+ let e = r.code_id, a = g.parse({
1069
+ ...r,
1070
+ hook_id: i,
1071
+ ...e ? { code_id: v.get(e) ?? e } : {}
1072
+ }), o = await t.hooks.get(n, i);
1073
+ return m({
1074
+ existing: o ? g.parse(o) : null,
1075
+ desired: a,
1076
+ create: () => t.hooks.create(n, a),
1077
+ update: () => t.hooks.update(n, i, a),
1078
+ view: (e) => e
1079
+ });
1080
+ });
1081
+ }
1082
+ e.emailProvider && await p("emailProvider", "singleton", async () => {
1083
+ let r = f.parse(e.emailProvider);
1084
+ return await t.emailProviders.get(n) ? "unchanged" : (a || await t.emailProviders.create(n, r), "added");
1085
+ }), e.branding && await p("branding", "singleton", async () => {
1086
+ let r = o.parse(e.branding);
1087
+ return await t.branding.get(n) ? "unchanged" : (a || await t.branding.set(n, r), "added");
1047
1088
  });
1089
+ for (let i of e.deletes) {
1090
+ let e = await _(i.entity, i.key), o = `${i.entity}:${i.key}`;
1091
+ try {
1092
+ if (!await ot(t, n, i.entity, e)) continue;
1093
+ l.changes.push(`delete ${o}`), r.deletes && !a && (await st(t, n, i.entity, e), l.entities[i.entity].deleted += 1);
1094
+ } catch (e) {
1095
+ l.entities[i.entity].errors.push(`delete ${o}: ${e instanceof Error ? e.message : e}`);
1096
+ }
1097
+ }
1098
+ let y = Object.values(l.entities).some((e) => e.errors.length > 0);
1099
+ return !a && !y && u && await t.tenants.update(n, {
1100
+ config_sync_hash: e.hash,
1101
+ config_synced_at: (/* @__PURE__ */ new Date()).toISOString()
1102
+ }), l;
1103
+ }
1104
+ async function ot(e, t, n, r) {
1105
+ switch (n) {
1106
+ case "connection": return !!await e.connections.get(t, r);
1107
+ case "resourceServer": return !!await e.resourceServers.get(t, r);
1108
+ case "hookCode": return !!await e.hookCode.get(t, r);
1109
+ case "action": return !!await e.actions.get(t, r);
1110
+ case "hook": return !!await e.hooks.get(t, r);
1111
+ }
1048
1112
  }
1049
- async function U(e, t) {
1050
- let { controlPlaneTenantId: n, getControlPlaneAdapters: r, getAdapters: i, entities: a, continueOnError: o = !1 } = e, s = z(a), c = await H(await r(), n, s), l = await i(t), u = Re(t);
1051
- return await Be(c, l, n, s, o, u), u;
1113
+ async function st(e, t, n, r) {
1114
+ switch (n) {
1115
+ case "connection":
1116
+ await e.connections.remove(t, r);
1117
+ return;
1118
+ case "resourceServer":
1119
+ await e.resourceServers.remove(t, r);
1120
+ return;
1121
+ case "hookCode":
1122
+ await e.hookCode.remove(t, r);
1123
+ return;
1124
+ case "action":
1125
+ await e.actions.remove(t, r);
1126
+ return;
1127
+ case "hook":
1128
+ await e.hooks.remove(t, r);
1129
+ return;
1130
+ }
1052
1131
  }
1053
1132
  //#endregion
1054
- //#region src/inheritance/read.ts
1055
- async function W(e, t) {
1056
- let n = await H(e, t, {
1057
- connections: !0,
1058
- resourceServers: !0,
1059
- hooks: !0,
1060
- emailProvider: !0,
1061
- branding: !0,
1062
- promptSettings: !0
1063
- }), r = await f((n) => e.actions.list(t, n), "actions", {
1064
- cursorField: "id",
1065
- pageSize: 100
1066
- });
1133
+ //#region src/operations/sync-defaults.ts
1134
+ function ct(e) {
1135
+ let t = e.input ?? {};
1067
1136
  return {
1068
- ...n,
1069
- actions: r
1137
+ dryRun: t.dry_run === !0,
1138
+ force: t.force === !0
1070
1139
  };
1071
1140
  }
1072
- //#endregion
1073
- //#region src/inheritance/shadow.ts
1074
- var Ve = /secret|password|private_key|api_key|token/i, He = new Set([
1075
- "id",
1076
- "tenant_id",
1077
- "created_at",
1078
- "updated_at",
1079
- "scope",
1080
- "override",
1081
- "enforce",
1082
- "enabled_clients"
1083
- ]);
1084
- async function G(e) {
1085
- let t = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e));
1086
- return [...new Uint8Array(t)].map((e) => e.toString(16).padStart(2, "0")).join("").slice(0, 16);
1141
+ function lt(e) {
1142
+ return Object.values(e.entities).flatMap((e) => e.errors);
1087
1143
  }
1088
- async function K(e, t = "") {
1089
- if (Array.isArray(e)) {
1090
- if (t === "secrets") {
1091
- let t = {};
1092
- for (let n of e) t[n.name] = n.value === void 0 ? null : `sha256:${await G(n.value)}`;
1093
- return t;
1094
- }
1095
- return Promise.all(e.map((e) => K(e, t)));
1096
- }
1097
- if (e && typeof e == "object") {
1098
- let t = {};
1099
- for (let n of Object.keys(e).sort()) {
1100
- let r = e[n];
1101
- r != null && (t[n] = typeof r == "string" && Ve.test(n) ? `sha256:${await G(r)}` : await K(r, n));
1102
- }
1103
- return t;
1144
+ function ut(e, t) {
1145
+ return {
1146
+ dry_run: t.dryRun,
1147
+ status: e.status,
1148
+ hash: e.hash,
1149
+ changes: e.changes,
1150
+ entities: Object.fromEntries(Object.entries(e.entities).map(([e, t]) => [e, {
1151
+ added: t.added,
1152
+ changed: t.changed,
1153
+ unchanged: t.unchanged,
1154
+ deleted: t.deleted,
1155
+ errors: t.errors.length
1156
+ }]))
1157
+ };
1158
+ }
1159
+ async function dt(e) {
1160
+ let { operation: t, syncConfig: n, recorder: r } = e;
1161
+ if (!t.tenant_id) throw Error("sync-defaults operations require a tenant_id");
1162
+ let i = ct(t), a = await n(t.tenant_id, i), o = ut(a, i);
1163
+ await r.setResult(t.id, o);
1164
+ let s = lt(a);
1165
+ if (s.length > 0) {
1166
+ let e = s.slice(0, 3).join("; ");
1167
+ throw Error(`sync-defaults reported ${s.length} error(s): ${e}${s.length > 3 ? "; ..." : ""}`);
1104
1168
  }
1105
- return e;
1169
+ return o;
1106
1170
  }
1107
- async function Ue(e) {
1108
- let t = {};
1109
- for (let [n, r] of Object.entries(e)) He.has(n) || (t[n] = r);
1110
- return await K(t);
1171
+ function ft(e, t) {
1172
+ return async (n, r) => {
1173
+ let i = await e.tenants.get(n);
1174
+ if (!i) throw Error(`Tenant "${n}" not found`);
1175
+ if (i.deployment_type === "wfp") throw Error(`Tenant "${n}" has its own database: configure a dispatch sync (syncDefaults) for it`);
1176
+ return at(await et(e, n, {
1177
+ legacyControlPlane: (t.resolveControlPlane ? await t.resolveControlPlane({ tenant_id: n }) : { tenantId: t.controlPlaneTenantId })?.tenantId,
1178
+ maxDepth: t.maxDepth
1179
+ }), e, n, {
1180
+ dryRun: r.dryRun,
1181
+ force: r.force
1182
+ });
1183
+ };
1111
1184
  }
1112
- var We = {
1113
- connection: (e) => `${e.strategy}:${e.name}`,
1114
- resourceServer: (e) => e.identifier,
1115
- hook: (e) => e.hook_id,
1116
- action: (e) => e.name
1117
- }, Ge = new Set([
1118
- "connection",
1119
- "resourceServer",
1120
- "action",
1121
- "emailProvider",
1122
- "branding",
1123
- "promptSettings"
1124
- ]);
1125
- async function Ke(e) {
1126
- let t = /* @__PURE__ */ new Map(), n = async (e, n, r) => {
1127
- let i = t.get(e) ?? /* @__PURE__ */ new Map();
1128
- i.set(n, await Ue(r)), t.set(e, i);
1185
+ //#endregion
1186
+ //#region src/operations/record-provision.ts
1187
+ function pt(e) {
1188
+ if (e.tenantOperations && e.tenantOperationEvents) return {
1189
+ tenantOperations: e.tenantOperations,
1190
+ tenantOperationEvents: e.tenantOperationEvents
1129
1191
  };
1130
- for (let [t, r] of Object.entries(We)) {
1131
- let i = e[{
1132
- connection: "connections",
1133
- resourceServer: "resourceServers",
1134
- hook: "hooks",
1135
- action: "actions"
1136
- }[t]];
1137
- for (let e of i) await n(t, r(e), e);
1138
- }
1139
- for (let t of [
1140
- "emailProvider",
1141
- "branding",
1142
- "promptSettings"
1143
- ]) e[t] && await n(t, "singleton", e[t]);
1144
- return t;
1145
1192
  }
1146
- async function qe(e, t) {
1147
- let [n, r] = await Promise.all([Ke(e), Ke(t)]), i = [], a = new Set([...n.keys(), ...r.keys()]);
1148
- for (let e of a) {
1149
- let t = n.get(e) ?? /* @__PURE__ */ new Map(), a = r.get(e) ?? /* @__PURE__ */ new Map();
1150
- for (let n of new Set([...t.keys(), ...a.keys()])) {
1151
- let r = t.get(n), o = a.get(n);
1152
- if (r && !o) i.push({
1153
- entity: e,
1154
- key: n,
1155
- kind: "missing",
1156
- fields: [],
1157
- expected: !1
1158
- });
1159
- else if (!r && o) i.push({
1160
- entity: e,
1161
- key: n,
1162
- kind: "extra",
1163
- fields: [],
1164
- expected: Ge.has(e)
1165
- });
1166
- else if (r && o) {
1167
- let t = JSON.stringify(r), a = JSON.stringify(o);
1168
- if (t === a) continue;
1169
- let s = [...new Set([...Object.keys(r), ...Object.keys(o)])].filter((e) => JSON.stringify(r[e]) !== JSON.stringify(o[e])).sort();
1170
- i.push({
1171
- entity: e,
1172
- key: n,
1173
- kind: "changed",
1174
- fields: s,
1175
- expected: !1,
1176
- legacy_hash: await G(t),
1177
- new_hash: await G(a)
1178
- });
1179
- }
1180
- }
1193
+ async function mt(e, t, n) {
1194
+ let r = pt(e);
1195
+ if (!r) {
1196
+ await n(void 0);
1197
+ return;
1181
1198
  }
1182
- return i;
1183
- }
1184
- async function Je(e) {
1185
- let { adapters: t, tenantId: n, legacyControlPlane: r } = e, i = await De({
1186
- tenantId: n,
1187
- getTenant: (e) => t.tenants.get(e),
1188
- legacyControlPlane: r,
1189
- maxDepth: e.maxDepth
1190
- }), a = await W(t, n), o = await Promise.all(i.map((e) => W(t, e))), s = r && r !== n ? await W(t, r) : void 0, { hidden: c, ...l } = Le(o, a), u = new Set(c);
1191
- return (await qe(Ae(a, s), l)).filter((e) => !u.has(`${e.entity}:${e.key}`));
1192
- }
1193
- //#endregion
1194
- //#region src/inheritance/report.ts
1195
- var Ye = 3600 * 1e3, Xe = 1e4;
1196
- function Ze(e, t) {
1197
- let n = t.sample ?? 1, r = t.intervalMs ?? 6e4, i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map();
1198
- async function s(n, r) {
1199
- let i = await Je({
1200
- adapters: e,
1201
- tenantId: n,
1202
- legacyControlPlane: r
1203
- }), a = Date.now();
1204
- o.size > Xe && o.clear();
1205
- for (let s of i) {
1206
- if (s.expected && !t.includeExpected) continue;
1207
- let i = await G([
1208
- n,
1209
- s.entity,
1210
- s.key,
1211
- s.kind,
1212
- s.fields.join(",")
1213
- ].join("|")), c = o.get(i);
1214
- c !== void 0 && a - c < Ye || (o.set(i, a), await Qe(e, n, s, r));
1199
+ let i = A(r), a = async (e) => {
1200
+ try {
1201
+ await e();
1202
+ } catch (e) {
1203
+ console.warn("Failed to record tenant operation progress:", e);
1215
1204
  }
1205
+ }, o;
1206
+ if (await a(async () => {
1207
+ let e = await M(r, t, "inline");
1208
+ o = e.id, await i.markRunning(e.id);
1209
+ }), !o) {
1210
+ await n(void 0);
1211
+ return;
1216
1212
  }
1217
- return { schedule(e, t) {
1218
- if (a.has(e) || n < 1 && Math.random() >= n) return;
1219
- let o = Date.now(), c = i.get(e);
1220
- c !== void 0 && o - c < r || (i.set(e, o), a.add(e), s(e, t).catch(() => {}).finally(() => a.delete(e)));
1221
- } };
1222
- }
1223
- async function Qe(e, n, r, i) {
1224
- await e.logs.create(n, {
1225
- type: t.CONFIG_INHERITANCE_DIFF,
1226
- date: (/* @__PURE__ */ new Date()).toISOString(),
1227
- isMobile: !1,
1228
- description: `${r.kind} ${r.entity} ${r.key}`,
1229
- details: {
1230
- shadow: "config-inheritance",
1231
- legacy_control_plane: i,
1232
- ...r
1233
- }
1213
+ let s = o, c = !1, l = async (e, t, n) => {
1214
+ c = !0, await a(async () => {
1215
+ t === "started" && await i.setCurrentStep(s, e), await i.appendEvent(s, {
1216
+ step: e,
1217
+ outcome: t,
1218
+ detail: n
1219
+ });
1220
+ });
1221
+ };
1222
+ try {
1223
+ await n(l);
1224
+ } catch (e) {
1225
+ throw await a(async () => {
1226
+ c || await i.appendEvent(s, {
1227
+ step: t.kind,
1228
+ outcome: "failed",
1229
+ detail: { message: se(e) }
1230
+ }), await i.markFailed(s, e);
1231
+ }), e;
1232
+ }
1233
+ await a(async () => {
1234
+ c || await i.appendEvent(s, {
1235
+ step: t.kind,
1236
+ outcome: "succeeded"
1237
+ }), await i.markSucceeded(s);
1234
1238
  });
1235
1239
  }
1236
1240
  //#endregion
1237
- //#region src/middleware/settings-inheritance.ts
1238
- function q(e, t) {
1239
- let n = t.find((t) => t.strategy === e.strategy);
1240
- if (!n?.options) return e;
1241
- let r = c.passthrough().parse({
1242
- ...n,
1243
- ...e
1244
- });
1245
- return r.options = s.passthrough().parse({
1246
- ...n.options || {},
1247
- ...e.options
1248
- }), r;
1249
- }
1250
- function J(e, t) {
1251
- let n = [...t || [], ...e || []];
1252
- return [...new Set(n)];
1241
+ //#region src/hooks/provisioning.ts
1242
+ function ht(e) {
1243
+ return `urn:authhero:tenant:${e.toLowerCase()}`;
1253
1244
  }
1254
- function $e(e, t) {
1255
- if (!t?.length) return e || [];
1256
- if (!e?.length) return t;
1257
- let n = /* @__PURE__ */ new Map();
1258
- for (let e of t) n.set(e.value, e);
1259
- for (let t of e) n.set(t.value, t);
1260
- return Array.from(n.values());
1245
+ function gt(e) {
1246
+ return {
1247
+ async beforeCreate(e, t) {
1248
+ return !t.audience && t.id ? {
1249
+ ...t,
1250
+ audience: ht(t.id)
1251
+ } : t;
1252
+ },
1253
+ async afterCreate(t, i) {
1254
+ let { accessControl: a, databaseIsolation: o } = e;
1255
+ if (a && t.ctx && await _t(t, i, a), o?.onProvision) {
1256
+ let e = o.onProvision;
1257
+ o.recordProvisionOperations === !1 ? await e(i.id) : await mt(t.adapters, {
1258
+ kind: "provision",
1259
+ tenant_id: i.id,
1260
+ initiated_by: t.ctx?.var.user?.sub
1261
+ }, (t) => e(i.id, t));
1262
+ } else try {
1263
+ await te(t.adapters, i.id, {
1264
+ managementApiIdentifier: n,
1265
+ managementApiScopes: r
1266
+ });
1267
+ } catch (e) {
1268
+ throw console.warn(`Failed to provision default clients for tenant ${i.id}:`, e), e;
1269
+ }
1270
+ },
1271
+ async beforeDelete(t, n) {
1272
+ let { accessControl: r, databaseIsolation: i } = e;
1273
+ if (r) try {
1274
+ let e = (await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find((e) => e.name === n);
1275
+ e && await t.adapters.organizations.remove(r.controlPlaneTenantId, e.id);
1276
+ } catch (e) {
1277
+ console.warn(`Failed to remove organization for tenant ${n}:`, e);
1278
+ }
1279
+ if (i?.onDeprovision) try {
1280
+ await i.onDeprovision(n);
1281
+ } catch (e) {
1282
+ console.warn(`Failed to deprovision database for tenant ${n}:`, e);
1283
+ }
1284
+ }
1285
+ };
1261
1286
  }
1262
- function Y(e, t) {
1263
- return t ? {
1264
- ...e,
1265
- scopes: $e(e.scopes, t.scopes)
1266
- } : e;
1287
+ async function _t(e, t, n) {
1288
+ 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, {
1289
+ name: t.id,
1290
+ display_name: t.friendly_name || t.id
1291
+ }), d;
1292
+ if (o && (d = await yt(e, r, s, c)), l && e.ctx) {
1293
+ let t = e.ctx.var.user;
1294
+ if (t?.sub && !await vt(e, r, t.sub)) try {
1295
+ await e.adapters.userOrganizations.create(r, {
1296
+ user_id: t.sub,
1297
+ organization_id: u.id
1298
+ }), d && await e.adapters.userRoles.create(r, t.sub, d, u.id);
1299
+ } catch (e) {
1300
+ console.warn(`Failed to add creator ${t.sub} to organization ${u.id}:`, e);
1301
+ }
1302
+ }
1303
+ 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}`);
1267
1304
  }
1268
- function et(e, t) {
1269
- return t ? {
1270
- ...e,
1271
- callbacks: J(e.callbacks, t.callbacks),
1272
- web_origins: J(e.web_origins, t.web_origins),
1273
- allowed_logout_urls: J(e.allowed_logout_urls, t.allowed_logout_urls),
1274
- allowed_origins: J(e.allowed_origins, t.allowed_origins)
1275
- } : e;
1305
+ async function vt(e, t, r) {
1306
+ let i = await e.adapters.userRoles.list(t, r, void 0, "");
1307
+ for (let r of i) if ((await e.adapters.rolePermissions.list(t, r.id, { per_page: 1e3 })).some((e) => e.permission_name === "admin:organizations" && e.resource_server_identifier === n)) return !0;
1308
+ return !1;
1276
1309
  }
1277
- function tt(e) {
1278
- let { controlPlaneTenantId: t, controlPlaneClientId: n, resolveControlPlane: r } = e;
1279
- if (r) return async (e) => r({ tenant_id: e });
1280
- if (!t) return async () => void 0;
1281
- let i = {
1282
- tenantId: t,
1283
- clientId: n
1284
- };
1285
- return async () => i;
1310
+ async function yt(e, t, i, a) {
1311
+ let o = (await e.adapters.roles.list(t, {})).roles.find((e) => e.name === i);
1312
+ if (o) return o.id;
1313
+ let s = await e.adapters.roles.create(t, {
1314
+ name: i,
1315
+ description: a
1316
+ }), c = n, l = r.map((e) => ({
1317
+ role_id: s.id,
1318
+ resource_server_identifier: c,
1319
+ permission_name: e.value
1320
+ }));
1321
+ return await e.adapters.rolePermissions.assign(t, s.id, l), s.id;
1286
1322
  }
1287
- function nt(e, t) {
1288
- return {
1289
- ...e.resourceServers,
1290
- get: async (n, r) => {
1291
- let i = await e.resourceServers.get(n, r);
1292
- if (!i) return i;
1293
- let a = await t(n);
1294
- return !a || n === a.tenantId || !i.is_system ? i : Y(i, await e.resourceServers.get(a.tenantId, r));
1295
- },
1296
- list: async (n, r) => {
1297
- let i = await e.resourceServers.list(n, r), a = await t(n);
1298
- if (!a || n === a.tenantId) return i;
1299
- let o = a.tenantId, s = i.resource_servers.filter((e) => !!(e.is_system && e.id)).map((e) => e.id);
1300
- if (s.length === 0) return i;
1301
- let c = /* @__PURE__ */ new Map();
1302
- await Promise.all(s.map(async (t) => {
1303
- let n = await e.resourceServers.get(o, t);
1304
- n && c.set(t, n);
1305
- }));
1306
- let l = i.resource_servers.map((e) => e.is_system && e.id ? Y(e, c.get(e.id) ?? null) : e);
1307
- return {
1308
- ...i,
1309
- resource_servers: l
1310
- };
1323
+ //#endregion
1324
+ //#region src/hooks/sync.ts
1325
+ function bt(e, t, n = () => !0) {
1326
+ let { controlPlaneTenantId: r, getChildTenantIds: i, getAdapters: a } = e, o = /* @__PURE__ */ new Map();
1327
+ async function s(e, n, r) {
1328
+ return (await t(e).list(n, {
1329
+ q: `name:${p(r)}`,
1330
+ per_page: 1
1331
+ }))[0] ?? null;
1332
+ }
1333
+ async function c(e) {
1334
+ let n = await i(), o = t(await a(r));
1335
+ await Promise.all(n.map(async (n) => {
1336
+ try {
1337
+ let r = await a(n), i = t(r), c = {
1338
+ ...o.transform(e),
1339
+ is_system: !0
1340
+ }, l = await s(r, n, e.name), u = l ? i.getId(l) : void 0;
1341
+ if (l && u) {
1342
+ let e = i.preserveOnUpdate ? i.preserveOnUpdate(l, c) : c;
1343
+ await i.update(n, u, e);
1344
+ } else await i.create(n, c);
1345
+ } catch (t) {
1346
+ console.error(`Failed to sync ${o.listKey} "${e.name}" to tenant "${n}":`, t);
1347
+ }
1348
+ }));
1349
+ }
1350
+ async function l(e) {
1351
+ let n = await i();
1352
+ await Promise.all(n.map(async (n) => {
1353
+ try {
1354
+ let r = await a(n), i = t(r), o = await s(r, n, e), c = o ? i.getId(o) : void 0;
1355
+ o && c && await i.remove(n, c);
1356
+ } catch (t) {
1357
+ console.error(`Failed to delete entity "${e}" from tenant "${n}":`, t);
1358
+ }
1359
+ }));
1360
+ }
1361
+ return {
1362
+ afterCreate: async (e, t) => {
1363
+ e.tenantId === r && n(t) && await c(t);
1364
+ },
1365
+ afterUpdate: async (e, t, i) => {
1366
+ e.tenantId === r && n(i) && await c(i);
1367
+ },
1368
+ beforeDelete: async (e, i) => {
1369
+ if (e.tenantId !== r) return;
1370
+ let a = await t(e.adapters).get(e.tenantId, i);
1371
+ a && n(a) && o.set(i, a);
1372
+ },
1373
+ afterDelete: async (e, t) => {
1374
+ if (e.tenantId !== r) return;
1375
+ let n = o.get(t);
1376
+ n && (o.delete(t), await l(n.name));
1377
+ }
1378
+ };
1379
+ }
1380
+ function xt(e, t, n = () => !0) {
1381
+ let { controlPlaneTenantId: r, getControlPlaneAdapters: i, getAdapters: a } = e;
1382
+ return { async afterCreate(e, o) {
1383
+ if (o.id !== r) try {
1384
+ let e = await i(), s = await a(o.id), c = t(e), l = t(s), u = await m((e) => c.listPaginated(r, e), c.listKey, {
1385
+ cursorField: "id",
1386
+ pageSize: 100
1387
+ });
1388
+ await Promise.all(u.filter((e) => n(e)).map(async (e) => {
1389
+ try {
1390
+ let t = c.transform(e);
1391
+ await l.create(o.id, {
1392
+ ...t,
1393
+ is_system: !0
1394
+ });
1395
+ } catch (e) {
1396
+ console.error(`Failed to sync entity to new tenant "${o.id}":`, e);
1397
+ }
1398
+ }));
1399
+ } catch (e) {
1400
+ console.error(`Failed to sync entities to new tenant "${o.id}":`, e);
1401
+ }
1402
+ } };
1403
+ }
1404
+ var St = (e) => ({
1405
+ list: async (t, n) => (await e.resourceServers.list(t, n)).resource_servers,
1406
+ listPaginated: (t, n) => e.resourceServers.list(t, n),
1407
+ get: (t, n) => e.resourceServers.get(t, n),
1408
+ create: (t, n) => e.resourceServers.create(t, n),
1409
+ update: (t, n, r) => e.resourceServers.update(t, n, r),
1410
+ remove: (t, n) => e.resourceServers.remove(t, n),
1411
+ listKey: "resource_servers",
1412
+ getId: (e) => e.id,
1413
+ transform: (e) => ({
1414
+ id: e.id,
1415
+ name: e.name,
1416
+ identifier: e.identifier,
1417
+ scopes: e.scopes,
1418
+ signing_alg: e.signing_alg,
1419
+ token_lifetime: e.token_lifetime,
1420
+ token_lifetime_for_web: e.token_lifetime_for_web
1421
+ })
1422
+ }), Ct = (e) => ({
1423
+ list: async (t, n) => (await e.roles.list(t, n)).roles,
1424
+ listPaginated: (t, n) => e.roles.list(t, n),
1425
+ get: (t, n) => e.roles.get(t, n),
1426
+ create: (t, n) => e.roles.create(t, n),
1427
+ update: (t, n, r) => e.roles.update(t, n, r),
1428
+ remove: (t, n) => e.roles.remove(t, n),
1429
+ listKey: "roles",
1430
+ getId: (e) => e.id,
1431
+ transform: (e) => ({
1432
+ id: e.id,
1433
+ name: e.name,
1434
+ description: e.description
1435
+ })
1436
+ });
1437
+ function wt(e) {
1438
+ return e.metadata?.sync !== !1;
1439
+ }
1440
+ function Tt(e) {
1441
+ let { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, i = t.roles ?? !0, a = (e) => wt(e) ? n.resourceServers ? n.resourceServers(e) : !0 : !1, o = (e) => wt(e) ? n.roles ? n.roles(e) : !0 : !1, s = r ? bt(e, St, a) : void 0, c = i ? bt(e, Ct, o) : void 0, l = r ? xt(e, St, a) : void 0, u = i ? xt(e, Ct, o) : void 0, d = i ? { async afterCreate(t, r) {
1442
+ if (r.id !== e.controlPlaneTenantId) {
1443
+ await u?.afterCreate?.(t, r);
1444
+ try {
1445
+ let t = await e.getControlPlaneAdapters(), i = await e.getAdapters(r.id), a = await m((n) => t.roles.list(e.controlPlaneTenantId, n), "roles", {
1446
+ cursorField: "id",
1447
+ pageSize: 100
1448
+ }), o = /* @__PURE__ */ new Map();
1449
+ for (let e of a.filter((e) => n.roles?.(e) ?? !0)) {
1450
+ let t = await f(i, r.id, e.name);
1451
+ t && o.set(e.name, t.id);
1452
+ }
1453
+ for (let s of a.filter((e) => n.roles?.(e) ?? !0)) {
1454
+ let n = o.get(s.name);
1455
+ if (n) try {
1456
+ let a = await t.rolePermissions.list(e.controlPlaneTenantId, s.id, {});
1457
+ a.length > 0 && await i.rolePermissions.assign(r.id, n, a.map((e) => ({
1458
+ role_id: n,
1459
+ resource_server_identifier: e.resource_server_identifier,
1460
+ permission_name: e.permission_name
1461
+ })));
1462
+ } catch (e) {
1463
+ console.error(`Failed to sync permissions for role "${s.name}" to tenant "${r.id}":`, e);
1464
+ }
1465
+ }
1466
+ } catch (e) {
1467
+ console.error(`Failed to sync role permissions to tenant "${r.id}":`, e);
1468
+ }
1469
+ }
1470
+ } } : void 0;
1471
+ async function f(e, t, n) {
1472
+ return (await e.roles.list(t, {
1473
+ q: `name:${p(n)}`,
1474
+ per_page: 1
1475
+ })).roles[0] ?? null;
1476
+ }
1477
+ return {
1478
+ entityHooks: {
1479
+ resourceServers: s,
1480
+ roles: c
1481
+ },
1482
+ tenantHooks: { async afterCreate(e, t) {
1483
+ let n = [l?.afterCreate, d?.afterCreate ?? u?.afterCreate], r = [];
1484
+ for (let i of n) if (i) try {
1485
+ await i(e, t);
1486
+ } catch (e) {
1487
+ r.push(e instanceof Error ? e : Error(String(e)));
1488
+ }
1489
+ if (r.length === 1) throw r[0];
1490
+ if (r.length > 1) throw AggregateError(r, r.map((e) => e.message).join("; "));
1491
+ } }
1492
+ };
1493
+ }
1494
+ //#endregion
1495
+ //#region src/middleware/request-data.ts
1496
+ function q(e) {
1497
+ return e.var.data ?? e.env.data;
1498
+ }
1499
+ //#endregion
1500
+ //#region src/routes/tenants.ts
1501
+ var Et = D.object({
1502
+ sub: D.string(),
1503
+ tenant_id: D.string().optional(),
1504
+ org_id: D.string().optional(),
1505
+ scope: D.string().optional(),
1506
+ permissions: D.array(D.string()).optional()
1507
+ }).passthrough();
1508
+ function Dt(e) {
1509
+ let t = Et.safeParse(e);
1510
+ return t.success ? t.data : void 0;
1511
+ }
1512
+ function Ot(e, t, n) {
1513
+ return t ? !e || n ? !1 : e.tenant_id === t : !0;
1514
+ }
1515
+ function kt(e) {
1516
+ let t = e.permissions ?? [], n = e.scope ? e.scope.split(" ").filter(Boolean) : [], r = new Set([...t, ...n]);
1517
+ return r.has("delete:tenants") || r.has("admin:organizations");
1518
+ }
1519
+ function At(e, t) {
1520
+ let n = new T(), r = (t) => {
1521
+ let n = Dt(t.var.user);
1522
+ return Ot(n, e.accessControl?.controlPlaneTenantId ?? q(t).multiTenancyConfig?.controlPlaneTenantId, !!(n?.org_id ?? t.var.organization_id ?? t.var.org_name));
1523
+ };
1524
+ if (n.openapi(E({
1525
+ tags: ["tenants"],
1526
+ method: "get",
1527
+ path: "/",
1528
+ request: { query: a },
1529
+ security: [{ Bearer: [] }],
1530
+ responses: { 200: {
1531
+ content: { "application/json": { schema: D.object({
1532
+ tenants: D.array(C),
1533
+ start: D.number().optional(),
1534
+ limit: D.number().optional(),
1535
+ length: D.number().optional(),
1536
+ total: D.number().optional()
1537
+ }) } },
1538
+ description: "List of tenants"
1539
+ } }
1540
+ }), async (t) => {
1541
+ let { page: n, per_page: r, include_totals: i, q: a } = t.req.valid("query"), o = t.var.user, s = o?.permissions || [];
1542
+ if (!(o?.org_id ?? t.var.organization_id) && s.includes("admin:organizations")) {
1543
+ let e = await q(t).tenants.list({
1544
+ page: n,
1545
+ per_page: r,
1546
+ include_totals: i,
1547
+ q: a
1548
+ });
1549
+ return i ? t.json({
1550
+ tenants: e.tenants,
1551
+ start: e.totals?.start ?? 0,
1552
+ limit: e.totals?.limit ?? r,
1553
+ length: e.tenants.length,
1554
+ total: e.totals?.length
1555
+ }) : t.json({ tenants: e.tenants });
1556
+ }
1557
+ let c = e.accessControl?.controlPlaneTenantId ?? q(t).multiTenancyConfig?.controlPlaneTenantId;
1558
+ if (c && !o?.sub) throw new w(403, { message: "Access denied: token has no subject" });
1559
+ if (c && o?.sub) {
1560
+ let e = (await m((e) => q(t).userOrganizations.listUserOrganizations(c, o.sub, e), "organizations")).map((e) => e.name);
1561
+ if (e.length === 0) return i ? t.json({
1562
+ tenants: [],
1563
+ start: 0,
1564
+ limit: r ?? 50,
1565
+ length: 0,
1566
+ total: 0
1567
+ }) : t.json({ tenants: [] });
1568
+ let s = e.length, l = n ?? 0, u = r ?? 50, d = l * u, f = e.slice(d, d + u);
1569
+ if (f.length === 0) return i ? t.json({
1570
+ tenants: [],
1571
+ start: d,
1572
+ limit: u,
1573
+ length: 0,
1574
+ total: s
1575
+ }) : t.json({ tenants: [] });
1576
+ let p = f.map((e) => `id:${e}`).join(" OR "), h = a ? `(${p}) AND (${a})` : p, g = await q(t).tenants.list({
1577
+ q: h,
1578
+ per_page: u,
1579
+ include_totals: !1
1580
+ });
1581
+ return i ? t.json({
1582
+ tenants: g.tenants,
1583
+ start: d,
1584
+ limit: u,
1585
+ length: g.tenants.length,
1586
+ total: s
1587
+ }) : t.json({ tenants: g.tenants });
1588
+ }
1589
+ let l = await q(t).tenants.list({
1590
+ page: n,
1591
+ per_page: r,
1592
+ include_totals: i,
1593
+ q: a
1594
+ });
1595
+ return i ? t.json({
1596
+ tenants: l.tenants,
1597
+ start: l.totals?.start ?? 0,
1598
+ limit: l.totals?.limit ?? r,
1599
+ length: l.tenants.length,
1600
+ total: l.totals?.length
1601
+ }) : t.json({ tenants: l.tenants });
1602
+ }), n.openapi(E({
1603
+ tags: ["tenants"],
1604
+ method: "post",
1605
+ path: "/",
1606
+ request: { body: { content: { "application/json": { schema: S } } } },
1607
+ security: [{ Bearer: [] }],
1608
+ responses: {
1609
+ 201: {
1610
+ content: { "application/json": { schema: C } },
1611
+ description: "Tenant created"
1612
+ },
1613
+ 400: { description: "Validation error" },
1614
+ 409: { description: "Tenant with this ID already exists" }
1615
+ }
1616
+ }), async (n) => {
1617
+ if (!n.var.user?.sub) throw new w(401, { message: "Authentication required to create tenants" });
1618
+ let { config_sync_hash: i, config_synced_at: a, config_sync: o, ...s } = n.req.valid("json"), c = s;
1619
+ if (c.parent_tenant_id && !r(n)) throw new w(403, { message: "Only the control plane can set a tenant's parent" });
1620
+ o !== void 0 && r(n) && (c = {
1621
+ ...c,
1622
+ config_sync: o
1623
+ });
1624
+ let l = {
1625
+ adapters: q(n),
1626
+ ctx: n
1627
+ };
1628
+ t.tenants?.beforeCreate && (c = await t.tenants.beforeCreate(l, c)), await de({
1629
+ tenantId: c.id,
1630
+ parentTenantId: c.parent_tenant_id,
1631
+ getTenant: (e) => q(n).tenants.get(e)
1632
+ });
1633
+ let u = await q(n).tenants.create(c);
1634
+ return t.tenants?.afterCreate && await t.tenants.afterCreate(l, u), e.onConfigSyncChange?.(u.id), n.json(u, 201);
1635
+ }), n.openapi(E({
1636
+ tags: ["tenants"],
1637
+ method: "delete",
1638
+ path: "/{id}",
1639
+ request: { params: D.object({ id: D.string() }) },
1640
+ security: [{ Bearer: ["delete:tenants"] }],
1641
+ responses: {
1642
+ 204: { description: "Tenant deleted" },
1643
+ 403: { description: "Access denied or cannot delete the control plane" },
1644
+ 404: { description: "Tenant not found" }
1645
+ }
1646
+ }), async (n) => {
1647
+ let { id: r } = n.req.valid("param"), i = e.accessControl?.controlPlaneTenantId ?? q(n).multiTenancyConfig?.controlPlaneTenantId;
1648
+ if (i) {
1649
+ let e = Dt(n.var.user);
1650
+ if (!e?.sub) throw new w(401, { message: "Authentication required" });
1651
+ if (r === i) throw new w(403, { message: "Cannot delete the control plane" });
1652
+ let t = n.var.org_name, a = r.toLowerCase(), o = !!t && t.toLowerCase() === a;
1653
+ if (!o) {
1654
+ let r = !!(e.org_id ?? n.var.organization_id ?? t), a = !e.tenant_id || e.tenant_id === i;
1655
+ !r && a && kt(e) && (o = !0);
1656
+ }
1657
+ if (o ||= (await m((t) => q(n).userOrganizations.listUserOrganizations(i, e.sub, t), "organizations")).some((e) => e.name?.toLowerCase() === a), !o) throw new w(403, { message: "Access denied to this tenant" });
1658
+ }
1659
+ if (!await q(n).tenants.get(r)) throw new w(404, { message: "Tenant not found" });
1660
+ let a = {
1661
+ adapters: q(n),
1662
+ ctx: n
1663
+ };
1664
+ return t.tenants?.beforeDelete && await t.tenants.beforeDelete(a, r), await q(n).tenants.remove(r), t.tenants?.afterDelete && await t.tenants.afterDelete(a, r), n.body(null, 204);
1665
+ }), e.configSyncStatus) {
1666
+ let t = e.configSyncStatus;
1667
+ n.openapi(E({
1668
+ tags: ["tenants"],
1669
+ method: "get",
1670
+ path: "/{id}/config-sync",
1671
+ request: { params: D.object({ id: D.string() }) },
1672
+ security: [{ Bearer: ["read:tenants"] }],
1673
+ responses: {
1674
+ 200: {
1675
+ content: { "application/json": { schema: D.object({
1676
+ tenant_id: D.string(),
1677
+ parent_tenant_id: D.string().nullable(),
1678
+ config_sync: D.enum(["inherit-on-read", "synced"]),
1679
+ config_sync_hash: D.string().nullable(),
1680
+ config_synced_at: D.string().nullable(),
1681
+ expected_hash: D.string().nullable(),
1682
+ drifted: D.boolean(),
1683
+ chain: D.array(D.string()),
1684
+ inherited: D.record(D.string(), D.string())
1685
+ }) } },
1686
+ description: "Config sync status of the tenant"
1687
+ },
1688
+ 403: { description: "Not allowed to read this tenant" },
1689
+ 404: { description: "Tenant not found" }
1690
+ }
1691
+ }), async (e) => {
1692
+ let { id: n } = e.req.valid("param");
1693
+ if (n !== e.var.tenant_id && !r(e)) throw new w(403, { message: "Config sync status is only readable for your own tenant" });
1694
+ let i = await t(n);
1695
+ if (!i) throw new w(404, { message: "Tenant not found" });
1696
+ return e.json(i);
1697
+ });
1698
+ }
1699
+ return n.openapi(E({
1700
+ tags: ["tenants", "settings"],
1701
+ method: "get",
1702
+ path: "/settings",
1703
+ request: { headers: D.object({ "tenant-id": D.string().optional() }) },
1704
+ security: [{ Bearer: ["read:tenants"] }],
1705
+ responses: { 200: {
1706
+ content: { "application/json": { schema: C } },
1707
+ description: "Current tenant settings"
1708
+ } }
1709
+ }), async (e) => {
1710
+ let t = await q(e).tenants.get(e.var.tenant_id);
1711
+ if (!t) throw new w(404, { message: "Tenant not found" });
1712
+ return e.json(t);
1713
+ }), n.openapi(E({
1714
+ tags: ["tenants", "settings"],
1715
+ method: "patch",
1716
+ path: "/settings",
1717
+ request: {
1718
+ headers: D.object({ "tenant-id": D.string().optional() }),
1719
+ body: { content: { "application/json": { schema: D.object(S.shape).partial() } } }
1720
+ },
1721
+ security: [{ Bearer: ["update:tenants"] }],
1722
+ responses: { 200: {
1723
+ content: { "application/json": { schema: C } },
1724
+ description: "Updated tenant settings"
1725
+ } }
1726
+ }), async (t) => {
1727
+ let { id: n, config_sync_hash: i, config_synced_at: a, ...o } = t.req.valid("json"), s = await q(t).tenants.get(t.var.tenant_id);
1728
+ if (!s) throw new w(404, { message: "Tenant not found" });
1729
+ if ("config_sync" in o && (o.config_sync ?? "inherit-on-read") !== (s.config_sync ?? "inherit-on-read") && !r(t)) throw new w(403, { message: "Only the control plane can change a tenant's config_sync mode" });
1730
+ if ("default_client_id" in o) {
1731
+ let e = o.default_client_id;
1732
+ if (typeof e == "string" && e.length > 0) {
1733
+ let n = await q(t).clients.get(t.var.tenant_id, e);
1734
+ if (!n) throw new w(400, { message: `Client with id '${e}' not found` });
1735
+ if (!v(n)) throw new w(400, { message: `Client '${e}' is not an interactive client and cannot be used as the default client` });
1736
+ }
1737
+ }
1738
+ if ("parent_tenant_id" in o) {
1739
+ if ((o.parent_tenant_id ?? null) !== (s.parent_tenant_id ?? null) && !r(t)) throw new w(403, { message: "Only the control plane can change a tenant's parent" });
1740
+ await de({
1741
+ tenantId: t.var.tenant_id,
1742
+ parentTenantId: o.parent_tenant_id,
1743
+ getTenant: (e) => q(t).tenants.get(e),
1744
+ getChildren: async (e) => (await m((e) => q(t).tenants.list(e), "tenants")).filter((t) => t.parent_tenant_id === e).map((e) => e.id)
1745
+ });
1746
+ }
1747
+ let c = d(s, o);
1748
+ await q(t).tenants.update(t.var.tenant_id, c), "config_sync" in o && e.onConfigSyncChange?.(t.var.tenant_id);
1749
+ let l = await q(t).tenants.get(t.var.tenant_id);
1750
+ if (!l) throw new w(500, { message: "Failed to retrieve updated tenant" });
1751
+ return t.json(l);
1752
+ }), n;
1753
+ }
1754
+ //#endregion
1755
+ //#region src/middleware/protect-synced.ts
1756
+ function jt(e) {
1757
+ for (let { pattern: t, type: n } of [
1758
+ {
1759
+ pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
1760
+ type: "resource_server"
1761
+ },
1762
+ {
1763
+ pattern: /\/api\/v2\/roles\/([^/]+)$/,
1764
+ type: "role"
1765
+ },
1766
+ {
1767
+ pattern: /\/api\/v2\/connections\/([^/]+)$/,
1768
+ type: "connection"
1769
+ }
1770
+ ]) {
1771
+ let r = e.match(t);
1772
+ if (r && r[1]) return {
1773
+ type: n,
1774
+ id: r[1]
1775
+ };
1776
+ }
1777
+ return null;
1778
+ }
1779
+ async function Mt(e, t, n) {
1780
+ try {
1781
+ switch (n.type) {
1782
+ case "resource_server": return (await e.resourceServers.get(t, n.id))?.is_system === !0;
1783
+ case "role": return (await e.roles.get(t, n.id))?.is_system === !0;
1784
+ case "connection": return (await e.connections.get(t, n.id))?.is_system === !0;
1785
+ default: return !1;
1311
1786
  }
1312
- };
1787
+ } catch {
1788
+ return !1;
1789
+ }
1313
1790
  }
1314
- function rt(e, t) {
1315
- let n = tt({
1316
- controlPlaneTenantId: t.controlPlaneTenantId,
1317
- resolveControlPlane: t.resolveControlPlane
1318
- });
1791
+ function Nt(e) {
1319
1792
  return {
1320
- ...e,
1321
- resourceServers: nt(e, n)
1322
- };
1793
+ resource_server: "resource server",
1794
+ role: "role",
1795
+ connection: "connection"
1796
+ }[e];
1323
1797
  }
1324
- function it(e, t) {
1325
- let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i, inheritanceShadow: a } = t, o = tt({
1326
- controlPlaneTenantId: n,
1327
- controlPlaneClientId: r,
1328
- resolveControlPlane: i
1329
- }), s = a ? Ze(e, a === !0 ? {} : a) : void 0, c = s ? async (e) => {
1330
- let t = await o(e);
1331
- return s.schedule(e, t?.tenantId), t;
1332
- } : o;
1333
- return {
1334
- ...e,
1335
- multiTenancyConfig: {
1336
- controlPlaneTenantId: n,
1337
- controlPlaneClientId: r,
1338
- resolveControlPlane: i
1798
+ function Pt(e) {
1799
+ for (let { pattern: t, type: n } of [
1800
+ {
1801
+ pattern: /\/api\/v2\/connections\/([^/]+)$/,
1802
+ type: "connection"
1339
1803
  },
1340
- connections: {
1341
- ...e.connections,
1342
- get: async (t, n) => {
1343
- let r = await e.connections.get(t, n);
1344
- if (!r) return r;
1345
- let i = await c(t);
1346
- return !i || t === i.tenantId ? r : q(r, (await e.connections.list(i.tenantId)).connections || []);
1347
- },
1348
- list: async (t, n) => {
1349
- let r = await e.connections.list(t, n), i = await c(t);
1350
- if (!i || t === i.tenantId) return r;
1351
- let a = await e.connections.list(i.tenantId), o = r.connections.map((e) => q(e, a.connections || []));
1352
- return {
1353
- ...r,
1354
- connections: o
1355
- };
1356
- }
1804
+ {
1805
+ pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
1806
+ type: "resource_server"
1357
1807
  },
1358
- clientConnections: {
1359
- ...e.clientConnections,
1360
- listByClient: async (t, n) => {
1361
- let r = await e.clientConnections.listByClient(t, n);
1362
- r.length === 0 && (r = (await e.connections.list(t)).connections || []);
1363
- let i = await c(t);
1364
- if (!i || t === i.tenantId) return r;
1365
- let a = await e.connections.list(i.tenantId);
1366
- return r.map((e) => q(e, a.connections || []));
1367
- }
1808
+ {
1809
+ pattern: /\/api\/v2\/actions\/actions\/([^/]+)$/,
1810
+ type: "action"
1368
1811
  },
1369
- emailProviders: {
1370
- ...e.emailProviders,
1371
- get: async (t) => {
1372
- let n = await e.emailProviders.get(t);
1373
- if (n) return n;
1374
- let r = await c(t);
1375
- return !r || t === r.tenantId ? null : e.emailProviders.get(r.tenantId);
1376
- }
1812
+ {
1813
+ pattern: /\/api\/v2\/hooks\/([^/]+)$/,
1814
+ type: "hook"
1377
1815
  },
1378
- resourceServers: nt(e, c),
1379
- hooks: at(e, c)
1380
- };
1381
- }
1382
- function X(e) {
1383
- if (!e || typeof e != "object") return !1;
1384
- let t = e.metadata;
1385
- return !t || typeof t != "object" ? !1 : t.inheritable === !0;
1816
+ {
1817
+ pattern: /\/api\/v2\/hook-code\/([^/]+)$/,
1818
+ type: "hook_code"
1819
+ }
1820
+ ]) {
1821
+ let r = e.match(t);
1822
+ if (r?.[1]) return {
1823
+ type: n,
1824
+ id: r[1]
1825
+ };
1826
+ }
1827
+ return null;
1386
1828
  }
1387
- function at(e, t) {
1388
- return {
1389
- ...e.hooks,
1390
- list: async (n, r) => {
1391
- let i = await e.hooks.list(n, r), a = await t(n);
1392
- if (!a || n === a.tenantId) return i;
1393
- let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(X);
1394
- if (o.length === 0) return i;
1395
- let s = new Set((i.hooks || []).map((e) => e.hook_id)), c = o.filter((e) => !s.has(e.hook_id));
1396
- return {
1397
- ...i,
1398
- hooks: [...i.hooks || [], ...c],
1399
- length: typeof i.length == "number" ? i.length + c.length : i.length
1400
- };
1401
- },
1402
- get: async (n, r) => {
1403
- let i = await e.hooks.get(n, r);
1404
- if (i) return i;
1405
- let a = await t(n);
1406
- if (!a || n === a.tenantId) return i;
1407
- let o = await e.hooks.get(a.tenantId, r);
1408
- return o && X(o) ? o : null;
1829
+ async function Ft(e, t, n) {
1830
+ try {
1831
+ switch (n.type) {
1832
+ case "connection": return await e.connections.get(t, n.id);
1833
+ case "resource_server": return await e.resourceServers.get(t, n.id);
1834
+ case "action": return await e.actions.get(t, n.id);
1835
+ case "hook": return await e.hooks.get(t, n.id);
1836
+ case "hook_code": return await e.hookCode.get(t, n.id);
1409
1837
  }
1838
+ } catch {
1839
+ return null;
1840
+ }
1841
+ }
1842
+ var It = {
1843
+ connection: ["options"],
1844
+ resource_server: ["signing_secret"],
1845
+ action: ["secrets"],
1846
+ hook: [],
1847
+ hook_code: []
1848
+ }, Lt = new Set([
1849
+ "client_secret",
1850
+ "app_secret",
1851
+ "twilio_token"
1852
+ ]);
1853
+ function Rt(e, t) {
1854
+ let n = (e) => {
1855
+ let { client_secret: t, ...n } = e ?? {};
1856
+ return n;
1410
1857
  };
1858
+ return zt(n(e), n(t));
1859
+ }
1860
+ var zt = (e, t) => JSON.stringify(e) === JSON.stringify(t);
1861
+ function J(e, t) {
1862
+ return new w(403, { message: `This ${e.type.replace("_", " ")} is synced from a parent tenant and ${t}. Make changes in the parent tenant instead.` });
1863
+ }
1864
+ async function Bt(e, t, n) {
1865
+ let r = await Ft(q(e), t, n);
1866
+ if (!r) return;
1867
+ if (n.type === "hook_code") throw J(n, "cannot be modified");
1868
+ if (e.req.method === "DELETE") {
1869
+ if (r.enforce === !0) throw J(n, "cannot be deleted");
1870
+ return;
1871
+ }
1872
+ let i = r.override ?? "fields";
1873
+ if (i === "none") throw J(n, "cannot be edited");
1874
+ let a = {};
1875
+ try {
1876
+ let t = await e.req.raw.clone().json();
1877
+ t && typeof t == "object" && (a = t);
1878
+ } catch {}
1879
+ for (let e of [
1880
+ "scope",
1881
+ "override",
1882
+ "enforce"
1883
+ ]) if (e in a && !zt(a[e] ?? null, r[e] ?? null)) throw J(n, `has a locked ${e}`);
1884
+ if (r.enforce === !0 && a.enabled === !1) throw J(n, "cannot be disabled");
1885
+ if (i === "secrets") {
1886
+ let e = It[n.type];
1887
+ for (let [t, i] of Object.entries(a)) if (![
1888
+ "scope",
1889
+ "override",
1890
+ "enforce"
1891
+ ].includes(t) && !zt(i, r[t])) {
1892
+ if (!e.includes(t)) throw J(n, `only allows its secrets to be changed (not ${t})`);
1893
+ if (t === "options" && i && typeof i == "object") {
1894
+ let e = r.options ?? {};
1895
+ for (let [t, r] of Object.entries(i)) if (!zt(r, e[t]) && !t.endsWith("_hint") && !(Lt.has(t) || t === "configuration" && Rt(r, e[t]))) throw J(n, `only allows its secrets to be changed (not options.${t})`);
1896
+ }
1897
+ }
1898
+ }
1411
1899
  }
1412
- function Z(e, t) {
1413
- return it(e, t);
1900
+ function Vt() {
1901
+ return async (e, t) => {
1902
+ if (![
1903
+ "PATCH",
1904
+ "PUT",
1905
+ "DELETE"
1906
+ ].includes(e.req.method)) return t();
1907
+ let n = jt(e.req.path), r = Pt(e.req.path);
1908
+ if (!n && !r) return t();
1909
+ let i = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
1910
+ if (!i) return t();
1911
+ if (n && await Mt(q(e), i, n)) throw new w(403, { message: `This ${Nt(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.` });
1912
+ return r && y(r.id) && await Bt(e, i, r), t();
1913
+ };
1414
1914
  }
1415
1915
  //#endregion
1416
1916
  //#region src/middleware/index.ts
1417
- function ot(e) {
1917
+ function Ht(e) {
1418
1918
  return async (t, n) => {
1419
1919
  let r = t.var.user;
1420
1920
  return r?.tenant_id === e && r.org_name && t.set("tenant_id", r.org_name), n();
1421
1921
  };
1422
1922
  }
1423
- function st(e) {
1923
+ function Ut(e) {
1424
1924
  return async (t, r) => {
1425
1925
  if (!e.accessControl) return r();
1426
1926
  let { controlPlaneTenantId: i } = e.accessControl, a = t.var.org_name, o = t.var.organization_id, s = a || o, c = t.var.tenant_id, l = t.var.user, u = (l?.aud ? Array.isArray(l.aud) ? l.aud : [l.aud] : []).includes(n);
1427
- if (!c && s && u && (t.set("tenant_id", s), c = s), !c) throw new T(400, { message: "Tenant ID not found in request" });
1428
- if (!D(o, c, i, a)) throw new T(403, { message: `Access denied to tenant ${c}` });
1927
+ if (!c && s && u && (t.set("tenant_id", s), c = s), !c) throw new w(400, { message: "Tenant ID not found in request" });
1928
+ if (!O(o, c, i, a)) throw new w(403, { message: `Access denied to tenant ${c}` });
1429
1929
  return r();
1430
1930
  };
1431
1931
  }
1432
- function ct(e) {
1932
+ function Wt(e) {
1433
1933
  return async (t, n) => {
1434
1934
  if (!e.subdomainRouting) return n();
1435
1935
  let { baseDomain: r, reservedSubdomains: i = [], resolveSubdomain: a } = e.subdomainRouting, o = t.req.header("x-forwarded-host") || t.req.header("host") || "", s = null;
@@ -1441,18 +1941,18 @@ function ct(e) {
1441
1941
  let c = null;
1442
1942
  if (a) c = await a(s);
1443
1943
  else if (e.subdomainRouting.useOrganizations !== !1 && e.accessControl) try {
1444
- let n = await P(t).organizations.get(e.accessControl.controlPlaneTenantId, s);
1944
+ let n = await q(t).organizations.get(e.accessControl.controlPlaneTenantId, s);
1445
1945
  n && (c = n.id);
1446
1946
  } catch {}
1447
- if (!c) throw new T(404, { message: `Tenant not found for subdomain: ${s}` });
1947
+ if (!c) throw new w(404, { message: `Tenant not found for subdomain: ${s}` });
1448
1948
  return t.set("tenant_id", c), n();
1449
1949
  };
1450
1950
  }
1451
- function lt(e) {
1951
+ function Gt(e) {
1452
1952
  return async (t, n) => {
1453
1953
  if (!e.databaseIsolation) return n();
1454
1954
  let r = t.var.tenant_id;
1455
- if (!r) throw new T(400, { message: "Tenant ID not found in request" });
1955
+ if (!r) throw new w(400, { message: "Tenant ID not found in request" });
1456
1956
  try {
1457
1957
  let n = await e.databaseIsolation.getAdapters(r);
1458
1958
  t.set("baseData", n), t.env = {
@@ -1460,131 +1960,674 @@ function lt(e) {
1460
1960
  data: n
1461
1961
  };
1462
1962
  } catch (e) {
1463
- throw console.error(`Failed to resolve database for tenant ${r}:`, e), new T(500, { message: "Failed to resolve tenant database" });
1963
+ throw console.error(`Failed to resolve database for tenant ${r}:`, e), new w(500, { message: "Failed to resolve tenant database" });
1464
1964
  }
1465
1965
  return n();
1466
1966
  };
1467
1967
  }
1468
- function Q(e) {
1469
- let t = ct(e), n = st(e), r = lt(e);
1968
+ function Kt(e) {
1969
+ let t = Wt(e), n = Ut(e), r = Gt(e);
1470
1970
  return async (e, i) => (await t(e, async () => {}), await n(e, async () => {}), await r(e, async () => {}), i());
1471
1971
  }
1472
1972
  //#endregion
1973
+ //#region src/rollouts/config.ts
1974
+ var qt = [
1975
+ 10,
1976
+ 50,
1977
+ 100
1978
+ ], Y = {
1979
+ canary: 1,
1980
+ waves: qt,
1981
+ failure_threshold: .1,
1982
+ max_concurrent: 25,
1983
+ debounce_ms: 6e4
1984
+ };
1985
+ function X(e) {
1986
+ let t = e.config ?? {};
1987
+ return {
1988
+ ...Y,
1989
+ trigger: "manual",
1990
+ root_tenant_id: "",
1991
+ ...t,
1992
+ waves: Array.isArray(t.waves) && t.waves.length > 0 ? t.waves : [...qt]
1993
+ };
1994
+ }
1995
+ function Jt(e, t, n) {
1996
+ let r = Array(e).fill(0);
1997
+ if (e === 0) return r;
1998
+ let i = Math.min(Math.max(t, 0), e), a = [], o = i;
1999
+ for (let t of n) {
2000
+ let n = Math.min(e, Math.max(o, Math.ceil(e * t / 100)));
2001
+ n > o && (a.push(n), o = n);
2002
+ }
2003
+ o < e && a.push(e);
2004
+ let s = +(i > 0), c = i;
2005
+ for (let e of a) {
2006
+ for (; c < e; c++) r[c] = s;
2007
+ s++;
2008
+ }
2009
+ return r;
2010
+ }
2011
+ //#endregion
2012
+ //#region src/rollouts/enumerate.ts
2013
+ async function Yt(e, t, n) {
2014
+ let r = n.maxDepth ?? 8, i = await m((t) => e.tenants.list(t), "tenants", {
2015
+ cursorField: "id",
2016
+ pageSize: 100
2017
+ }), a = new Map(i.map((e) => [e.id, e])), o = async (e) => e.parent_tenant_id ?? (e.id === t ? void 0 : await n.resolveLegacyParent(e.id)), s = [];
2018
+ for (let e of i) {
2019
+ if (e.id === t || e.config_sync !== "synced") continue;
2020
+ let n = 0, i = e, c = !1;
2021
+ for (; i && n <= r;) {
2022
+ let e = await o(i);
2023
+ if (!e) break;
2024
+ if (n++, e === t) {
2025
+ c = !0;
2026
+ break;
2027
+ }
2028
+ i = a.get(e);
2029
+ }
2030
+ c && s.push({
2031
+ tenantId: e.id,
2032
+ depth: n,
2033
+ appliedHash: e.config_sync_hash ?? null
2034
+ });
2035
+ }
2036
+ return s.sort((e, t) => e.depth - t.depth || (e.tenantId < t.tenantId ? -1 : 1));
2037
+ }
2038
+ //#endregion
2039
+ //#region src/rollouts/hashes.ts
2040
+ async function Xt(e, t) {
2041
+ return e.resolveControlPlane ? (await e.resolveControlPlane({ tenant_id: t }))?.tenantId : e.controlPlaneTenantId;
2042
+ }
2043
+ function Zt(e) {
2044
+ let t = /* @__PURE__ */ new Map();
2045
+ return async (n) => {
2046
+ let r = await Xt(e, n), i = (await N({
2047
+ tenantId: n,
2048
+ getTenant: (t) => e.adapters.tenants.get(t),
2049
+ legacyControlPlane: r,
2050
+ maxDepth: e.maxDepth
2051
+ })).join(">"), a = t.get(i);
2052
+ return a || (a = et(e.adapters, n, {
2053
+ legacyControlPlane: r,
2054
+ maxDepth: e.maxDepth
2055
+ }).then((e) => e.hash), t.set(i, a)), a;
2056
+ };
2057
+ }
2058
+ //#endregion
2059
+ //#region src/rollouts/plan.ts
2060
+ var Qt = [
2061
+ "pending",
2062
+ "canary",
2063
+ "rolling",
2064
+ "paused"
2065
+ ];
2066
+ function $t(e) {
2067
+ let { tenantOperations: t, tenantOperationEvents: n } = e.adapters;
2068
+ if (!t || !n) throw Error("Fleet rollouts need the tenant operations adapters");
2069
+ return {
2070
+ tenantOperations: t,
2071
+ tenantOperationEvents: n
2072
+ };
2073
+ }
2074
+ function Z(e) {
2075
+ if (!e.adapters.rollouts) throw Error("Fleet rollouts need the rollouts adapter");
2076
+ return e.adapters.rollouts;
2077
+ }
2078
+ async function en(e, t, n = {}) {
2079
+ let r = Z(e), i = $t(e), a = X(t), o = await Yt(e.adapters, a.root_tenant_id, {
2080
+ resolveLegacyParent: (t) => Xt(e, t),
2081
+ maxDepth: e.maxDepth
2082
+ });
2083
+ if (n.tenantIds) {
2084
+ let e = new Set(n.tenantIds);
2085
+ o = o.filter((t) => e.has(t.tenantId));
2086
+ }
2087
+ let s = Zt(e), c = [];
2088
+ for (let e of o) (a.force || e.appliedHash !== await s(e.tenantId)) && c.push(e);
2089
+ let l = o.length - c.length;
2090
+ if (c.length === 0) return a.trigger === "write" ? await r.remove(t.id) : await r.update(t.id, {
2091
+ status: "done",
2092
+ finished_at: new Date(e.now?.() ?? Date.now()).toISOString(),
2093
+ config: {
2094
+ ...a,
2095
+ planned: !0,
2096
+ tenant_count: 0
2097
+ }
2098
+ }), {
2099
+ planned: 0,
2100
+ upToDate: l
2101
+ };
2102
+ let u = new Set((await Q(e, t.id)).map((e) => e.tenant_id)), d = Jt(c.length, a.canary, a.waves);
2103
+ for (let [n, r] of c.entries()) u.has(r.tenantId) || await M(i, {
2104
+ kind: "sync-defaults",
2105
+ tenant_id: r.tenantId,
2106
+ rollout_id: t.id,
2107
+ initiated_by: `rollout:${t.id}`,
2108
+ input: {
2109
+ wave: d[n],
2110
+ ...a.dry_run ? { dry_run: !0 } : {},
2111
+ ...a.force ? { force: !0 } : {}
2112
+ }
2113
+ }, e.executor.engine);
2114
+ return await r.update(t.id, {
2115
+ status: "canary",
2116
+ config: {
2117
+ ...a,
2118
+ planned: !0,
2119
+ tenant_count: c.length
2120
+ }
2121
+ }), {
2122
+ planned: c.length,
2123
+ upToDate: l
2124
+ };
2125
+ }
2126
+ async function Q(e, t) {
2127
+ let { tenantOperations: n } = $t(e), r = [];
2128
+ for (let e = 0;; e++) {
2129
+ let { operations: i } = await n.list({
2130
+ rollout_id: t,
2131
+ page: e,
2132
+ per_page: 200
2133
+ });
2134
+ if (r.push(...i), i.length < 200) break;
2135
+ }
2136
+ 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);
2137
+ }
2138
+ //#endregion
2139
+ //#region src/rollouts/advance.ts
2140
+ var $ = (e) => {
2141
+ let t = e.input?.wave;
2142
+ return typeof t == "number" ? t : 0;
2143
+ }, tn = (e) => e.status === "failed" || e.status === "cancelled";
2144
+ function nn(e, t, n) {
2145
+ let r = t.filter((e) => $(e) === n), i = r.filter(tn).length, a = n === 0 && e.canary > 0, o = a ? 0 : e.failure_threshold;
2146
+ return r.length === 0 || i === 0 || i / r.length <= o ? null : `${a ? "canary" : `wave ${n}`} failed for ${i} of ${r.length} tenant(s)`;
2147
+ }
2148
+ async function rn(e, t) {
2149
+ let n = Z(e), r = e.now?.() ?? Date.now(), i = typeof t == "string" ? await n.get(t) : t;
2150
+ if (!i || i.kind !== "config-sync") return {
2151
+ rolloutId: String(i?.id ?? t),
2152
+ outcome: "skipped",
2153
+ started: 0
2154
+ };
2155
+ let a = i.id;
2156
+ if (!Qt.includes(i.status) || i.status === "paused") return {
2157
+ rolloutId: a,
2158
+ outcome: "skipped",
2159
+ started: 0
2160
+ };
2161
+ let o = X(i);
2162
+ if (!o.planned) {
2163
+ if (r - Date.parse(i.updated_at) < o.debounce_ms) return {
2164
+ rolloutId: a,
2165
+ outcome: "waiting",
2166
+ started: 0
2167
+ };
2168
+ let { planned: t } = await en(e, i);
2169
+ if (t === 0) return {
2170
+ rolloutId: a,
2171
+ outcome: "planned-empty",
2172
+ started: 0
2173
+ };
2174
+ i = await n.get(a) ?? i, o = X(i);
2175
+ }
2176
+ let s = await Q(e, a), c = s.filter((e) => !j(e.status));
2177
+ if (c.length === 0) {
2178
+ let e = Math.max(0, ...s.map($)), t = s.length > 0 && e > (o.accepted_through ?? -1) ? nn(o, s, e) : null;
2179
+ return await n.update(a, {
2180
+ status: t ? "failed" : "done",
2181
+ ...t ? { paused_reason: t } : {},
2182
+ finished_at: new Date(r).toISOString()
2183
+ }), {
2184
+ rolloutId: a,
2185
+ outcome: "done",
2186
+ started: 0
2187
+ };
2188
+ }
2189
+ let l = Math.min(...c.map($)), u = l - 1;
2190
+ if (u >= 0 && u > (o.accepted_through ?? -1)) {
2191
+ let e = nn(o, s, u);
2192
+ if (e) return await n.update(a, {
2193
+ status: "paused",
2194
+ paused_reason: e
2195
+ }), {
2196
+ rolloutId: a,
2197
+ outcome: "paused",
2198
+ started: 0,
2199
+ wave: l
2200
+ };
2201
+ }
2202
+ let d = l === 0 ? "canary" : "rolling";
2203
+ i.status !== d && await n.update(a, { status: d });
2204
+ let f = c.filter((e) => $(e) === l), p = f.filter((e) => e.status === "running").length, m = Math.max(0, o.max_concurrent - p), { tenantOperations: h, tenantOperationEvents: g } = $t(e), _ = A({
2205
+ tenantOperations: h,
2206
+ tenantOperationEvents: g
2207
+ }), v = 0;
2208
+ for (let t of f.filter((e) => e.status === "pending").slice(0, m)) {
2209
+ try {
2210
+ await _.markRunning(t.id), await e.executor.start(t);
2211
+ } catch (e) {
2212
+ try {
2213
+ let n = await h.get(t.id);
2214
+ n && !j(n.status) && await _.markFailed(t.id, e);
2215
+ } catch {}
2216
+ }
2217
+ v++;
2218
+ }
2219
+ return {
2220
+ rolloutId: a,
2221
+ outcome: v > 0 ? "started" : "running",
2222
+ started: v,
2223
+ wave: l
2224
+ };
2225
+ }
2226
+ async function an(e, t = {}) {
2227
+ let { rollouts: n } = await Z(e).list({
2228
+ kind: "config-sync",
2229
+ status: [
2230
+ "pending",
2231
+ "canary",
2232
+ "rolling"
2233
+ ],
2234
+ per_page: t.limit ?? 20
2235
+ }), r = [];
2236
+ for (let i of n) try {
2237
+ r.push(await rn(e, i));
2238
+ } catch (e) {
2239
+ t.logger?.warn(`Advancing rollout ${i.id} failed:`, e);
2240
+ }
2241
+ return r;
2242
+ }
2243
+ async function on(e, t, n = "paused by an operator") {
2244
+ let r = Z(e), i = await r.get(t);
2245
+ return !i || i.kind !== "config-sync" ? null : i.status === "done" || i.status === "failed" ? i : (await r.update(t, {
2246
+ status: "paused",
2247
+ paused_reason: n
2248
+ }), r.get(t));
2249
+ }
2250
+ async function sn(e, t) {
2251
+ let n = Z(e), r = await n.get(t);
2252
+ if (!r || r.kind !== "config-sync") return null;
2253
+ if (r.status !== "paused") return r;
2254
+ let i = X(r), a = (await Q(e, t)).filter((e) => !j(e.status)), o = a.length > 0 ? Math.min(...a.map($)) : 0;
2255
+ return await n.update(t, {
2256
+ status: o === 0 ? "canary" : "rolling",
2257
+ paused_reason: null,
2258
+ config: {
2259
+ ...i,
2260
+ accepted_through: Math.max(i.accepted_through ?? -1, o - 1)
2261
+ }
2262
+ }), n.get(t);
2263
+ }
2264
+ //#endregion
2265
+ //#region src/rollouts/status.ts
2266
+ async function cn(e, t) {
2267
+ let n = await e.adapters.tenants.get(t);
2268
+ if (!n) return null;
2269
+ let r = n.config_sync === "synced", i = await N({
2270
+ tenantId: t,
2271
+ getTenant: (t) => e.adapters.tenants.get(t),
2272
+ legacyControlPlane: await Xt(e, t),
2273
+ maxDepth: e.maxDepth
2274
+ }), a = r ? await Zt(e)(t) : null, o = n.config_sync_hash ?? null, s = {};
2275
+ for (let n of [...i].reverse()) {
2276
+ let r = await I(e.adapters, n), i = (e, t) => V(e, t) === "shared", a = async (e, r, a) => {
2277
+ for (let o of r) {
2278
+ let r = o.id ?? o.hook_id;
2279
+ r && y(r) || i(a, o) && (s[await W(e, t, G(e, o))] = n);
2280
+ }
2281
+ };
2282
+ await a("connection", r.connections, "connection"), await a("resourceServer", r.resourceServers, "resourceServer"), await a("action", r.actions, "action"), await a("hook", r.hooks, "hook"), r.emailProvider && i("emailProvider", r.emailProvider) && (s.emailProvider = n), r.branding && i("branding", r.branding) && (s.branding = n), r.promptSettings && i("promptSettings", r.promptSettings) && (s.promptSettings = n);
2283
+ }
2284
+ return {
2285
+ tenant_id: t,
2286
+ parent_tenant_id: n.parent_tenant_id ?? null,
2287
+ config_sync: r ? "synced" : "inherit-on-read",
2288
+ config_sync_hash: o,
2289
+ config_synced_at: n.config_synced_at ?? null,
2290
+ expected_hash: a,
2291
+ drifted: r && a !== o,
2292
+ chain: i,
2293
+ inherited: s
2294
+ };
2295
+ }
2296
+ //#endregion
2297
+ //#region src/rollouts/reconcile.ts
2298
+ async function ln(e, n = {}) {
2299
+ let r = Z(e), i = n.rootTenantId ?? e.controlPlaneTenantId, a = n.limit ?? 500, o = await Yt(e.adapters, i, {
2300
+ resolveLegacyParent: (t) => Xt(e, t),
2301
+ maxDepth: e.maxDepth
2302
+ }), s = Zt(e), c = [];
2303
+ for (let e of o) {
2304
+ if (c.length >= a) break;
2305
+ try {
2306
+ let t = await s(e.tenantId);
2307
+ e.appliedHash !== t && c.push({
2308
+ tenantId: e.tenantId,
2309
+ expected: t,
2310
+ applied: e.appliedHash
2311
+ });
2312
+ } catch (t) {
2313
+ n.logger?.warn(`Could not compute the expected hash of ${e.tenantId}:`, t);
2314
+ }
2315
+ }
2316
+ let l = {
2317
+ checked: o.length,
2318
+ drifted: c.length,
2319
+ alreadyCovered: 0,
2320
+ recentlyFailed: 0
2321
+ };
2322
+ if (c.length === 0) return l;
2323
+ let u = /* @__PURE__ */ new Set(), { rollouts: d } = await r.list({
2324
+ kind: "config-sync",
2325
+ status: [...Qt],
2326
+ per_page: 100
2327
+ });
2328
+ for (let t of d) for (let n of await Q(e, t.id)) n.tenant_id && !j(n.status) && u.add(n.tenant_id);
2329
+ for (let r of c) try {
2330
+ await e.adapters.logs.create(r.tenantId, {
2331
+ type: t.CONFIG_DRIFT,
2332
+ date: new Date(e.now?.() ?? Date.now()).toISOString(),
2333
+ isMobile: !1,
2334
+ 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",
2335
+ details: {
2336
+ reason: r.applied ? "hash-mismatch" : "never-synced",
2337
+ applied_hash: r.applied,
2338
+ expected_hash: r.expected,
2339
+ covered_by_open_rollout: u.has(r.tenantId),
2340
+ trigger: "reconcile"
2341
+ }
2342
+ });
2343
+ } catch (e) {
2344
+ n.logger?.warn(`Could not record drift for ${r.tenantId}:`, e);
2345
+ }
2346
+ let f = c.filter((e) => !u.has(e.tenantId));
2347
+ l.alreadyCovered = c.length - f.length;
2348
+ let { tenantOperations: p } = $t(e), m = e.now?.() ?? Date.now(), h = n.retryAfterMs ?? 36e5, g = [];
2349
+ for (let e of f) {
2350
+ try {
2351
+ let { operations: t } = await p.list({
2352
+ tenant_id: e.tenantId,
2353
+ kind: "sync-defaults",
2354
+ per_page: 5
2355
+ }), 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];
2356
+ if (n?.status === "failed" && m - Date.parse(n.updated_at) < h) {
2357
+ l.recentlyFailed++;
2358
+ continue;
2359
+ }
2360
+ } catch (t) {
2361
+ n.logger?.warn(`Could not read the latest sync of ${e.tenantId}:`, t);
2362
+ }
2363
+ g.push(e);
2364
+ }
2365
+ if (g.length === 0) return l;
2366
+ let _ = await r.create({
2367
+ kind: "config-sync",
2368
+ initiated_by: "reconcile",
2369
+ config: {
2370
+ ...Y,
2371
+ trigger: "reconcile",
2372
+ root_tenant_id: i,
2373
+ planned: !1
2374
+ }
2375
+ });
2376
+ return await en(e, _, { tenantIds: g.map((e) => e.tenantId) }), l.rolloutId = _.id, l;
2377
+ }
2378
+ //#endregion
2379
+ //#region src/rollouts/trigger.ts
2380
+ function un(e, t) {
2381
+ return e === "hookCode" ? !0 : !t || typeof t != "object" ? !1 : V(e, t) !== "local";
2382
+ }
2383
+ async function dn(e, t, n) {
2384
+ let r = Z(e), { rollouts: i } = await r.list({
2385
+ kind: "config-sync",
2386
+ status: "pending",
2387
+ per_page: 100
2388
+ }), a = i.find((e) => {
2389
+ let n = X(e);
2390
+ return n.trigger === "write" && n.planned !== !0 && n.origin_tenant_id === t;
2391
+ });
2392
+ return a ? (await r.update(a.id, {}), await r.get(a.id) ?? a) : r.create({
2393
+ kind: "config-sync",
2394
+ initiated_by: n ?? `write:${t}`,
2395
+ config: {
2396
+ ...Y,
2397
+ trigger: "write",
2398
+ root_tenant_id: t,
2399
+ origin_tenant_id: t,
2400
+ planned: !1
2401
+ }
2402
+ });
2403
+ }
2404
+ async function fn(e, t) {
2405
+ if (t === e.controlPlaneTenantId) return !0;
2406
+ try {
2407
+ let { tenants: n } = await e.adapters.tenants.list({
2408
+ q: `parent_tenant_id:${t}`,
2409
+ per_page: 1
2410
+ });
2411
+ return n.some((e) => e.parent_tenant_id === t);
2412
+ } catch {
2413
+ return !0;
2414
+ }
2415
+ }
2416
+ function pn(e, t = {}) {
2417
+ let n = async (n) => {
2418
+ try {
2419
+ await fn(e, n) && await dn(e, n);
2420
+ } catch (e) {
2421
+ t.logger?.warn(`Could not record a config change for ${n}:`, e);
2422
+ }
2423
+ }, r = (e) => ({
2424
+ afterCreate: async (t, r) => {
2425
+ un(e, r) && await n(t.tenantId);
2426
+ },
2427
+ afterUpdate: async (t, r, i) => {
2428
+ un(e, i) && await n(t.tenantId);
2429
+ },
2430
+ afterDelete: async (e) => n(e.tenantId)
2431
+ });
2432
+ return {
2433
+ actions: r("action"),
2434
+ hooks: r("hook"),
2435
+ hookCode: r("hookCode"),
2436
+ connections: r("connection"),
2437
+ resourceServers: r("resourceServer")
2438
+ };
2439
+ }
2440
+ //#endregion
2441
+ //#region src/rollouts/controller.ts
2442
+ function mn(e) {
2443
+ return {
2444
+ async create(t) {
2445
+ let n = {
2446
+ ...Y,
2447
+ waves: t.waves ?? [...Y.waves],
2448
+ canary: t.canary ?? Y.canary,
2449
+ failure_threshold: t.failureThreshold ?? Y.failure_threshold,
2450
+ max_concurrent: t.maxConcurrent ?? Y.max_concurrent,
2451
+ trigger: "manual",
2452
+ root_tenant_id: t.rootTenantId ?? e.controlPlaneTenantId,
2453
+ dry_run: t.dryRun,
2454
+ force: t.force,
2455
+ planned: !1
2456
+ }, r = Z(e), i = await r.create({
2457
+ kind: "config-sync",
2458
+ initiated_by: t.initiatedBy,
2459
+ config: n
2460
+ });
2461
+ return await en(e, i, { tenantIds: t.tenantIds }), await rn(e, i.id), await r.get(i.id) ?? i;
2462
+ },
2463
+ pause: (t, n) => on(e, t, n),
2464
+ resume: (t) => sn(e, t)
2465
+ };
2466
+ }
2467
+ //#endregion
1473
2468
  //#region src/init.ts
1474
- function ut(e) {
1475
- let { dataAdapter: t, controlPlane: n, controlPlane: { tenantId: r = "control_plane", clientId: i } = {}, resolveControlPlane: a, inheritanceShadow: o, sync: s = {
2469
+ function hn(e) {
2470
+ let { dataAdapter: t, controlPlane: n, controlPlane: { tenantId: r = "control_plane", clientId: i } = {}, resolveControlPlane: a, inheritanceShadow: o, syncDefaults: s, rolloutExecutor: c, sync: l = {
1476
2471
  resourceServers: !0,
1477
2472
  roles: !0
1478
- }, defaultPermissions: c = ["tenant:admin"], requireOrganizationMatch: l = !1, managementApiExtensions: u = [], entityHooks: d, getChildTenantIds: p, getAdapters: h, ...g } = e;
2473
+ }, defaultPermissions: u = ["tenant:admin"], requireOrganizationMatch: d = !1, managementApiExtensions: f = [], entityHooks: p, getChildTenantIds: h, getAdapters: g, ...v } = e;
1479
2474
  if (a && !n) throw Error("initMultiTenant: `resolveControlPlane` requires `controlPlane` to be set. The static `controlPlane.tenantId` is used for access control, sync direction, and tenant management routing; the resolver only overrides per-tenant runtime inheritance lookups on top of it.");
1480
- let _ = t, v = t;
1481
- n && (_ = Z(t, {
1482
- controlPlaneTenantId: r,
1483
- controlPlaneClientId: i,
1484
- resolveControlPlane: a,
1485
- inheritanceShadow: o
1486
- }), v = {
1487
- ...rt(t, {
1488
- controlPlaneTenantId: r,
1489
- resolveControlPlane: a
1490
- }),
1491
- multiTenancyConfig: {
2475
+ let y = t, b = t, ee;
2476
+ if (n) {
2477
+ let e = Pe({
2478
+ base: Re({
2479
+ controlPlaneTenantId: r,
2480
+ controlPlaneClientId: i,
2481
+ resolveControlPlane: a
2482
+ }),
2483
+ getTenant: async (e) => await t.tenants.get(e) ?? null,
2484
+ controlPlaneTenantId: r
2485
+ });
2486
+ ee = (t) => e.invalidate(t), y = Ue(t, {
1492
2487
  controlPlaneTenantId: r,
1493
2488
  controlPlaneClientId: i,
1494
- resolveControlPlane: a
1495
- }
1496
- });
1497
- let y = g.tenantOperationExecutor;
1498
- if (!y && t.tenantOperations && t.tenantOperationEvents && g.tenantUpgrade) {
2489
+ resolveControlPlane: a,
2490
+ inheritanceShadow: o,
2491
+ configSync: e
2492
+ }), b = {
2493
+ ...Be(t, {
2494
+ controlPlaneTenantId: r,
2495
+ resolveControlPlane: e.resolve
2496
+ }),
2497
+ multiTenancyConfig: {
2498
+ controlPlaneTenantId: r,
2499
+ controlPlaneClientId: i,
2500
+ resolveControlPlane: e.resolve
2501
+ }
2502
+ };
2503
+ }
2504
+ let te = v.tenantOperationExecutor, x;
2505
+ if (t.tenantOperations && t.tenantOperationEvents) {
1499
2506
  let e = {
1500
2507
  tenantOperations: t.tenantOperations,
1501
2508
  tenantOperationEvents: t.tenantOperationEvents
1502
- }, n = g.tenantUpgrade, r = ie({
2509
+ }, n = v.tenantUpgrade, i = A(e), o = s ?? ft(t, {
2510
+ controlPlaneTenantId: r,
2511
+ resolveControlPlane: a
2512
+ }), c = le({
1503
2513
  stores: e,
1504
- definitions: { upgrade: (e) => [{
1505
- name: "upgrade",
1506
- async run() {
1507
- if (!e.tenant_id) throw Error("upgrade operations require a tenant_id");
1508
- await n(e.tenant_id);
1509
- }
1510
- }] }
2514
+ definitions: {
2515
+ ...n ? { upgrade: (e) => [{
2516
+ name: "upgrade",
2517
+ async run() {
2518
+ if (!e.tenant_id) throw Error("upgrade operations require a tenant_id");
2519
+ await n(e.tenant_id);
2520
+ }
2521
+ }] } : {},
2522
+ "sync-defaults": (e) => [{
2523
+ name: "sync-defaults",
2524
+ run: () => dt({
2525
+ operation: e,
2526
+ syncConfig: o,
2527
+ recorder: i
2528
+ })
2529
+ }]
2530
+ }
1511
2531
  });
1512
- y = {
1513
- engine: r.engine,
1514
- enqueue: (t) => oe(e, r, {
2532
+ x = c, te ??= {
2533
+ engine: c.engine,
2534
+ kinds: n ? ["upgrade", "sync-defaults"] : ["sync-defaults"],
2535
+ enqueue: (t) => ue(e, c, {
1515
2536
  ...t,
1516
2537
  tenant_id: t.tenant_id
1517
- })
2538
+ }, { returnFailed: t.kind === "sync-defaults" })
1518
2539
  };
1519
2540
  }
1520
- let b = s !== !1, x = b ? {
1521
- resourceServers: s.resourceServers ?? !0,
1522
- roles: s.roles ?? !0
2541
+ let S = c ?? x, C = S && t.rollouts && t.tenantOperations && t.tenantOperationEvents ? {
2542
+ adapters: t,
2543
+ executor: S,
2544
+ controlPlaneTenantId: r,
2545
+ resolveControlPlane: a
2546
+ } : void 0, w = C ? mn(C) : void 0, T = C ? pn(C, { logger: console }) : void 0, E = l !== !1, D = E ? {
2547
+ resourceServers: l.resourceServers ?? !0,
2548
+ roles: l.roles ?? !0
1523
2549
  } : {
1524
2550
  resourceServers: !1,
1525
2551
  roles: !1
1526
- }, { entityHooks: S, tenantHooks: C } = ve({
2552
+ }, { entityHooks: ne, tenantHooks: O } = Tt({
1527
2553
  controlPlaneTenantId: r,
1528
- getChildTenantIds: p ?? (async () => (await f((e) => _.tenants.list(e), "tenants", {
2554
+ getChildTenantIds: h ?? (async () => (await m((e) => y.tenants.list(e), "tenants", {
1529
2555
  cursorField: "id",
1530
2556
  pageSize: 100
1531
2557
  })).filter((e) => e.id !== r).map((e) => e.id)),
1532
- getAdapters: h ?? (async () => _),
1533
- getControlPlaneAdapters: async () => _,
1534
- sync: x
1535
- }), w = {
1536
- resourceServers: [S.resourceServers, ...d?.resourceServers ?? []],
1537
- roles: [S.roles, ...d?.roles ?? []],
1538
- connections: d?.connections ?? [],
1539
- tenants: d?.tenants ?? [],
1540
- rolePermissions: d?.rolePermissions ?? []
1541
- }, T = N({ accessControl: {
1542
- controlPlaneTenantId: r,
1543
- requireOrganizationMatch: l,
1544
- defaultPermissions: c
1545
- } }), E = F({ accessControl: {
2558
+ getAdapters: g ?? (async () => y),
2559
+ getControlPlaneAdapters: async () => y,
2560
+ sync: D
2561
+ }), re = {
2562
+ resourceServers: [
2563
+ ne.resourceServers,
2564
+ T?.resourceServers,
2565
+ ...p?.resourceServers ?? []
2566
+ ],
2567
+ roles: [ne.roles, ...p?.roles ?? []],
2568
+ connections: [T?.connections, ...p?.connections ?? []],
2569
+ tenants: p?.tenants ?? [],
2570
+ rolePermissions: p?.rolePermissions ?? [],
2571
+ actions: [T?.actions, ...p?.actions ?? []],
2572
+ hooks: [T?.hooks, ...p?.hooks ?? []],
2573
+ hookCode: [T?.hookCode, ...p?.hookCode ?? []]
2574
+ }, k = gt({ accessControl: {
1546
2575
  controlPlaneTenantId: r,
1547
- requireOrganizationMatch: l,
1548
- defaultPermissions: c
1549
- } }, { tenants: {
2576
+ requireOrganizationMatch: d,
2577
+ defaultPermissions: u
2578
+ } }), ie = At({
2579
+ accessControl: {
2580
+ controlPlaneTenantId: r,
2581
+ requireOrganizationMatch: d,
2582
+ defaultPermissions: u
2583
+ },
2584
+ onConfigSyncChange: (e) => ee?.(e),
2585
+ configSyncStatus: (e) => cn({
2586
+ adapters: t,
2587
+ controlPlaneTenantId: r,
2588
+ resolveControlPlane: a
2589
+ }, e)
2590
+ }, { tenants: {
1550
2591
  async beforeCreate(e, t) {
1551
- return T.beforeCreate && (t = await T.beforeCreate(e, t)), C.beforeCreate && (t = await C.beforeCreate(e, t)), t;
2592
+ return k.beforeCreate && (t = await k.beforeCreate(e, t)), O.beforeCreate && (t = await O.beforeCreate(e, t)), t;
1552
2593
  },
1553
2594
  async afterCreate(e, t) {
1554
- await T.afterCreate?.(e, t), await C.afterCreate?.(e, t);
2595
+ await k.afterCreate?.(e, t), await O.afterCreate?.(e, t);
1555
2596
  },
1556
2597
  async beforeDelete(e, t) {
1557
- await T.beforeDelete?.(e, t), await C.beforeDelete?.(e, t);
2598
+ await k.beforeDelete?.(e, t), await O.beforeDelete?.(e, t);
1558
2599
  }
1559
- } }), { app: D } = m({
1560
- dataAdapter: _,
1561
- managementDataAdapter: v,
1562
- ...g,
1563
- tenantOperationExecutor: y,
1564
- entityHooks: w,
1565
- managementApiExtensions: [...u, {
2600
+ } }), { app: ae } = _({
2601
+ dataAdapter: y,
2602
+ managementDataAdapter: b,
2603
+ ...v,
2604
+ tenantOperationExecutor: te,
2605
+ ...w ? { rolloutController: w } : {},
2606
+ entityHooks: re,
2607
+ managementApiExtensions: [...f, {
1566
2608
  path: "/tenants",
1567
- router: E
2609
+ router: ie
1568
2610
  }],
1569
- managementApiMiddleware: [...g.managementApiMiddleware ?? [], ...b ? [Ee()] : []]
2611
+ managementApiMiddleware: [...v.managementApiMiddleware ?? [], ...E ? [Vt()] : []]
1570
2612
  });
1571
2613
  return {
1572
- app: D,
1573
- controlPlaneTenantId: r
2614
+ app: ae,
2615
+ controlPlaneTenantId: r,
2616
+ rollouts: C
1574
2617
  };
1575
2618
  }
1576
2619
  //#endregion
1577
2620
  //#region src/rollout/payload.ts
1578
- function dt(e) {
2621
+ function gn(e) {
1579
2622
  let { pkcs7: t, tenant_id: n, ...r } = e;
1580
2623
  return r;
1581
2624
  }
1582
- async function ft(e, t, n = {}, r) {
1583
- let i = z(n), a = n.signingKeys ?? !0, o = n.tenants ?? !0, s = await H(e, t, i), c = a ? (await g(e.keys)).map(dt) : [], l = o ? await pt(e, t, r) : [];
2625
+ async function _n(e, t, n = {}, r) {
2626
+ let i = he(n), a = n.signingKeys ?? !0, o = n.tenants ?? !0, s = await ve(e, t, i), c = a ? (await b(e.keys)).map(gn) : [], l = o ? await vn(e, t, r) : [];
1584
2627
  return {
1585
2628
  connections: s.connections,
1586
2629
  resourceServers: s.resourceServers.filter((e) => e.is_system),
1587
- hooks: s.hooks.filter(ze),
2630
+ hooks: s.hooks.filter(_e),
1588
2631
  emailProvider: s.emailProvider,
1589
2632
  branding: s.branding,
1590
2633
  promptSettings: s.promptSettings,
@@ -1592,7 +2635,7 @@ async function ft(e, t, n = {}, r) {
1592
2635
  tenants: l
1593
2636
  };
1594
2637
  }
1595
- async function pt(e, t, n) {
2638
+ async function vn(e, t, n) {
1596
2639
  let r = n && n !== t ? [t, n] : [t], i = [];
1597
2640
  for (let t of r) {
1598
2641
  let n = await e.tenants.get(t);
@@ -1603,19 +2646,19 @@ async function pt(e, t, n) {
1603
2646
  }
1604
2647
  return i;
1605
2648
  }
1606
- async function mt(e, t, n) {
1607
- let r = B();
2649
+ async function yn(e, t, n) {
2650
+ let r = P();
1608
2651
  if (e.length === 0) return r;
1609
- let i = await g(t.keys), a = new Set(i.map((e) => e.kid));
1610
- for (let i of e) await V(r, `signing_key ${i.kid}`, n, async () => {
1611
- let e = dt(i);
2652
+ let i = await b(t.keys), a = new Set(i.map((e) => e.kid));
2653
+ for (let i of e) await F(r, `signing_key ${i.kid}`, n, async () => {
2654
+ let e = gn(i);
1612
2655
  a.has(e.kid) || (await t.keys.create(e), a.add(e.kid), r.upserted += 1);
1613
2656
  });
1614
2657
  return r;
1615
2658
  }
1616
- async function ht(e, t, n) {
1617
- let r = B();
1618
- for (let i of e) await V(r, `tenant ${i.id}`, n, async () => {
2659
+ async function bn(e, t, n) {
2660
+ let r = P();
2661
+ for (let i of e) await F(r, `tenant ${i.id}`, n, async () => {
1619
2662
  await t.tenants.get(i.id) || (await t.tenants.create({
1620
2663
  id: i.id,
1621
2664
  friendly_name: i.friendly_name
@@ -1623,46 +2666,50 @@ async function ht(e, t, n) {
1623
2666
  });
1624
2667
  return r;
1625
2668
  }
1626
- async function gt(e, t, n, r = {}) {
1627
- let i = r.continueOnError ?? !1, o = z(r.entities), s = r.entities?.signingKeys ?? !0, c = r.entities?.tenants ?? !0, l = {
2669
+ async function xn(e, t, n, r = {}) {
2670
+ let i = r.continueOnError ?? !1, a = he(r.entities), s = r.entities?.signingKeys ?? !0, c = r.entities?.tenants ?? !0, l = {
1628
2671
  connections: e.connections,
1629
2672
  resourceServers: e.resourceServers,
1630
2673
  hooks: e.hooks,
1631
- emailProvider: e.emailProvider ? u.parse(e.emailProvider) : null,
1632
- branding: e.branding ? a.parse(e.branding) : null,
1633
- promptSettings: e.promptSettings ? _.parse(e.promptSettings) : null
1634
- }, d = c ? await ht(e.tenants ?? [], t, i) : B(), f = Re(n);
1635
- await Be(l, t, n, o, i, f);
1636
- let p = s ? await mt(e.signingKeys, t, i) : B();
2674
+ emailProvider: e.emailProvider ? f.parse(e.emailProvider) : null,
2675
+ branding: e.branding ? o.parse(e.branding) : null,
2676
+ promptSettings: e.promptSettings ? ee.parse(e.promptSettings) : null
2677
+ }, u = c ? await bn(e.tenants ?? [], t, i) : P(), d = ge(n);
2678
+ await ye(l, t, n, a, i, d);
2679
+ let p = s ? await yn(e.signingKeys, t, i) : P(), m = e.resolved && r.resolved ? await at(e.resolved, t, r.resolved.tenantId, {
2680
+ continueOnError: i,
2681
+ ...r.resolved
2682
+ }) : void 0;
1637
2683
  return {
1638
- ...f,
2684
+ ...d,
1639
2685
  signingKeys: p,
1640
- tenants: d
2686
+ tenants: u,
2687
+ ...m ? { resolved: m } : {}
1641
2688
  };
1642
2689
  }
1643
2690
  //#endregion
1644
2691
  //#region src/rollout/index.ts
1645
- function _t(e) {
2692
+ function Sn(e) {
1646
2693
  return {
1647
- syncDefaults: (t) => U(e, t),
2694
+ syncDefaults: (t) => be(e, t),
1648
2695
  syncDefaultsToTenants: async (t) => {
1649
2696
  let n = [];
1650
- for (let r of t) n.push(await U(e, r));
2697
+ for (let r of t) n.push(await be(e, r));
1651
2698
  return n;
1652
2699
  }
1653
2700
  };
1654
2701
  }
1655
2702
  //#endregion
1656
2703
  //#region src/plugin.ts
1657
- function vt(e) {
1658
- let t = $(e);
2704
+ function Cn(e) {
2705
+ let t = wn(e);
1659
2706
  return {
1660
2707
  name: "multi-tenancy",
1661
- middleware: Q(e),
2708
+ middleware: Kt(e),
1662
2709
  hooks: t,
1663
2710
  routes: [{
1664
2711
  path: "/management",
1665
- handler: F(e, t)
2712
+ handler: At(e, t)
1666
2713
  }],
1667
2714
  onRegister: async () => {
1668
2715
  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");
@@ -1671,29 +2718,29 @@ function vt(e) {
1671
2718
  }
1672
2719
  //#endregion
1673
2720
  //#region src/index.ts
1674
- function $(e) {
1675
- let t = e.accessControl ? E(e.accessControl) : {}, n = e.databaseIsolation ? ee(e.databaseIsolation) : {}, r = N(e);
2721
+ function wn(e) {
2722
+ let t = e.accessControl ? ne(e.accessControl) : {}, n = e.databaseIsolation ? re(e.databaseIsolation) : {}, r = gt(e);
1676
2723
  return {
1677
2724
  ...t,
1678
2725
  ...n,
1679
2726
  tenants: r
1680
2727
  };
1681
2728
  }
1682
- function yt(t) {
1683
- let n = new e(), r = $(t);
1684
- return n.route("/tenants", F(t, r)), n;
2729
+ function Tn(t) {
2730
+ let n = new e(), r = wn(t);
2731
+ return n.route("/tenants", At(t, r)), n;
1685
2732
  }
1686
- function bt(e) {
2733
+ function En(e) {
1687
2734
  return {
1688
- hooks: $(e),
1689
- middleware: Q(e),
1690
- app: yt(e),
2735
+ hooks: wn(e),
2736
+ middleware: Kt(e),
2737
+ app: Tn(e),
1691
2738
  config: e,
1692
- wrapAdapters: (t, n) => Z(t, {
2739
+ wrapAdapters: (t, n) => Ue(t, {
1693
2740
  controlPlaneTenantId: e.accessControl?.controlPlaneTenantId,
1694
2741
  controlPlaneClientId: n?.controlPlaneClientId
1695
2742
  })
1696
2743
  };
1697
2744
  }
1698
2745
  //#endregion
1699
- export { gt as applyControlPlaneDefaultsPayload, ft as buildControlPlaneDefaultsPayload, A as buildEngineInstanceId, Je as compareShadow, Ae as computeLegacyConfig, E as createAccessControlHooks, st as createAccessControlMiddleware, ot as createControlPlaneTenantMiddleware, ee as createDatabaseHooks, lt as createDatabaseMiddleware, _t as createDirectRolloutAdapter, ie as createInlineExecutor, yt as createMultiTenancy, $ as createMultiTenancyHooks, Q as createMultiTenancyMiddleware, vt as createMultiTenancyPlugin, M as createOperationRecorder, Ee as createProtectSyncedMiddleware, N as createProvisioningHooks, it as createRuntimeFallbackAdapter, Ze as createShadowReporter, ct as createSubdomainMiddleware, ve as createSyncHooks, F as createTenantsOpenAPIRouter, qe as diffConfig, L as effectiveOverride, I as effectiveScope, oe as enqueueTenantOperation, j as errorToMessage, ut as initMultiTenant, re as inlineStepRunner, ne as isTerminalStatus, et as mergeClientWithFallback, Le as mergeConfig, U as projectControlPlaneDefaults, W as readConfigRows, De as resolveTenantChain, ce as runRecordedTenantOperation, bt as setupMultiTenancy, D as validateTenantAccess, Z as withRuntimeFallback, rt as withSystemResourceServerInheritance };
2746
+ export { Y as DEFAULT_ROLLOUT_SETTINGS, qt as DEFAULT_ROLLOUT_WAVES, rn as advanceRollout, an as advanceRollouts, xn as applyControlPlaneDefaultsPayload, at as applyResolvedConfigBlock, Jt as assignWaves, _n as buildControlPlaneDefaultsPayload, ae as buildEngineInstanceId, et as buildResolvedConfigBlock, ke as compareShadow, me as computeLegacyConfig, ne as createAccessControlHooks, Ut as createAccessControlMiddleware, Pe as createConfigSyncResolver, Ht as createControlPlaneTenantMiddleware, re as createDatabaseHooks, Gt as createDatabaseMiddleware, Sn as createDirectRolloutAdapter, Zt as createExpectedHash, ft as createInProcessSyncConfig, le as createInlineExecutor, Tn as createMultiTenancy, wn as createMultiTenancyHooks, Kt as createMultiTenancyMiddleware, Cn as createMultiTenancyPlugin, A as createOperationRecorder, M as createOperationRow, Vt as createProtectSyncedMiddleware, gt as createProvisioningHooks, mn as createRolloutController, pn as createRolloutWriteHooks, Ve as createRuntimeFallbackAdapter, Me as createShadowReporter, Wt as createSubdomainMiddleware, Tt as createSyncHooks, At as createTenantsOpenAPIRouter, Oe as diffConfig, H as effectiveOverride, V as effectiveScope, ue as enqueueTenantOperation, se as errorToMessage, rt as findUndecryptableKeyIds, cn as getConfigSyncStatus, hn as initMultiTenant, ce as inlineStepRunner, un as isPublishedRow, j as isTerminalStatus, Q as listRolloutOperations, Yt as listSyncedDescendants, Le as mergeClientWithFallback, Ze as mergeConfig, on as pauseRollout, en as planRollout, be as projectControlPlaneDefaults, I as readConfigRows, X as readRolloutConfig, ln as reconcileConfigDrift, dn as requestRollout, N as resolveTenantChain, sn as resumeRollout, mt as runRecordedTenantOperation, dt as runSyncDefaultsStep, En as setupMultiTenancy, ut as summarizeSyncResult, lt as syncErrors, ct as syncOptionsOf, W as syncedRowId, O as validateTenantAccess, Ue as withRuntimeFallback, Be as withSystemResourceServerInheritance };