@fonderie/workspaces 6.0.0 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -17,6 +17,7 @@ type WorkspacesEventKey = (typeof EVENT_KEYS)[keyof typeof EVENT_KEYS];
17
17
  interface IWorkspacesConfig {
18
18
  invitationTtl?: string;
19
19
  management?: 'owner-or-admin' | 'any-member';
20
+ managerRoles?: string[];
20
21
  personalWorkspace?: boolean;
21
22
  routes?: Partial<Record<WorkspaceRouteId, WorkspaceRouteOverride>>;
22
23
  }
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ type WorkspacesEventKey = (typeof EVENT_KEYS)[keyof typeof EVENT_KEYS];
17
17
  interface IWorkspacesConfig {
18
18
  invitationTtl?: string;
19
19
  management?: 'owner-or-admin' | 'any-member';
20
+ managerRoles?: string[];
20
21
  personalWorkspace?: boolean;
21
22
  routes?: Partial<Record<WorkspaceRouteId, WorkspaceRouteOverride>>;
22
23
  }
package/dist/index.js CHANGED
@@ -430,6 +430,7 @@ function withWorkspace(store, ctx, next) {
430
430
  // src/middlewares/require-manager.ts
431
431
  import { setApiResponse as setApiResponse2, HTTP as HTTP2 } from "@fonderie/core";
432
432
  function requireManager(store, config) {
433
+ const managerRoles = config.managerRoles ?? ["ADMIN"];
433
434
  return async (ctx, next) => {
434
435
  if (config.management === "any-member") return next();
435
436
  if (!ctx.user) {
@@ -448,8 +449,9 @@ function requireManager(store, config) {
448
449
  AND ruw.suspended = false
449
450
  AND r.is_system = true
450
451
  AND r.active = true
452
+ AND r.name = ANY($3)
451
453
  LIMIT 1`,
452
- [ctx.user.id, ctx.workspace.id]
454
+ [ctx.user.id, ctx.workspace.id, managerRoles]
453
455
  );
454
456
  if (!row) {
455
457
  return setApiResponse2(
@@ -1356,6 +1358,25 @@ function invitationController(store, ttl, bus) {
1356
1358
  return setApiResponse6(HTTP6.SERVER_ERROR, "SERVER_ERROR", "Default role not found");
1357
1359
  }
1358
1360
  }
1361
+ const explicitRoleIds = [...new Set(
1362
+ entries.map((e) => e["roleId"]).filter((r) => typeof r === "string")
1363
+ )];
1364
+ if (explicitRoleIds.length > 0) {
1365
+ const rows = await store.query(
1366
+ `SELECT id FROM fonderie_roles
1367
+ WHERE id = ANY($1) AND workspace_id = $2 AND is_system = false`,
1368
+ [explicitRoleIds, ctx.workspace.id]
1369
+ );
1370
+ const assignable = new Set(rows.map((r) => r.id));
1371
+ const bad = explicitRoleIds.find((id) => !assignable.has(id));
1372
+ if (bad) {
1373
+ return setApiResponse6(
1374
+ HTTP6.UNPROCESSABLE,
1375
+ "INVALID_ROLE",
1376
+ "Role is not assignable in this workspace."
1377
+ );
1378
+ }
1379
+ }
1359
1380
  const results = await Promise.all(
1360
1381
  entries.map(async (entry) => {
1361
1382
  const email2 = entry["email"];