@authhero/multi-tenancy 14.22.0 → 14.23.1

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.
@@ -1,1377 +1,861 @@
1
- var ne = Object.defineProperty;
2
- var re = (e, t, r) => t in e ? ne(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
3
- var E = (e, t, r) => re(e, typeof t != "symbol" ? t + "" : t, r);
4
- import { Hono as ae } from "hono";
5
- import { MANAGEMENT_API_SCOPES as se, MANAGEMENT_API_AUDIENCE as X, fetchAll as q, auth0QuerySchema as oe, tenantSchema as D, tenantInsertSchema as G, deepMergePatch as ie, connectionSchema as ce, connectionOptionsSchema as le, init as ue } from "authhero";
6
- import { OpenAPIHono as de, createRoute as M, z as S } from "@hono/zod-openapi";
7
- function fe(e) {
8
- const { controlPlaneTenantId: t, requireOrganizationMatch: r = !0 } = e;
9
- return {
10
- async onTenantAccessValidation(n, a) {
11
- if (a === t)
12
- return !0;
13
- if (r) {
14
- const o = n.var.org_name, c = n.var.organization_id, i = o || c;
15
- return i ? i.toLowerCase() === a.toLowerCase() : !1;
16
- }
17
- return !0;
18
- }
19
- };
20
- }
21
- function me(e, t, r, n) {
22
- if (t === r)
23
- return !0;
24
- const a = n || e;
25
- return a ? a.toLowerCase() === t.toLowerCase() : !1;
26
- }
27
- function ge(e) {
28
- return {
29
- async resolveDataAdapters(t) {
30
- try {
31
- return await e.getAdapters(t);
32
- } catch (r) {
33
- console.error(
34
- `Failed to resolve data adapters for tenant ${t}:`,
35
- r
36
- );
37
- return;
38
- }
39
- }
40
- };
41
- }
42
- function we(e) {
43
- return `urn:authhero:tenant:${e.toLowerCase()}`;
44
- }
45
- function Y(e) {
46
- return {
47
- async beforeCreate(t, r) {
48
- return !r.audience && r.id ? {
49
- ...r,
50
- audience: we(r.id)
51
- } : r;
52
- },
53
- async afterCreate(t, r) {
54
- const { accessControl: n, databaseIsolation: a } = e;
55
- n && t.ctx && await pe(t, r, n), a != null && a.onProvision && await a.onProvision(r.id);
56
- },
57
- async beforeDelete(t, r) {
58
- const { accessControl: n, databaseIsolation: a } = e;
59
- if (n)
60
- try {
61
- const c = (await t.adapters.organizations.list(
62
- n.controlPlaneTenantId
63
- )).organizations.find((i) => i.name === r);
64
- c && await t.adapters.organizations.remove(
65
- n.controlPlaneTenantId,
66
- c.id
67
- );
68
- } catch (o) {
69
- console.warn(
70
- `Failed to remove organization for tenant ${r}:`,
71
- o
72
- );
73
- }
74
- if (a != null && a.onDeprovision)
75
- try {
76
- await a.onDeprovision(r);
77
- } catch (o) {
78
- console.warn(
79
- `Failed to deprovision database for tenant ${r}:`,
80
- o
81
- );
82
- }
83
- }
84
- };
85
- }
86
- async function pe(e, t, r) {
87
- const {
88
- controlPlaneTenantId: n,
89
- defaultPermissions: a,
90
- defaultRoles: o,
91
- issuer: c,
92
- adminRoleName: i = "Tenant Admin",
93
- adminRoleDescription: l = "Full access to all tenant management operations",
94
- addCreatorToOrganization: u = !0
95
- } = r, s = await e.adapters.organizations.create(
96
- n,
97
- {
98
- name: t.id,
99
- display_name: t.friendly_name || t.id
100
- }
101
- );
102
- let d;
103
- if (c && (d = await ye(
104
- e,
105
- n,
106
- i,
107
- l
108
- )), u && e.ctx) {
109
- const m = e.ctx.var.user;
110
- if (m != null && m.sub && !await he(
111
- e,
112
- n,
113
- m.sub
114
- ))
115
- try {
116
- await e.adapters.userOrganizations.create(n, {
117
- user_id: m.sub,
118
- organization_id: s.id
119
- }), d && await e.adapters.userRoles.create(
120
- n,
121
- m.sub,
122
- d,
123
- s.id
124
- // organizationId
125
- );
126
- } catch (f) {
127
- console.warn(
128
- `Failed to add creator ${m.sub} to organization ${s.id}:`,
129
- f
130
- );
131
- }
132
- }
133
- o && o.length > 0 && console.log(
134
- `Would assign roles ${o.join(", ")} to organization ${s.id}`
135
- ), a && a.length > 0 && console.log(
136
- `Would grant permissions ${a.join(", ")} to organization ${s.id}`
137
- );
138
- }
139
- async function he(e, t, r) {
140
- const n = await e.adapters.userRoles.list(
141
- t,
142
- r,
143
- void 0,
144
- ""
145
- // Empty string for global roles
146
- );
147
- for (const a of n)
148
- if ((await e.adapters.rolePermissions.list(
149
- t,
150
- a.id,
151
- { per_page: 1e3 }
152
- )).some(
153
- (i) => i.permission_name === "admin:organizations"
154
- ))
155
- return !0;
156
- return !1;
157
- }
158
- async function ye(e, t, r, n) {
159
- const o = (await e.adapters.roles.list(t, {})).roles.find((u) => u.name === r);
160
- if (o)
161
- return o.id;
162
- const c = await e.adapters.roles.create(t, {
163
- name: r,
164
- description: n
165
- }), i = X, l = se.map((u) => ({
166
- role_id: c.id,
167
- resource_server_identifier: i,
168
- permission_name: u.value
169
- }));
170
- return await e.adapters.rolePermissions.assign(
171
- t,
172
- c.id,
173
- l
174
- ), c.id;
175
- }
176
- function H(e, t, r = () => !0) {
177
- const { controlPlaneTenantId: n, getChildTenantIds: a, getAdapters: o } = e, c = /* @__PURE__ */ new Map();
178
- async function i(s, d, m) {
179
- return (await t(s).list(d, {
180
- q: `name:${m}`,
181
- per_page: 1
182
- }))[0] ?? null;
183
- }
184
- async function l(s) {
185
- const d = await a(), m = t(await o(n));
186
- await Promise.all(
187
- d.map(async (w) => {
188
- try {
189
- const f = await o(w), g = t(f), h = {
190
- ...m.transform(s),
191
- is_system: !0
192
- }, T = await i(f, w, s.name), b = T ? g.getId(T) : void 0;
193
- if (T && b) {
194
- const z = g.preserveOnUpdate ? g.preserveOnUpdate(T, h) : h;
195
- await g.update(w, b, z);
196
- } else
197
- await g.create(w, h);
198
- } catch (f) {
199
- console.error(
200
- `Failed to sync ${m.listKey} "${s.name}" to tenant "${w}":`,
201
- f
202
- );
203
- }
204
- })
205
- );
206
- }
207
- async function u(s) {
208
- const d = await a();
209
- await Promise.all(
210
- d.map(async (m) => {
211
- try {
212
- const w = await o(m), f = t(w), g = await i(w, m, s), _ = g ? f.getId(g) : void 0;
213
- g && _ && await f.remove(m, _);
214
- } catch (w) {
215
- console.error(
216
- `Failed to delete entity "${s}" from tenant "${m}":`,
217
- w
218
- );
219
- }
220
- })
221
- );
222
- }
223
- return {
224
- afterCreate: async (s, d) => {
225
- s.tenantId === n && r(d) && await l(d);
226
- },
227
- afterUpdate: async (s, d, m) => {
228
- s.tenantId === n && r(m) && await l(m);
229
- },
230
- beforeDelete: async (s, d) => {
231
- if (s.tenantId !== n) return;
232
- const w = await t(s.adapters).get(s.tenantId, d);
233
- w && r(w) && c.set(d, w);
234
- },
235
- afterDelete: async (s, d) => {
236
- if (s.tenantId !== n) return;
237
- const m = c.get(d);
238
- m && (c.delete(d), await u(m.name));
239
- }
240
- };
241
- }
242
- function W(e, t, r = () => !0) {
243
- const { controlPlaneTenantId: n, getControlPlaneAdapters: a, getAdapters: o } = e;
244
- return {
245
- async afterCreate(c, i) {
246
- if (i.id !== n)
247
- try {
248
- const l = await a(), u = await o(i.id), s = t(l), d = t(u), m = await q(
249
- (w) => s.listPaginated(n, w),
250
- s.listKey,
251
- { cursorField: "id", pageSize: 100 }
252
- );
253
- await Promise.all(
254
- m.filter((w) => r(w)).map(async (w) => {
255
- try {
256
- const f = s.transform(w);
257
- await d.create(i.id, {
258
- ...f,
259
- is_system: !0
260
- });
261
- } catch (f) {
262
- console.error(
263
- `Failed to sync entity to new tenant "${i.id}":`,
264
- f
265
- );
266
- }
267
- })
268
- );
269
- } catch (l) {
270
- console.error(
271
- `Failed to sync entities to new tenant "${i.id}":`,
272
- l
273
- );
274
- }
275
- }
276
- };
277
- }
278
- const L = (e) => ({
279
- list: async (t, r) => (await e.resourceServers.list(t, r)).resource_servers,
280
- listPaginated: (t, r) => e.resourceServers.list(t, r),
281
- get: (t, r) => e.resourceServers.get(t, r),
282
- create: (t, r) => e.resourceServers.create(t, r),
283
- update: (t, r, n) => e.resourceServers.update(t, r, n),
284
- remove: (t, r) => e.resourceServers.remove(t, r),
285
- listKey: "resource_servers",
286
- getId: (t) => t.id,
287
- transform: (t) => ({
288
- id: t.id,
289
- name: t.name,
290
- identifier: t.identifier,
291
- scopes: t.scopes,
292
- signing_alg: t.signing_alg,
293
- token_lifetime: t.token_lifetime,
294
- token_lifetime_for_web: t.token_lifetime_for_web
295
- })
296
- }), K = (e) => ({
297
- list: async (t, r) => (await e.roles.list(t, r)).roles,
298
- listPaginated: (t, r) => e.roles.list(t, r),
299
- get: (t, r) => e.roles.get(t, r),
300
- create: (t, r) => e.roles.create(t, r),
301
- update: (t, r, n) => e.roles.update(t, r, n),
302
- remove: (t, r) => e.roles.remove(t, r),
303
- listKey: "roles",
304
- getId: (t) => t.id,
305
- transform: (t) => ({
306
- id: t.id,
307
- name: t.name,
308
- description: t.description
309
- })
1
+ import { Hono as e } from "hono";
2
+ import { MANAGEMENT_API_AUDIENCE as t, MANAGEMENT_API_SCOPES as n, auth0QuerySchema as r, connectionOptionsSchema as i, connectionSchema as a, deepMergePatch as o, fetchAll as s, init as c, tenantInsertSchema as l, tenantSchema as u } from "authhero";
3
+ import { OpenAPIHono as d, createRoute as f, z as p } from "@hono/zod-openapi";
4
+ //#region src/hooks/access-control.ts
5
+ function m(e) {
6
+ let { controlPlaneTenantId: t, requireOrganizationMatch: n = !0 } = e;
7
+ return { async onTenantAccessValidation(e, r) {
8
+ if (r === t) return !0;
9
+ if (n) {
10
+ let t = e.var.org_name, n = e.var.organization_id, i = t || n;
11
+ return i ? i.toLowerCase() === r.toLowerCase() : !1;
12
+ }
13
+ return !0;
14
+ } };
15
+ }
16
+ function h(e, t, n, r) {
17
+ if (t === n) return !0;
18
+ let i = r || e;
19
+ return i ? i.toLowerCase() === t.toLowerCase() : !1;
20
+ }
21
+ //#endregion
22
+ //#region src/hooks/database.ts
23
+ function g(e) {
24
+ return { async resolveDataAdapters(t) {
25
+ try {
26
+ return await e.getAdapters(t);
27
+ } catch (e) {
28
+ console.error(`Failed to resolve data adapters for tenant ${t}:`, e);
29
+ return;
30
+ }
31
+ } };
32
+ }
33
+ //#endregion
34
+ //#region src/hooks/provisioning.ts
35
+ function _(e) {
36
+ return `urn:authhero:tenant:${e.toLowerCase()}`;
37
+ }
38
+ function v(e) {
39
+ return {
40
+ async beforeCreate(e, t) {
41
+ return !t.audience && t.id ? {
42
+ ...t,
43
+ audience: _(t.id)
44
+ } : t;
45
+ },
46
+ async afterCreate(t, n) {
47
+ let { accessControl: r, databaseIsolation: i } = e;
48
+ r && t.ctx && await y(t, n, r), i?.onProvision && await i.onProvision(n.id);
49
+ },
50
+ async beforeDelete(t, n) {
51
+ let { accessControl: r, databaseIsolation: i } = e;
52
+ if (r) try {
53
+ let e = (await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find((e) => e.name === n);
54
+ e && await t.adapters.organizations.remove(r.controlPlaneTenantId, e.id);
55
+ } catch (e) {
56
+ console.warn(`Failed to remove organization for tenant ${n}:`, e);
57
+ }
58
+ if (i?.onDeprovision) try {
59
+ await i.onDeprovision(n);
60
+ } catch (e) {
61
+ console.warn(`Failed to deprovision database for tenant ${n}:`, e);
62
+ }
63
+ }
64
+ };
65
+ }
66
+ async function y(e, t, n) {
67
+ 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, {
68
+ name: t.id,
69
+ display_name: t.friendly_name || t.id
70
+ }), d;
71
+ if (o && (d = await x(e, r, s, c)), l && e.ctx) {
72
+ let t = e.ctx.var.user;
73
+ if (t?.sub && !await b(e, r, t.sub)) try {
74
+ await e.adapters.userOrganizations.create(r, {
75
+ user_id: t.sub,
76
+ organization_id: u.id
77
+ }), d && await e.adapters.userRoles.create(r, t.sub, d, u.id);
78
+ } catch (e) {
79
+ console.warn(`Failed to add creator ${t.sub} to organization ${u.id}:`, e);
80
+ }
81
+ }
82
+ 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}`);
83
+ }
84
+ async function b(e, t, n) {
85
+ let r = await e.adapters.userRoles.list(t, n, void 0, "");
86
+ for (let n of r) if ((await e.adapters.rolePermissions.list(t, n.id, { per_page: 1e3 })).some((e) => e.permission_name === "admin:organizations")) return !0;
87
+ return !1;
88
+ }
89
+ async function x(e, r, i, a) {
90
+ let o = (await e.adapters.roles.list(r, {})).roles.find((e) => e.name === i);
91
+ if (o) return o.id;
92
+ let s = await e.adapters.roles.create(r, {
93
+ name: i,
94
+ description: a
95
+ }), c = t, l = n.map((e) => ({
96
+ role_id: s.id,
97
+ resource_server_identifier: c,
98
+ permission_name: e.value
99
+ }));
100
+ return await e.adapters.rolePermissions.assign(r, s.id, l), s.id;
101
+ }
102
+ //#endregion
103
+ //#region src/hooks/sync.ts
104
+ function S(e, t, n = () => !0) {
105
+ let { controlPlaneTenantId: r, getChildTenantIds: i, getAdapters: a } = e, o = /* @__PURE__ */ new Map();
106
+ async function s(e, n, r) {
107
+ return (await t(e).list(n, {
108
+ q: `name:${r}`,
109
+ per_page: 1
110
+ }))[0] ?? null;
111
+ }
112
+ async function c(e) {
113
+ let n = await i(), o = t(await a(r));
114
+ await Promise.all(n.map(async (n) => {
115
+ try {
116
+ let r = await a(n), i = t(r), c = {
117
+ ...o.transform(e),
118
+ is_system: !0
119
+ }, l = await s(r, n, e.name), u = l ? i.getId(l) : void 0;
120
+ if (l && u) {
121
+ let e = i.preserveOnUpdate ? i.preserveOnUpdate(l, c) : c;
122
+ await i.update(n, u, e);
123
+ } else await i.create(n, c);
124
+ } catch (t) {
125
+ console.error(`Failed to sync ${o.listKey} "${e.name}" to tenant "${n}":`, t);
126
+ }
127
+ }));
128
+ }
129
+ async function l(e) {
130
+ let n = await i();
131
+ await Promise.all(n.map(async (n) => {
132
+ try {
133
+ let r = await a(n), i = t(r), o = await s(r, n, e), c = o ? i.getId(o) : void 0;
134
+ o && c && await i.remove(n, c);
135
+ } catch (t) {
136
+ console.error(`Failed to delete entity "${e}" from tenant "${n}":`, t);
137
+ }
138
+ }));
139
+ }
140
+ return {
141
+ afterCreate: async (e, t) => {
142
+ e.tenantId === r && n(t) && await c(t);
143
+ },
144
+ afterUpdate: async (e, t, i) => {
145
+ e.tenantId === r && n(i) && await c(i);
146
+ },
147
+ beforeDelete: async (e, i) => {
148
+ if (e.tenantId !== r) return;
149
+ let a = await t(e.adapters).get(e.tenantId, i);
150
+ a && n(a) && o.set(i, a);
151
+ },
152
+ afterDelete: async (e, t) => {
153
+ if (e.tenantId !== r) return;
154
+ let n = o.get(t);
155
+ n && (o.delete(t), await l(n.name));
156
+ }
157
+ };
158
+ }
159
+ function C(e, t, n = () => !0) {
160
+ let { controlPlaneTenantId: r, getControlPlaneAdapters: i, getAdapters: a } = e;
161
+ return { async afterCreate(e, o) {
162
+ if (o.id !== r) try {
163
+ let e = await i(), c = await a(o.id), l = t(e), u = t(c), d = await s((e) => l.listPaginated(r, e), l.listKey, {
164
+ cursorField: "id",
165
+ pageSize: 100
166
+ });
167
+ await Promise.all(d.filter((e) => n(e)).map(async (e) => {
168
+ try {
169
+ let t = l.transform(e);
170
+ await u.create(o.id, {
171
+ ...t,
172
+ is_system: !0
173
+ });
174
+ } catch (e) {
175
+ console.error(`Failed to sync entity to new tenant "${o.id}":`, e);
176
+ }
177
+ }));
178
+ } catch (e) {
179
+ console.error(`Failed to sync entities to new tenant "${o.id}":`, e);
180
+ }
181
+ } };
182
+ }
183
+ var w = (e) => ({
184
+ list: async (t, n) => (await e.resourceServers.list(t, n)).resource_servers,
185
+ listPaginated: (t, n) => e.resourceServers.list(t, n),
186
+ get: (t, n) => e.resourceServers.get(t, n),
187
+ create: (t, n) => e.resourceServers.create(t, n),
188
+ update: (t, n, r) => e.resourceServers.update(t, n, r),
189
+ remove: (t, n) => e.resourceServers.remove(t, n),
190
+ listKey: "resource_servers",
191
+ getId: (e) => e.id,
192
+ transform: (e) => ({
193
+ id: e.id,
194
+ name: e.name,
195
+ identifier: e.identifier,
196
+ scopes: e.scopes,
197
+ signing_alg: e.signing_alg,
198
+ token_lifetime: e.token_lifetime,
199
+ token_lifetime_for_web: e.token_lifetime_for_web
200
+ })
201
+ }), T = (e) => ({
202
+ list: async (t, n) => (await e.roles.list(t, n)).roles,
203
+ listPaginated: (t, n) => e.roles.list(t, n),
204
+ get: (t, n) => e.roles.get(t, n),
205
+ create: (t, n) => e.roles.create(t, n),
206
+ update: (t, n, r) => e.roles.update(t, n, r),
207
+ remove: (t, n) => e.roles.remove(t, n),
208
+ listKey: "roles",
209
+ getId: (e) => e.id,
210
+ transform: (e) => ({
211
+ id: e.id,
212
+ name: e.name,
213
+ description: e.description
214
+ })
310
215
  });
311
- function Q(e) {
312
- var t;
313
- return ((t = e.metadata) == null ? void 0 : t.sync) !== !1;
314
- }
315
- function ve(e) {
316
- const { sync: t = {}, filters: r = {} } = e, n = t.resourceServers ?? !0, a = t.roles ?? !0, o = (f) => Q(f) ? r.resourceServers ? r.resourceServers(f) : !0 : !1, c = (f) => Q(f) ? r.roles ? r.roles(f) : !0 : !1, i = n ? H(
317
- e,
318
- L,
319
- o
320
- ) : void 0, l = a ? H(e, K, c) : void 0, u = n ? W(
321
- e,
322
- L,
323
- o
324
- ) : void 0, s = a ? W(
325
- e,
326
- K,
327
- c
328
- ) : void 0, d = a ? {
329
- async afterCreate(f, g) {
330
- var _;
331
- if (g.id !== e.controlPlaneTenantId) {
332
- await ((_ = s == null ? void 0 : s.afterCreate) == null ? void 0 : _.call(s, f, g));
333
- try {
334
- const h = await e.getControlPlaneAdapters(), T = await e.getAdapters(g.id), b = await q(
335
- (v) => h.roles.list(
336
- e.controlPlaneTenantId,
337
- v
338
- ),
339
- "roles",
340
- { cursorField: "id", pageSize: 100 }
341
- ), z = /* @__PURE__ */ new Map();
342
- for (const v of b.filter(
343
- (p) => {
344
- var C;
345
- return ((C = r.roles) == null ? void 0 : C.call(r, p)) ?? !0;
346
- }
347
- )) {
348
- const p = await m(
349
- T,
350
- g.id,
351
- v.name
352
- );
353
- p && z.set(v.name, p.id);
354
- }
355
- for (const v of b.filter(
356
- (p) => {
357
- var C;
358
- return ((C = r.roles) == null ? void 0 : C.call(r, p)) ?? !0;
359
- }
360
- )) {
361
- const p = z.get(v.name);
362
- if (p)
363
- try {
364
- const C = await h.rolePermissions.list(
365
- e.controlPlaneTenantId,
366
- v.id,
367
- {}
368
- );
369
- C.length > 0 && await T.rolePermissions.assign(
370
- g.id,
371
- p,
372
- C.map((I) => ({
373
- role_id: p,
374
- resource_server_identifier: I.resource_server_identifier,
375
- permission_name: I.permission_name
376
- }))
377
- );
378
- } catch (C) {
379
- console.error(
380
- `Failed to sync permissions for role "${v.name}" to tenant "${g.id}":`,
381
- C
382
- );
383
- }
384
- }
385
- } catch (h) {
386
- console.error(
387
- `Failed to sync role permissions to tenant "${g.id}":`,
388
- h
389
- );
390
- }
391
- }
392
- }
393
- } : void 0;
394
- async function m(f, g, _) {
395
- return (await f.roles.list(g, {
396
- q: `name:${_}`,
397
- per_page: 1
398
- })).roles[0] ?? null;
399
- }
400
- return {
401
- entityHooks: {
402
- resourceServers: i,
403
- roles: l
404
- },
405
- tenantHooks: {
406
- async afterCreate(f, g) {
407
- const _ = [
408
- u == null ? void 0 : u.afterCreate,
409
- (d == null ? void 0 : d.afterCreate) ?? (s == null ? void 0 : s.afterCreate)
410
- ], h = [];
411
- for (const T of _)
412
- if (T)
413
- try {
414
- await T(f, g);
415
- } catch (b) {
416
- h.push(b instanceof Error ? b : new Error(String(b)));
417
- }
418
- if (h.length === 1) throw h[0];
419
- if (h.length > 1)
420
- throw new AggregateError(
421
- h,
422
- h.map((T) => T.message).join("; ")
423
- );
424
- }
425
- }
426
- };
427
- }
428
- var P = class extends Error {
429
- /**
430
- * Creates an instance of `HTTPException`.
431
- * @param status - HTTP status code for the exception. Defaults to 500.
432
- * @param options - Additional options for the exception.
433
- */
434
- constructor(t = 500, r) {
435
- super(r == null ? void 0 : r.message, { cause: r == null ? void 0 : r.cause });
436
- E(this, "res");
437
- E(this, "status");
438
- this.res = r == null ? void 0 : r.res, this.status = t;
439
- }
440
- /**
441
- * Returns the response object associated with the exception.
442
- * If a response object is not provided, a new response is created with the error message and status code.
443
- * @returns The response object.
444
- */
445
- getResponse() {
446
- return this.res ? new Response(this.res.body, {
447
- status: this.status,
448
- headers: this.res.headers
449
- }) : new Response(this.message, {
450
- status: this.status
451
- });
452
- }
216
+ function E(e) {
217
+ return e.metadata?.sync !== !1;
218
+ }
219
+ function D(e) {
220
+ 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, c = r ? S(e, w, a) : void 0, l = i ? S(e, T, o) : void 0, u = r ? C(e, w, a) : void 0, d = i ? C(e, T, o) : void 0, f = i ? { async afterCreate(t, r) {
221
+ if (r.id !== e.controlPlaneTenantId) {
222
+ await d?.afterCreate?.(t, r);
223
+ try {
224
+ let t = await e.getControlPlaneAdapters(), i = await e.getAdapters(r.id), a = await s((n) => t.roles.list(e.controlPlaneTenantId, n), "roles", {
225
+ cursorField: "id",
226
+ pageSize: 100
227
+ }), o = /* @__PURE__ */ new Map();
228
+ for (let e of a.filter((e) => n.roles?.(e) ?? !0)) {
229
+ let t = await p(i, r.id, e.name);
230
+ t && o.set(e.name, t.id);
231
+ }
232
+ for (let s of a.filter((e) => n.roles?.(e) ?? !0)) {
233
+ let n = o.get(s.name);
234
+ if (n) try {
235
+ let a = await t.rolePermissions.list(e.controlPlaneTenantId, s.id, {});
236
+ a.length > 0 && await i.rolePermissions.assign(r.id, n, a.map((e) => ({
237
+ role_id: n,
238
+ resource_server_identifier: e.resource_server_identifier,
239
+ permission_name: e.permission_name
240
+ })));
241
+ } catch (e) {
242
+ console.error(`Failed to sync permissions for role "${s.name}" to tenant "${r.id}":`, e);
243
+ }
244
+ }
245
+ } catch (e) {
246
+ console.error(`Failed to sync role permissions to tenant "${r.id}":`, e);
247
+ }
248
+ }
249
+ } } : void 0;
250
+ async function p(e, t, n) {
251
+ return (await e.roles.list(t, {
252
+ q: `name:${n}`,
253
+ per_page: 1
254
+ })).roles[0] ?? null;
255
+ }
256
+ return {
257
+ entityHooks: {
258
+ resourceServers: c,
259
+ roles: l
260
+ },
261
+ tenantHooks: { async afterCreate(e, t) {
262
+ let n = [u?.afterCreate, f?.afterCreate ?? d?.afterCreate], r = [];
263
+ for (let i of n) if (i) try {
264
+ await i(e, t);
265
+ } catch (e) {
266
+ r.push(e instanceof Error ? e : Error(String(e)));
267
+ }
268
+ if (r.length === 1) throw r[0];
269
+ if (r.length > 1) throw AggregateError(r, r.map((e) => e.message).join("; "));
270
+ } }
271
+ };
272
+ }
273
+ //#endregion
274
+ //#region ../../node_modules/.pnpm/hono@4.12.25/node_modules/hono/dist/http-exception.js
275
+ var O = class extends Error {
276
+ res;
277
+ status;
278
+ constructor(e = 500, t) {
279
+ super(t?.message, { cause: t?.cause }), this.res = t?.res, this.status = e;
280
+ }
281
+ getResponse() {
282
+ return this.res ? new Response(this.res.body, {
283
+ status: this.status,
284
+ headers: this.res.headers
285
+ }) : new Response(this.message, { status: this.status });
286
+ }
453
287
  };
454
- function B(e, t) {
455
- const r = new de();
456
- return r.openapi(
457
- M({
458
- tags: ["tenants"],
459
- method: "get",
460
- path: "/",
461
- request: {
462
- query: oe
463
- },
464
- security: [
465
- {
466
- Bearer: []
467
- }
468
- ],
469
- responses: {
470
- 200: {
471
- content: {
472
- "application/json": {
473
- schema: S.object({
474
- tenants: S.array(D),
475
- start: S.number().optional(),
476
- limit: S.number().optional(),
477
- length: S.number().optional()
478
- })
479
- }
480
- },
481
- description: "List of tenants"
482
- }
483
- }
484
- }),
485
- async (n) => {
486
- var g, _, h, T, b, z;
487
- const a = n.req.valid("query"), { page: o, per_page: c, include_totals: i, q: l } = a, u = n.var.user, s = (u == null ? void 0 : u.permissions) || [];
488
- if (!!!((u == null ? void 0 : u.org_id) ?? n.var.organization_id) && s.includes("admin:organizations")) {
489
- const v = await n.env.data.tenants.list({
490
- page: o,
491
- per_page: c,
492
- include_totals: i,
493
- q: l
494
- });
495
- return i ? n.json({
496
- tenants: v.tenants,
497
- start: ((g = v.totals) == null ? void 0 : g.start) ?? 0,
498
- limit: ((_ = v.totals) == null ? void 0 : _.limit) ?? c,
499
- length: v.tenants.length
500
- }) : n.json({ tenants: v.tenants });
501
- }
502
- const w = ((h = e.accessControl) == null ? void 0 : h.controlPlaneTenantId) ?? ((T = n.env.data.multiTenancyConfig) == null ? void 0 : T.controlPlaneTenantId);
503
- if (w && !(u != null && u.sub))
504
- throw new P(403, {
505
- message: "Access denied: token has no subject"
506
- });
507
- if (w && (u != null && u.sub)) {
508
- const p = (await q(
509
- (R) => n.env.data.userOrganizations.listUserOrganizations(
510
- w,
511
- u.sub,
512
- R
513
- ),
514
- "organizations"
515
- )).map((R) => R.name);
516
- if (p.length === 0)
517
- return i ? n.json({
518
- tenants: [],
519
- start: 0,
520
- limit: c ?? 50,
521
- length: 0
522
- }) : n.json({ tenants: [] });
523
- const C = p.length, I = o ?? 0, j = c ?? 50, k = I * j, F = p.slice(k, k + j);
524
- if (F.length === 0)
525
- return i ? n.json({
526
- tenants: [],
527
- start: k,
528
- limit: j,
529
- length: C
530
- }) : n.json({ tenants: [] });
531
- const A = F.map((R) => `id:${R}`).join(" OR "), y = l ? `(${A}) AND (${l})` : A, $ = await n.env.data.tenants.list({
532
- q: y,
533
- per_page: j,
534
- include_totals: !1
535
- // We calculate totals from accessibleTenantIds
536
- });
537
- return i ? n.json({
538
- tenants: $.tenants,
539
- start: k,
540
- limit: j,
541
- length: C
542
- }) : n.json({ tenants: $.tenants });
543
- }
544
- const f = await n.env.data.tenants.list({
545
- page: o,
546
- per_page: c,
547
- include_totals: i,
548
- q: l
549
- });
550
- return i ? n.json({
551
- tenants: f.tenants,
552
- start: ((b = f.totals) == null ? void 0 : b.start) ?? 0,
553
- limit: ((z = f.totals) == null ? void 0 : z.limit) ?? c,
554
- length: f.tenants.length
555
- }) : n.json({ tenants: f.tenants });
556
- }
557
- ), r.openapi(
558
- M({
559
- tags: ["tenants"],
560
- method: "post",
561
- path: "/",
562
- request: {
563
- body: {
564
- content: {
565
- "application/json": {
566
- schema: G
567
- }
568
- }
569
- }
570
- },
571
- security: [
572
- {
573
- Bearer: []
574
- }
575
- ],
576
- responses: {
577
- 201: {
578
- content: {
579
- "application/json": {
580
- schema: D
581
- }
582
- },
583
- description: "Tenant created"
584
- },
585
- 400: {
586
- description: "Validation error"
587
- },
588
- 409: {
589
- description: "Tenant with this ID already exists"
590
- }
591
- }
592
- }),
593
- async (n) => {
594
- var l, u;
595
- const a = n.var.user;
596
- if (!(a != null && a.sub))
597
- throw new P(401, {
598
- message: "Authentication required to create tenants"
599
- });
600
- let o = n.req.valid("json");
601
- const c = {
602
- adapters: n.env.data,
603
- ctx: n
604
- };
605
- (l = t.tenants) != null && l.beforeCreate && (o = await t.tenants.beforeCreate(c, o));
606
- const i = await n.env.data.tenants.create(o);
607
- return (u = t.tenants) != null && u.afterCreate && await t.tenants.afterCreate(c, i), n.json(i, 201);
608
- }
609
- ), r.openapi(
610
- M({
611
- tags: ["tenants"],
612
- method: "delete",
613
- path: "/{id}",
614
- request: {
615
- params: S.object({
616
- id: S.string()
617
- })
618
- },
619
- security: [
620
- {
621
- Bearer: ["delete:tenants"]
622
- }
623
- ],
624
- responses: {
625
- 204: {
626
- description: "Tenant deleted"
627
- },
628
- 403: {
629
- description: "Access denied or cannot delete the control plane"
630
- },
631
- 404: {
632
- description: "Tenant not found"
633
- }
634
- }
635
- }),
636
- async (n) => {
637
- var l, u, s, d;
638
- const { id: a } = n.req.valid("param"), o = ((l = e.accessControl) == null ? void 0 : l.controlPlaneTenantId) ?? ((u = n.env.data.multiTenancyConfig) == null ? void 0 : u.controlPlaneTenantId);
639
- if (o) {
640
- const m = n.var.user;
641
- if (!(m != null && m.sub))
642
- throw new P(401, {
643
- message: "Authentication required"
644
- });
645
- if (a === o)
646
- throw new P(403, {
647
- message: "Cannot delete the control plane"
648
- });
649
- if (!(await q(
650
- (g) => n.env.data.userOrganizations.listUserOrganizations(
651
- o,
652
- m.sub,
653
- g
654
- ),
655
- "organizations"
656
- )).some((g) => g.name === a))
657
- throw new P(403, {
658
- message: "Access denied to this tenant"
659
- });
660
- }
661
- if (!await n.env.data.tenants.get(a))
662
- throw new P(404, {
663
- message: "Tenant not found"
664
- });
665
- const i = {
666
- adapters: n.env.data,
667
- ctx: n
668
- };
669
- return (s = t.tenants) != null && s.beforeDelete && await t.tenants.beforeDelete(i, a), await n.env.data.tenants.remove(a), (d = t.tenants) != null && d.afterDelete && await t.tenants.afterDelete(i, a), n.body(null, 204);
670
- }
671
- ), r.openapi(
672
- M({
673
- tags: ["tenants", "settings"],
674
- method: "get",
675
- path: "/settings",
676
- request: {
677
- headers: S.object({
678
- "tenant-id": S.string().optional()
679
- })
680
- },
681
- security: [
682
- {
683
- Bearer: ["read:tenants"]
684
- }
685
- ],
686
- responses: {
687
- 200: {
688
- content: {
689
- "application/json": {
690
- schema: D
691
- }
692
- },
693
- description: "Current tenant settings"
694
- }
695
- }
696
- }),
697
- async (n) => {
698
- const a = await n.env.data.tenants.get(n.var.tenant_id);
699
- if (!a)
700
- throw new P(404, {
701
- message: "Tenant not found"
702
- });
703
- return n.json(a);
704
- }
705
- ), r.openapi(
706
- M({
707
- tags: ["tenants", "settings"],
708
- method: "patch",
709
- path: "/settings",
710
- request: {
711
- headers: S.object({
712
- "tenant-id": S.string().optional()
713
- }),
714
- body: {
715
- content: {
716
- "application/json": {
717
- schema: S.object(G.shape).partial()
718
- }
719
- }
720
- }
721
- },
722
- security: [
723
- {
724
- Bearer: ["update:tenants"]
725
- }
726
- ],
727
- responses: {
728
- 200: {
729
- content: {
730
- "application/json": {
731
- schema: D
732
- }
733
- },
734
- description: "Updated tenant settings"
735
- }
736
- }
737
- }),
738
- async (n) => {
739
- const a = n.req.valid("json"), { id: o, ...c } = a, i = await n.env.data.tenants.get(n.var.tenant_id);
740
- if (!i)
741
- throw new P(404, {
742
- message: "Tenant not found"
743
- });
744
- const l = ie(i, c);
745
- await n.env.data.tenants.update(n.var.tenant_id, l);
746
- const u = await n.env.data.tenants.get(n.var.tenant_id);
747
- if (!u)
748
- throw new P(500, {
749
- message: "Failed to retrieve updated tenant"
750
- });
751
- return n.json(u);
752
- }
753
- ), r;
754
- }
755
- function _e(e) {
756
- const t = [
757
- {
758
- pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
759
- type: "resource_server"
760
- },
761
- { pattern: /\/api\/v2\/roles\/([^/]+)$/, type: "role" },
762
- { pattern: /\/api\/v2\/connections\/([^/]+)$/, type: "connection" }
763
- ];
764
- for (const { pattern: r, type: n } of t) {
765
- const a = e.match(r);
766
- if (a && a[1])
767
- return { type: n, id: a[1] };
768
- }
769
- return null;
770
- }
771
- async function Te(e, t, r) {
772
- try {
773
- switch (r.type) {
774
- case "resource_server": {
775
- const n = await e.resourceServers.get(t, r.id);
776
- return (n == null ? void 0 : n.is_system) === !0;
777
- }
778
- case "role": {
779
- const n = await e.roles.get(t, r.id);
780
- return (n == null ? void 0 : n.is_system) === !0;
781
- }
782
- case "connection": {
783
- const n = await e.connections.get(t, r.id);
784
- return (n == null ? void 0 : n.is_system) === !0;
785
- }
786
- default:
787
- return !1;
788
- }
789
- } catch {
790
- return !1;
791
- }
288
+ //#endregion
289
+ //#region src/routes/tenants.ts
290
+ function k(e, t) {
291
+ let n = new d();
292
+ return n.openapi(f({
293
+ tags: ["tenants"],
294
+ method: "get",
295
+ path: "/",
296
+ request: { query: r },
297
+ security: [{ Bearer: [] }],
298
+ responses: { 200: {
299
+ content: { "application/json": { schema: p.object({
300
+ tenants: p.array(u),
301
+ start: p.number().optional(),
302
+ limit: p.number().optional(),
303
+ length: p.number().optional()
304
+ }) } },
305
+ description: "List of tenants"
306
+ } }
307
+ }), async (t) => {
308
+ let { page: n, per_page: r, include_totals: i, q: a } = t.req.valid("query"), o = t.var.user, c = o?.permissions || [];
309
+ if (!(o?.org_id ?? t.var.organization_id) && c.includes("admin:organizations")) {
310
+ let e = await t.env.data.tenants.list({
311
+ page: n,
312
+ per_page: r,
313
+ include_totals: i,
314
+ q: a
315
+ });
316
+ return i ? t.json({
317
+ tenants: e.tenants,
318
+ start: e.totals?.start ?? 0,
319
+ limit: e.totals?.limit ?? r,
320
+ length: e.tenants.length
321
+ }) : t.json({ tenants: e.tenants });
322
+ }
323
+ let l = e.accessControl?.controlPlaneTenantId ?? t.env.data.multiTenancyConfig?.controlPlaneTenantId;
324
+ if (l && !o?.sub) throw new O(403, { message: "Access denied: token has no subject" });
325
+ if (l && o?.sub) {
326
+ let e = (await s((e) => t.env.data.userOrganizations.listUserOrganizations(l, o.sub, e), "organizations")).map((e) => e.name);
327
+ if (e.length === 0) return i ? t.json({
328
+ tenants: [],
329
+ start: 0,
330
+ limit: r ?? 50,
331
+ length: 0
332
+ }) : t.json({ tenants: [] });
333
+ let c = e.length, u = n ?? 0, d = r ?? 50, f = u * d, p = e.slice(f, f + d);
334
+ if (p.length === 0) return i ? t.json({
335
+ tenants: [],
336
+ start: f,
337
+ limit: d,
338
+ length: c
339
+ }) : t.json({ tenants: [] });
340
+ let m = p.map((e) => `id:${e}`).join(" OR "), h = a ? `(${m}) AND (${a})` : m, g = await t.env.data.tenants.list({
341
+ q: h,
342
+ per_page: d,
343
+ include_totals: !1
344
+ });
345
+ return i ? t.json({
346
+ tenants: g.tenants,
347
+ start: f,
348
+ limit: d,
349
+ length: c
350
+ }) : t.json({ tenants: g.tenants });
351
+ }
352
+ let u = await t.env.data.tenants.list({
353
+ page: n,
354
+ per_page: r,
355
+ include_totals: i,
356
+ q: a
357
+ });
358
+ return i ? t.json({
359
+ tenants: u.tenants,
360
+ start: u.totals?.start ?? 0,
361
+ limit: u.totals?.limit ?? r,
362
+ length: u.tenants.length
363
+ }) : t.json({ tenants: u.tenants });
364
+ }), n.openapi(f({
365
+ tags: ["tenants"],
366
+ method: "post",
367
+ path: "/",
368
+ request: { body: { content: { "application/json": { schema: l } } } },
369
+ security: [{ Bearer: [] }],
370
+ responses: {
371
+ 201: {
372
+ content: { "application/json": { schema: u } },
373
+ description: "Tenant created"
374
+ },
375
+ 400: { description: "Validation error" },
376
+ 409: { description: "Tenant with this ID already exists" }
377
+ }
378
+ }), async (e) => {
379
+ if (!e.var.user?.sub) throw new O(401, { message: "Authentication required to create tenants" });
380
+ let n = e.req.valid("json"), r = {
381
+ adapters: e.env.data,
382
+ ctx: e
383
+ };
384
+ t.tenants?.beforeCreate && (n = await t.tenants.beforeCreate(r, n));
385
+ let i = await e.env.data.tenants.create(n);
386
+ return t.tenants?.afterCreate && await t.tenants.afterCreate(r, i), e.json(i, 201);
387
+ }), n.openapi(f({
388
+ tags: ["tenants"],
389
+ method: "delete",
390
+ path: "/{id}",
391
+ request: { params: p.object({ id: p.string() }) },
392
+ security: [{ Bearer: ["delete:tenants"] }],
393
+ responses: {
394
+ 204: { description: "Tenant deleted" },
395
+ 403: { description: "Access denied or cannot delete the control plane" },
396
+ 404: { description: "Tenant not found" }
397
+ }
398
+ }), async (n) => {
399
+ let { id: r } = n.req.valid("param"), i = e.accessControl?.controlPlaneTenantId ?? n.env.data.multiTenancyConfig?.controlPlaneTenantId;
400
+ if (i) {
401
+ let e = n.var.user;
402
+ if (!e?.sub) throw new O(401, { message: "Authentication required" });
403
+ if (r === i) throw new O(403, { message: "Cannot delete the control plane" });
404
+ let t = n.var.org_name, a = r.toLowerCase(), o = !!t && t.toLowerCase() === a;
405
+ if (o ||= (await s((t) => n.env.data.userOrganizations.listUserOrganizations(i, e.sub, t), "organizations")).some((e) => e.name?.toLowerCase() === a), !o) throw new O(403, { message: "Access denied to this tenant" });
406
+ }
407
+ if (!await n.env.data.tenants.get(r)) throw new O(404, { message: "Tenant not found" });
408
+ let a = {
409
+ adapters: n.env.data,
410
+ ctx: n
411
+ };
412
+ return t.tenants?.beforeDelete && await t.tenants.beforeDelete(a, r), await n.env.data.tenants.remove(r), t.tenants?.afterDelete && await t.tenants.afterDelete(a, r), n.body(null, 204);
413
+ }), n.openapi(f({
414
+ tags: ["tenants", "settings"],
415
+ method: "get",
416
+ path: "/settings",
417
+ request: { headers: p.object({ "tenant-id": p.string().optional() }) },
418
+ security: [{ Bearer: ["read:tenants"] }],
419
+ responses: { 200: {
420
+ content: { "application/json": { schema: u } },
421
+ description: "Current tenant settings"
422
+ } }
423
+ }), async (e) => {
424
+ let t = await e.env.data.tenants.get(e.var.tenant_id);
425
+ if (!t) throw new O(404, { message: "Tenant not found" });
426
+ return e.json(t);
427
+ }), n.openapi(f({
428
+ tags: ["tenants", "settings"],
429
+ method: "patch",
430
+ path: "/settings",
431
+ request: {
432
+ headers: p.object({ "tenant-id": p.string().optional() }),
433
+ body: { content: { "application/json": { schema: p.object(l.shape).partial() } } }
434
+ },
435
+ security: [{ Bearer: ["update:tenants"] }],
436
+ responses: { 200: {
437
+ content: { "application/json": { schema: u } },
438
+ description: "Updated tenant settings"
439
+ } }
440
+ }), async (e) => {
441
+ let { id: t, ...n } = e.req.valid("json"), r = await e.env.data.tenants.get(e.var.tenant_id);
442
+ if (!r) throw new O(404, { message: "Tenant not found" });
443
+ let i = o(r, n);
444
+ await e.env.data.tenants.update(e.var.tenant_id, i);
445
+ let a = await e.env.data.tenants.get(e.var.tenant_id);
446
+ if (!a) throw new O(500, { message: "Failed to retrieve updated tenant" });
447
+ return e.json(a);
448
+ }), n;
449
+ }
450
+ //#endregion
451
+ //#region src/middleware/protect-synced.ts
452
+ function A(e) {
453
+ for (let { pattern: t, type: n } of [
454
+ {
455
+ pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
456
+ type: "resource_server"
457
+ },
458
+ {
459
+ pattern: /\/api\/v2\/roles\/([^/]+)$/,
460
+ type: "role"
461
+ },
462
+ {
463
+ pattern: /\/api\/v2\/connections\/([^/]+)$/,
464
+ type: "connection"
465
+ }
466
+ ]) {
467
+ let r = e.match(t);
468
+ if (r && r[1]) return {
469
+ type: n,
470
+ id: r[1]
471
+ };
472
+ }
473
+ return null;
474
+ }
475
+ async function j(e, t, n) {
476
+ try {
477
+ switch (n.type) {
478
+ case "resource_server": return (await e.resourceServers.get(t, n.id))?.is_system === !0;
479
+ case "role": return (await e.roles.get(t, n.id))?.is_system === !0;
480
+ case "connection": return (await e.connections.get(t, n.id))?.is_system === !0;
481
+ default: return !1;
482
+ }
483
+ } catch {
484
+ return !1;
485
+ }
486
+ }
487
+ function M(e) {
488
+ return {
489
+ resource_server: "resource server",
490
+ role: "role",
491
+ connection: "connection"
492
+ }[e];
493
+ }
494
+ function N() {
495
+ return async (e, t) => {
496
+ if (![
497
+ "PATCH",
498
+ "PUT",
499
+ "DELETE"
500
+ ].includes(e.req.method)) return t();
501
+ let n = A(e.req.path);
502
+ if (!n) return t();
503
+ let r = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
504
+ if (!r) return t();
505
+ if (await j(e.env.data, r, n)) throw new O(403, { message: `This ${M(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.` });
506
+ return t();
507
+ };
508
+ }
509
+ //#endregion
510
+ //#region src/middleware/settings-inheritance.ts
511
+ function P(e, t) {
512
+ let n = t.find((t) => t.strategy === e.strategy);
513
+ if (!n?.options) return e;
514
+ let r = a.passthrough().parse({
515
+ ...n,
516
+ ...e
517
+ });
518
+ return r.options = i.passthrough().parse({
519
+ ...n.options || {},
520
+ ...e.options
521
+ }), r;
522
+ }
523
+ function F(e, t) {
524
+ let n = [...t || [], ...e || []];
525
+ return [...new Set(n)];
526
+ }
527
+ function I(e, t) {
528
+ if (!t?.length) return e || [];
529
+ if (!e?.length) return t;
530
+ let n = /* @__PURE__ */ new Map();
531
+ for (let e of t) n.set(e.value, e);
532
+ for (let t of e) n.set(t.value, t);
533
+ return Array.from(n.values());
534
+ }
535
+ function L(e, t) {
536
+ return t ? {
537
+ ...e,
538
+ scopes: I(e.scopes, t.scopes)
539
+ } : e;
540
+ }
541
+ function R(e, t) {
542
+ return t ? {
543
+ ...e,
544
+ callbacks: F(e.callbacks, t.callbacks),
545
+ web_origins: F(e.web_origins, t.web_origins),
546
+ allowed_logout_urls: F(e.allowed_logout_urls, t.allowed_logout_urls),
547
+ allowed_origins: F(e.allowed_origins, t.allowed_origins)
548
+ } : e;
549
+ }
550
+ function z(e) {
551
+ let { controlPlaneTenantId: t, controlPlaneClientId: n, resolveControlPlane: r } = e;
552
+ if (r) return async (e) => r({ tenant_id: e });
553
+ if (!t) return async () => void 0;
554
+ let i = {
555
+ tenantId: t,
556
+ clientId: n
557
+ };
558
+ return async () => i;
792
559
  }
793
- function Ce(e) {
794
- return {
795
- resource_server: "resource server",
796
- role: "role",
797
- connection: "connection"
798
- }[e];
799
- }
800
- function Pe() {
801
- return async (e, t) => {
802
- if (!["PATCH", "PUT", "DELETE"].includes(e.req.method))
803
- return t();
804
- const r = _e(e.req.path);
805
- if (!r)
806
- return t();
807
- const n = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
808
- if (!n)
809
- return t();
810
- if (await Te(e.env.data, n, r))
811
- throw new P(403, {
812
- message: `This ${Ce(r.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`
813
- });
814
- return t();
815
- };
816
- }
817
- function N(e, t) {
818
- const r = t.find(
819
- (a) => a.strategy === e.strategy
820
- );
821
- if (!(r != null && r.options))
822
- return e;
823
- const n = ce.passthrough().parse({
824
- ...r,
825
- ...e
826
- });
827
- return n.options = le.passthrough().parse({
828
- ...r.options || {},
829
- ...e.options
830
- }), n;
831
- }
832
- function O(e, t) {
833
- const r = [...t || [], ...e || []];
834
- return [...new Set(r)];
835
- }
836
- function be(e, t) {
837
- if (!(t != null && t.length))
838
- return e || [];
839
- if (!(e != null && e.length))
840
- return t;
841
- const r = /* @__PURE__ */ new Map();
842
- for (const n of t)
843
- r.set(n.value, n);
844
- for (const n of e)
845
- r.set(n.value, n);
846
- return Array.from(r.values());
560
+ function B(e, t) {
561
+ return {
562
+ ...e.resourceServers,
563
+ get: async (n, r) => {
564
+ let i = await e.resourceServers.get(n, r);
565
+ if (!i) return i;
566
+ let a = await t(n);
567
+ return !a || n === a.tenantId || !i.is_system ? i : L(i, await e.resourceServers.get(a.tenantId, r));
568
+ },
569
+ list: async (n, r) => {
570
+ let i = await e.resourceServers.list(n, r), a = await t(n);
571
+ if (!a || n === a.tenantId) return i;
572
+ let o = a.tenantId, s = i.resource_servers.filter((e) => !!(e.is_system && e.id)).map((e) => e.id);
573
+ if (s.length === 0) return i;
574
+ let c = /* @__PURE__ */ new Map();
575
+ await Promise.all(s.map(async (t) => {
576
+ let n = await e.resourceServers.get(o, t);
577
+ n && c.set(t, n);
578
+ }));
579
+ let l = i.resource_servers.map((e) => e.is_system && e.id ? L(e, c.get(e.id) ?? null) : e);
580
+ return {
581
+ ...i,
582
+ resource_servers: l
583
+ };
584
+ }
585
+ };
847
586
  }
848
587
  function V(e, t) {
849
- return t ? {
850
- ...e,
851
- scopes: be(
852
- e.scopes,
853
- t.scopes
854
- )
855
- } : e;
588
+ let n = z({
589
+ controlPlaneTenantId: t.controlPlaneTenantId,
590
+ resolveControlPlane: t.resolveControlPlane
591
+ });
592
+ return {
593
+ ...e,
594
+ resourceServers: B(e, n)
595
+ };
596
+ }
597
+ function H(e, t) {
598
+ let { controlPlaneTenantId: n, controlPlaneClientId: r, resolveControlPlane: i } = t, a = z({
599
+ controlPlaneTenantId: n,
600
+ controlPlaneClientId: r,
601
+ resolveControlPlane: i
602
+ });
603
+ return {
604
+ ...e,
605
+ multiTenancyConfig: {
606
+ controlPlaneTenantId: n,
607
+ controlPlaneClientId: r,
608
+ resolveControlPlane: i
609
+ },
610
+ connections: {
611
+ ...e.connections,
612
+ get: async (t, n) => {
613
+ let r = await e.connections.get(t, n);
614
+ if (!r) return r;
615
+ let i = await a(t);
616
+ return !i || t === i.tenantId ? r : P(r, (await e.connections.list(i.tenantId)).connections || []);
617
+ },
618
+ list: async (t, n) => {
619
+ let r = await e.connections.list(t, n), i = await a(t);
620
+ if (!i || t === i.tenantId) return r;
621
+ let o = await e.connections.list(i.tenantId), s = r.connections.map((e) => P(e, o.connections || []));
622
+ return {
623
+ ...r,
624
+ connections: s
625
+ };
626
+ }
627
+ },
628
+ clientConnections: {
629
+ ...e.clientConnections,
630
+ listByClient: async (t, n) => {
631
+ let r = await e.clientConnections.listByClient(t, n);
632
+ r.length === 0 && (r = (await e.connections.list(t)).connections || []);
633
+ let i = await a(t);
634
+ if (!i || t === i.tenantId) return r;
635
+ let o = await e.connections.list(i.tenantId);
636
+ return r.map((e) => P(e, o.connections || []));
637
+ }
638
+ },
639
+ emailProviders: {
640
+ ...e.emailProviders,
641
+ get: async (t) => {
642
+ let n = await e.emailProviders.get(t);
643
+ if (n) return n;
644
+ let r = await a(t);
645
+ return !r || t === r.tenantId ? null : e.emailProviders.get(r.tenantId);
646
+ }
647
+ },
648
+ resourceServers: B(e, a),
649
+ hooks: W(e, a)
650
+ };
856
651
  }
857
- function Oe(e, t) {
858
- return t ? {
859
- ...e,
860
- callbacks: O(e.callbacks, t.callbacks),
861
- web_origins: O(
862
- e.web_origins,
863
- t.web_origins
864
- ),
865
- allowed_logout_urls: O(
866
- e.allowed_logout_urls,
867
- t.allowed_logout_urls
868
- ),
869
- allowed_origins: O(
870
- e.allowed_origins,
871
- t.allowed_origins
872
- )
873
- } : e;
874
- }
875
- function Z(e) {
876
- const { controlPlaneTenantId: t, controlPlaneClientId: r, resolveControlPlane: n } = e;
877
- if (n)
878
- return async (o) => n({ tenant_id: o });
879
- if (!t)
880
- return async () => {
881
- };
882
- const a = {
883
- tenantId: t,
884
- clientId: r
885
- };
886
- return async () => a;
887
- }
888
- function x(e, t) {
889
- return {
890
- ...e.resourceServers,
891
- get: async (r, n) => {
892
- const a = await e.resourceServers.get(
893
- r,
894
- n
895
- );
896
- if (!a)
897
- return a;
898
- const o = await t(r);
899
- if (!o || r === o.tenantId || !a.is_system)
900
- return a;
901
- const c = await e.resourceServers.get(
902
- o.tenantId,
903
- n
904
- );
905
- return V(
906
- a,
907
- c
908
- );
909
- },
910
- list: async (r, n) => {
911
- const a = await e.resourceServers.list(r, n), o = await t(r);
912
- if (!o || r === o.tenantId)
913
- return a;
914
- const c = o.tenantId, i = a.resource_servers.filter(
915
- (s) => !!(s.is_system && s.id)
916
- ).map((s) => s.id);
917
- if (i.length === 0)
918
- return a;
919
- const l = /* @__PURE__ */ new Map();
920
- await Promise.all(
921
- i.map(async (s) => {
922
- const d = await e.resourceServers.get(c, s);
923
- d && l.set(s, d);
924
- })
925
- );
926
- const u = a.resource_servers.map(
927
- (s) => s.is_system && s.id ? V(
928
- s,
929
- l.get(s.id) ?? null
930
- ) : s
931
- );
932
- return {
933
- ...a,
934
- resource_servers: u
935
- };
936
- }
937
- };
938
- }
939
- function Ie(e, t) {
940
- const r = Z({
941
- controlPlaneTenantId: t.controlPlaneTenantId,
942
- resolveControlPlane: t.resolveControlPlane
943
- });
944
- return {
945
- ...e,
946
- resourceServers: x(
947
- e,
948
- r
949
- )
950
- };
951
- }
952
- function Ae(e, t) {
953
- const { controlPlaneTenantId: r, controlPlaneClientId: n, resolveControlPlane: a } = t, o = Z({
954
- controlPlaneTenantId: r,
955
- controlPlaneClientId: n,
956
- resolveControlPlane: a
957
- });
958
- return {
959
- ...e,
960
- // Store the static config for use by tenants route access control.
961
- // Per-tenant inheritance overrides do NOT affect access-control values —
962
- // those intentionally use a single global control plane id. The resolver
963
- // is exposed here so runtime helpers (e.g. `getEnrichedClient`) can
964
- // consult it before merging control-plane URLs.
965
- multiTenancyConfig: {
966
- controlPlaneTenantId: r,
967
- controlPlaneClientId: n,
968
- resolveControlPlane: a
969
- },
970
- connections: {
971
- ...e.connections,
972
- get: async (c, i) => {
973
- const l = await e.connections.get(
974
- c,
975
- i
976
- );
977
- if (!l)
978
- return l;
979
- const u = await o(c);
980
- if (!u || c === u.tenantId)
981
- return l;
982
- const s = await e.connections.list(
983
- u.tenantId
984
- );
985
- return N(
986
- l,
987
- s.connections || []
988
- );
989
- },
990
- list: async (c, i) => {
991
- const l = await e.connections.list(c, i), u = await o(c);
992
- if (!u || c === u.tenantId)
993
- return l;
994
- const s = await e.connections.list(
995
- u.tenantId
996
- ), d = l.connections.map(
997
- (m) => N(
998
- m,
999
- s.connections || []
1000
- )
1001
- );
1002
- return {
1003
- ...l,
1004
- connections: d
1005
- };
1006
- }
1007
- },
1008
- clientConnections: {
1009
- ...e.clientConnections,
1010
- listByClient: async (c, i) => {
1011
- let l = await e.clientConnections.listByClient(
1012
- c,
1013
- i
1014
- );
1015
- l.length === 0 && (l = (await e.connections.list(c)).connections || []);
1016
- const u = await o(c);
1017
- if (!u || c === u.tenantId)
1018
- return l;
1019
- const s = await e.connections.list(
1020
- u.tenantId
1021
- );
1022
- return l.map(
1023
- (d) => N(
1024
- d,
1025
- s.connections || []
1026
- )
1027
- );
1028
- }
1029
- },
1030
- // Note: clients.get / getByClientId are intentionally NOT wrapped here.
1031
- // Storage reads must return the tenant's own stored URLs so that the
1032
- // management API and DCR don't echo control-plane callbacks back on
1033
- // update. Runtime URL merging for auth flows happens in
1034
- // `getEnrichedClient` (packages/authhero/src/helpers/client.ts).
1035
- emailProviders: {
1036
- ...e.emailProviders,
1037
- get: async (c) => {
1038
- const i = await e.emailProviders.get(c);
1039
- if (i)
1040
- return i;
1041
- const l = await o(c);
1042
- return !l || c === l.tenantId ? null : e.emailProviders.get(l.tenantId);
1043
- }
1044
- },
1045
- resourceServers: x(
1046
- e,
1047
- o
1048
- ),
1049
- hooks: Se(e, o)
1050
- // Note: Additional adapters can be extended here for runtime fallback:
1051
- // - promptSettings: Fall back to control plane prompts
1052
- // - branding: Fall back to control plane branding/themes
1053
- };
652
+ function U(e) {
653
+ if (!e || typeof e != "object") return !1;
654
+ let t = e.metadata;
655
+ return !t || typeof t != "object" ? !1 : t.inheritable === !0;
656
+ }
657
+ function W(e, t) {
658
+ return {
659
+ ...e.hooks,
660
+ list: async (n, r) => {
661
+ let i = await e.hooks.list(n, r), a = await t(n);
662
+ if (!a || n === a.tenantId) return i;
663
+ let o = ((await e.hooks.list(a.tenantId, r)).hooks || []).filter(U);
664
+ if (o.length === 0) return i;
665
+ let s = new Set((i.hooks || []).map((e) => e.hook_id)), c = o.filter((e) => !s.has(e.hook_id));
666
+ return {
667
+ ...i,
668
+ hooks: [...i.hooks || [], ...c],
669
+ length: typeof i.length == "number" ? i.length + c.length : i.length
670
+ };
671
+ },
672
+ get: async (n, r) => {
673
+ let i = await e.hooks.get(n, r);
674
+ if (i) return i;
675
+ let a = await t(n);
676
+ if (!a || n === a.tenantId) return i;
677
+ let o = await e.hooks.get(a.tenantId, r);
678
+ return o && U(o) ? o : null;
679
+ }
680
+ };
681
+ }
682
+ function G(e, t) {
683
+ return H(e, t);
684
+ }
685
+ //#endregion
686
+ //#region src/middleware/index.ts
687
+ function K(e) {
688
+ return async (t, n) => {
689
+ let r = t.var.user;
690
+ return r?.tenant_id === e && r.org_name && t.set("tenant_id", r.org_name), n();
691
+ };
692
+ }
693
+ function q(e) {
694
+ return async (n, r) => {
695
+ if (!e.accessControl) return r();
696
+ let { controlPlaneTenantId: i } = e.accessControl, a = n.var.org_name, o = n.var.organization_id, s = a || o, c = n.var.tenant_id, l = n.var.user, u = (l?.aud ? Array.isArray(l.aud) ? l.aud : [l.aud] : []).includes(t);
697
+ if (!c && s && u && (n.set("tenant_id", s), c = s), !c) throw new O(400, { message: "Tenant ID not found in request" });
698
+ if (!h(o, c, i, a)) throw new O(403, { message: `Access denied to tenant ${c}` });
699
+ return r();
700
+ };
1054
701
  }
1055
702
  function J(e) {
1056
- if (!e || typeof e != "object") return !1;
1057
- const t = e.metadata;
1058
- return !t || typeof t != "object" ? !1 : t.inheritable === !0;
703
+ return async (t, n) => {
704
+ if (!e.subdomainRouting) return n();
705
+ let { baseDomain: r, reservedSubdomains: i = [], resolveSubdomain: a } = e.subdomainRouting, o = t.req.header("x-forwarded-host") || t.req.header("host") || "", s = null;
706
+ if (o.endsWith(r)) {
707
+ let e = o.slice(0, -(r.length + 1));
708
+ e && !e.includes(".") && (s = e);
709
+ }
710
+ if (s && i.includes(s) && (s = null), !s) return e.accessControl && t.set("tenant_id", e.accessControl.controlPlaneTenantId), n();
711
+ let c = null;
712
+ if (a) c = await a(s);
713
+ else if (e.subdomainRouting.useOrganizations !== !1 && e.accessControl) try {
714
+ let n = await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId, s);
715
+ n && (c = n.id);
716
+ } catch {}
717
+ if (!c) throw new O(404, { message: `Tenant not found for subdomain: ${s}` });
718
+ return t.set("tenant_id", c), n();
719
+ };
1059
720
  }
1060
- function Se(e, t) {
1061
- return {
1062
- ...e.hooks,
1063
- list: async (r, n) => {
1064
- const a = await e.hooks.list(r, n), o = await t(r);
1065
- if (!o || r === o.tenantId)
1066
- return a;
1067
- const i = ((await e.hooks.list(
1068
- o.tenantId,
1069
- n
1070
- )).hooks || []).filter(
1071
- J
1072
- );
1073
- if (i.length === 0)
1074
- return a;
1075
- const l = new Set((a.hooks || []).map((s) => s.hook_id)), u = i.filter((s) => !l.has(s.hook_id));
1076
- return {
1077
- ...a,
1078
- hooks: [...a.hooks || [], ...u],
1079
- length: typeof a.length == "number" ? a.length + u.length : a.length
1080
- };
1081
- },
1082
- get: async (r, n) => {
1083
- const a = await e.hooks.get(r, n);
1084
- if (a) return a;
1085
- const o = await t(r);
1086
- if (!o || r === o.tenantId)
1087
- return a;
1088
- const c = await e.hooks.get(
1089
- o.tenantId,
1090
- n
1091
- );
1092
- return c && J(c) ? c : null;
1093
- }
1094
- };
1095
- }
1096
- function ee(e, t) {
1097
- return Ae(e, t);
1098
- }
1099
- function Re(e) {
1100
- return async (t, r) => {
1101
- const n = t.var.user;
1102
- return (n == null ? void 0 : n.tenant_id) === e && n.org_name && t.set("tenant_id", n.org_name), r();
1103
- };
1104
- }
1105
- function ze(e) {
1106
- return async (t, r) => {
1107
- if (!e.accessControl)
1108
- return r();
1109
- const { controlPlaneTenantId: n } = e.accessControl, a = t.var.org_name, o = t.var.organization_id, c = a || o;
1110
- let i = t.var.tenant_id;
1111
- const l = t.var.user, s = (l != null && l.aud ? Array.isArray(l.aud) ? l.aud : [l.aud] : []).includes(X);
1112
- if (!i && c && s && (t.set("tenant_id", c), i = c), !i)
1113
- throw new P(400, {
1114
- message: "Tenant ID not found in request"
1115
- });
1116
- if (!me(
1117
- o,
1118
- i,
1119
- n,
1120
- a
1121
- ))
1122
- throw new P(403, {
1123
- message: `Access denied to tenant ${i}`
1124
- });
1125
- return r();
1126
- };
1127
- }
1128
- function $e(e) {
1129
- return async (t, r) => {
1130
- if (!e.subdomainRouting)
1131
- return r();
1132
- const {
1133
- baseDomain: n,
1134
- reservedSubdomains: a = [],
1135
- resolveSubdomain: o
1136
- } = e.subdomainRouting, c = t.req.header("x-forwarded-host") || t.req.header("host") || "";
1137
- let i = null;
1138
- if (c.endsWith(n)) {
1139
- const u = c.slice(0, -(n.length + 1));
1140
- u && !u.includes(".") && (i = u);
1141
- }
1142
- if (i && a.includes(i) && (i = null), !i)
1143
- return e.accessControl && t.set("tenant_id", e.accessControl.controlPlaneTenantId), r();
1144
- let l = null;
1145
- if (o)
1146
- l = await o(i);
1147
- else if (e.subdomainRouting.useOrganizations !== !1 && e.accessControl)
1148
- try {
1149
- const u = await t.env.data.organizations.get(
1150
- e.accessControl.controlPlaneTenantId,
1151
- i
1152
- );
1153
- u && (l = u.id);
1154
- } catch {
1155
- }
1156
- if (!l)
1157
- throw new P(404, {
1158
- message: `Tenant not found for subdomain: ${i}`
1159
- });
1160
- return t.set("tenant_id", l), r();
1161
- };
721
+ function Y(e) {
722
+ return async (t, n) => {
723
+ if (!e.databaseIsolation) return n();
724
+ let r = t.var.tenant_id;
725
+ if (!r) throw new O(400, { message: "Tenant ID not found in request" });
726
+ try {
727
+ let n = await e.databaseIsolation.getAdapters(r);
728
+ t.env.data = n;
729
+ } catch (e) {
730
+ throw console.error(`Failed to resolve database for tenant ${r}:`, e), new O(500, { message: "Failed to resolve tenant database" });
731
+ }
732
+ return n();
733
+ };
734
+ }
735
+ function X(e) {
736
+ let t = J(e), n = q(e), r = Y(e);
737
+ return async (e, i) => (await t(e, async () => {}), await n(e, async () => {}), await r(e, async () => {}), i());
738
+ }
739
+ //#endregion
740
+ //#region src/init.ts
741
+ function Z(e) {
742
+ let { dataAdapter: t, controlPlane: n, controlPlane: { tenantId: r = "control_plane", clientId: i } = {}, resolveControlPlane: a, sync: o = {
743
+ resourceServers: !0,
744
+ roles: !0
745
+ }, defaultPermissions: l = ["tenant:admin"], requireOrganizationMatch: u = !1, managementApiExtensions: d = [], entityHooks: f, getChildTenantIds: p, getAdapters: m, ...h } = e;
746
+ 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.");
747
+ let g = t, _ = t;
748
+ n && (g = G(t, {
749
+ controlPlaneTenantId: r,
750
+ controlPlaneClientId: i,
751
+ resolveControlPlane: a
752
+ }), _ = {
753
+ ...V(t, {
754
+ controlPlaneTenantId: r,
755
+ resolveControlPlane: a
756
+ }),
757
+ multiTenancyConfig: {
758
+ controlPlaneTenantId: r,
759
+ controlPlaneClientId: i,
760
+ resolveControlPlane: a
761
+ }
762
+ });
763
+ let y = o !== !1, b = y ? {
764
+ resourceServers: o.resourceServers ?? !0,
765
+ roles: o.roles ?? !0
766
+ } : {
767
+ resourceServers: !1,
768
+ roles: !1
769
+ }, { entityHooks: x, tenantHooks: S } = D({
770
+ controlPlaneTenantId: r,
771
+ getChildTenantIds: p ?? (async () => (await s((e) => g.tenants.list(e), "tenants", {
772
+ cursorField: "id",
773
+ pageSize: 100
774
+ })).filter((e) => e.id !== r).map((e) => e.id)),
775
+ getAdapters: m ?? (async () => g),
776
+ getControlPlaneAdapters: async () => g,
777
+ sync: b
778
+ }), C = {
779
+ resourceServers: [x.resourceServers, ...f?.resourceServers ?? []],
780
+ roles: [x.roles, ...f?.roles ?? []],
781
+ connections: f?.connections ?? [],
782
+ tenants: f?.tenants ?? [],
783
+ rolePermissions: f?.rolePermissions ?? []
784
+ }, w = v({ accessControl: {
785
+ controlPlaneTenantId: r,
786
+ requireOrganizationMatch: u,
787
+ defaultPermissions: l
788
+ } }), T = k({ accessControl: {
789
+ controlPlaneTenantId: r,
790
+ requireOrganizationMatch: u,
791
+ defaultPermissions: l
792
+ } }, { tenants: {
793
+ async beforeCreate(e, t) {
794
+ return w.beforeCreate && (t = await w.beforeCreate(e, t)), S.beforeCreate && (t = await S.beforeCreate(e, t)), t;
795
+ },
796
+ async afterCreate(e, t) {
797
+ await w.afterCreate?.(e, t), await S.afterCreate?.(e, t);
798
+ },
799
+ async beforeDelete(e, t) {
800
+ await w.beforeDelete?.(e, t), await S.beforeDelete?.(e, t);
801
+ }
802
+ } }), { app: E } = c({
803
+ dataAdapter: g,
804
+ managementDataAdapter: _,
805
+ ...h,
806
+ entityHooks: C,
807
+ managementApiExtensions: [...d, {
808
+ path: "/tenants",
809
+ router: T
810
+ }]
811
+ });
812
+ return E.use("/api/v2/*", K(r)), y && E.use("/api/v2/*", N()), {
813
+ app: E,
814
+ controlPlaneTenantId: r
815
+ };
816
+ }
817
+ //#endregion
818
+ //#region src/plugin.ts
819
+ function ee(e) {
820
+ let t = Q(e);
821
+ return {
822
+ name: "multi-tenancy",
823
+ middleware: X(e),
824
+ hooks: t,
825
+ routes: [{
826
+ path: "/management",
827
+ handler: k(e, t)
828
+ }],
829
+ onRegister: async () => {
830
+ 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");
831
+ }
832
+ };
833
+ }
834
+ //#endregion
835
+ //#region src/index.ts
836
+ function Q(e) {
837
+ let t = e.accessControl ? m(e.accessControl) : {}, n = e.databaseIsolation ? g(e.databaseIsolation) : {}, r = v(e);
838
+ return {
839
+ ...t,
840
+ ...n,
841
+ tenants: r
842
+ };
1162
843
  }
1163
- function je(e) {
1164
- return async (t, r) => {
1165
- if (!e.databaseIsolation)
1166
- return r();
1167
- const n = t.var.tenant_id;
1168
- if (!n)
1169
- throw new P(400, {
1170
- message: "Tenant ID not found in request"
1171
- });
1172
- try {
1173
- const a = await e.databaseIsolation.getAdapters(n);
1174
- t.env.data = a;
1175
- } catch (a) {
1176
- throw console.error(
1177
- `Failed to resolve database for tenant ${n}:`,
1178
- a
1179
- ), new P(500, {
1180
- message: "Failed to resolve tenant database"
1181
- });
1182
- }
1183
- return r();
1184
- };
844
+ function $(t) {
845
+ let n = new e(), r = Q(t);
846
+ return n.route("/tenants", k(t, r)), n;
1185
847
  }
1186
848
  function te(e) {
1187
- const t = $e(e), r = ze(e), n = je(e);
1188
- return async (a, o) => (await t(a, async () => {
1189
- }), await r(a, async () => {
1190
- }), await n(a, async () => {
1191
- }), o());
1192
- }
1193
- function Ee(e) {
1194
- const {
1195
- dataAdapter: t,
1196
- controlPlane: r,
1197
- controlPlane: {
1198
- tenantId: n = "control_plane",
1199
- clientId: a
1200
- } = {},
1201
- resolveControlPlane: o,
1202
- sync: c = { resourceServers: !0, roles: !0 },
1203
- defaultPermissions: i = ["tenant:admin"],
1204
- requireOrganizationMatch: l = !1,
1205
- managementApiExtensions: u = [],
1206
- entityHooks: s,
1207
- getChildTenantIds: d,
1208
- getAdapters: m,
1209
- ...w
1210
- } = e;
1211
- if (o && !r)
1212
- throw new Error(
1213
- "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."
1214
- );
1215
- let f = t, g = t;
1216
- r && (f = ee(t, {
1217
- controlPlaneTenantId: n,
1218
- controlPlaneClientId: a,
1219
- resolveControlPlane: o
1220
- }), g = {
1221
- ...Ie(t, {
1222
- controlPlaneTenantId: n,
1223
- resolveControlPlane: o
1224
- }),
1225
- multiTenancyConfig: {
1226
- controlPlaneTenantId: n,
1227
- controlPlaneClientId: a,
1228
- resolveControlPlane: o
1229
- }
1230
- });
1231
- const _ = c !== !1, h = _ ? {
1232
- resourceServers: c.resourceServers ?? !0,
1233
- roles: c.roles ?? !0
1234
- } : { resourceServers: !1, roles: !1 }, z = {
1235
- controlPlaneTenantId: n,
1236
- getChildTenantIds: d ?? (async () => (await q(
1237
- (y) => f.tenants.list(y),
1238
- "tenants",
1239
- { cursorField: "id", pageSize: 100 }
1240
- )).filter((y) => y.id !== n).map((y) => y.id)),
1241
- getAdapters: m ?? (async () => f),
1242
- getControlPlaneAdapters: async () => f,
1243
- sync: h
1244
- }, { entityHooks: v, tenantHooks: p } = ve(z), C = {
1245
- resourceServers: [
1246
- v.resourceServers,
1247
- ...(s == null ? void 0 : s.resourceServers) ?? []
1248
- ],
1249
- roles: [v.roles, ...(s == null ? void 0 : s.roles) ?? []],
1250
- connections: (s == null ? void 0 : s.connections) ?? [],
1251
- tenants: (s == null ? void 0 : s.tenants) ?? [],
1252
- rolePermissions: (s == null ? void 0 : s.rolePermissions) ?? []
1253
- }, I = Y({
1254
- accessControl: {
1255
- controlPlaneTenantId: n,
1256
- requireOrganizationMatch: l,
1257
- defaultPermissions: i
1258
- }
1259
- }), k = B(
1260
- {
1261
- accessControl: {
1262
- controlPlaneTenantId: n,
1263
- requireOrganizationMatch: l,
1264
- defaultPermissions: i
1265
- }
1266
- },
1267
- { tenants: {
1268
- async beforeCreate(A, y) {
1269
- return I.beforeCreate && (y = await I.beforeCreate(A, y)), p.beforeCreate && (y = await p.beforeCreate(A, y)), y;
1270
- },
1271
- async afterCreate(A, y) {
1272
- var $, R;
1273
- await (($ = I.afterCreate) == null ? void 0 : $.call(I, A, y)), await ((R = p.afterCreate) == null ? void 0 : R.call(p, A, y));
1274
- },
1275
- async beforeDelete(A, y) {
1276
- var $, R;
1277
- await (($ = I.beforeDelete) == null ? void 0 : $.call(I, A, y)), await ((R = p.beforeDelete) == null ? void 0 : R.call(p, A, y));
1278
- }
1279
- } }
1280
- ), { app: F } = ue({
1281
- dataAdapter: f,
1282
- managementDataAdapter: g,
1283
- ...w,
1284
- entityHooks: C,
1285
- managementApiExtensions: [
1286
- ...u,
1287
- { path: "/tenants", router: k }
1288
- ]
1289
- });
1290
- return F.use(
1291
- "/api/v2/*",
1292
- Re(n)
1293
- ), _ && F.use("/api/v2/*", Pe()), { app: F, controlPlaneTenantId: n };
1294
- }
1295
- function Ne(e) {
1296
- const t = U(e);
1297
- return {
1298
- name: "multi-tenancy",
1299
- // Apply multi-tenancy middleware for subdomain routing, database resolution, etc.
1300
- middleware: te(e),
1301
- // Provide lifecycle hooks
1302
- hooks: t,
1303
- // Mount tenant management routes
1304
- routes: [
1305
- {
1306
- path: "/management",
1307
- handler: B(e, t)
1308
- }
1309
- ],
1310
- // Called when plugin is registered
1311
- onRegister: async () => {
1312
- console.log("Multi-tenancy plugin registered"), e.accessControl && console.log(
1313
- ` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`
1314
- ), e.subdomainRouting && console.log(
1315
- ` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`
1316
- ), e.databaseIsolation && console.log(" - Database isolation enabled");
1317
- }
1318
- };
1319
- }
1320
- function U(e) {
1321
- const t = e.accessControl ? fe(e.accessControl) : {}, r = e.databaseIsolation ? ge(e.databaseIsolation) : {}, n = Y(e);
1322
- return {
1323
- ...t,
1324
- ...r,
1325
- tenants: n
1326
- };
1327
- }
1328
- function ke(e) {
1329
- const t = new ae(), r = U(e);
1330
- return t.route("/tenants", B(e, r)), t;
1331
- }
1332
- function Be(e) {
1333
- return {
1334
- hooks: U(e),
1335
- middleware: te(e),
1336
- app: ke(e),
1337
- config: e,
1338
- /**
1339
- * Wraps data adapters with runtime fallback from the control plane.
1340
- * Uses the controlPlaneTenantId from the multi-tenancy config.
1341
- *
1342
- * @param adapters - Base data adapters to wrap
1343
- * @param additionalConfig - Additional config (controlPlaneClientId, etc.)
1344
- * @returns Wrapped adapters with runtime fallback
1345
- */
1346
- wrapAdapters: (t, r) => {
1347
- var n;
1348
- return ee(t, {
1349
- controlPlaneTenantId: (n = e.accessControl) == null ? void 0 : n.controlPlaneTenantId,
1350
- controlPlaneClientId: r == null ? void 0 : r.controlPlaneClientId
1351
- });
1352
- }
1353
- };
1354
- }
1355
- export {
1356
- fe as createAccessControlHooks,
1357
- ze as createAccessControlMiddleware,
1358
- Re as createControlPlaneTenantMiddleware,
1359
- ge as createDatabaseHooks,
1360
- je as createDatabaseMiddleware,
1361
- ke as createMultiTenancy,
1362
- U as createMultiTenancyHooks,
1363
- te as createMultiTenancyMiddleware,
1364
- Ne as createMultiTenancyPlugin,
1365
- Pe as createProtectSyncedMiddleware,
1366
- Y as createProvisioningHooks,
1367
- Ae as createRuntimeFallbackAdapter,
1368
- $e as createSubdomainMiddleware,
1369
- ve as createSyncHooks,
1370
- B as createTenantsOpenAPIRouter,
1371
- Ee as initMultiTenant,
1372
- Oe as mergeClientWithFallback,
1373
- Be as setupMultiTenancy,
1374
- me as validateTenantAccess,
1375
- ee as withRuntimeFallback,
1376
- Ie as withSystemResourceServerInheritance
1377
- };
849
+ return {
850
+ hooks: Q(e),
851
+ middleware: X(e),
852
+ app: $(e),
853
+ config: e,
854
+ wrapAdapters: (t, n) => G(t, {
855
+ controlPlaneTenantId: e.accessControl?.controlPlaneTenantId,
856
+ controlPlaneClientId: n?.controlPlaneClientId
857
+ })
858
+ };
859
+ }
860
+ //#endregion
861
+ export { m as createAccessControlHooks, q as createAccessControlMiddleware, K as createControlPlaneTenantMiddleware, g as createDatabaseHooks, Y as createDatabaseMiddleware, $ as createMultiTenancy, Q as createMultiTenancyHooks, X as createMultiTenancyMiddleware, ee as createMultiTenancyPlugin, N as createProtectSyncedMiddleware, v as createProvisioningHooks, H as createRuntimeFallbackAdapter, J as createSubdomainMiddleware, D as createSyncHooks, k as createTenantsOpenAPIRouter, Z as initMultiTenant, R as mergeClientWithFallback, te as setupMultiTenancy, h as validateTenantAccess, G as withRuntimeFallback, V as withSystemResourceServerInheritance };