@open-mercato/core 0.6.6-develop.5751.1.39143f001b → 0.6.6-develop.5754.1.c908b2af3f

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.
@@ -24,45 +24,40 @@ async function resolveAllowedWidgetIds(em, ctx, widgets) {
24
24
  allowedByUser = null;
25
25
  }
26
26
  }
27
- if (allowedByUser && allowedByUser.size === 0) {
28
- return Array.from(allowedByUser);
29
- }
30
- const userRoles = await findWithDecryption(
31
- em,
32
- UserRole,
33
- { user: ctx.userId, deletedAt: null },
34
- { populate: ["role"] },
35
- { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
36
- );
37
- const roleRecords = await em.find(DashboardRoleWidgets, {
38
- roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
39
- deletedAt: null
40
- });
41
- const byRole = /* @__PURE__ */ new Map();
42
- for (const record of roleRecords) {
43
- const role = String(record.roleId);
44
- if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue;
45
- if (record.tenantId && !ctx.tenantId) continue;
46
- if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue;
47
- if (record.organizationId && !ctx.organizationId) continue;
48
- const current = byRole.get(role);
49
- if (!current || specificity(record) > specificity(current)) {
50
- byRole.set(role, record);
51
- }
52
- }
53
- const allowedByRole = /* @__PURE__ */ new Set();
54
- for (const record of byRole.values()) {
55
- for (const id of record.widgetIdsJson) {
56
- if (allWidgetIds.includes(id)) allowedByRole.add(id);
57
- }
58
- }
59
27
  let baseSet;
60
28
  if (allowedByUser) {
61
29
  baseSet = allowedByUser;
62
- } else if (allowedByRole.size > 0) {
63
- baseSet = allowedByRole;
64
30
  } else {
65
- baseSet = new Set(allWidgetIds);
31
+ const userRoles = await findWithDecryption(
32
+ em,
33
+ UserRole,
34
+ { user: ctx.userId, deletedAt: null },
35
+ { populate: ["role"] },
36
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
37
+ );
38
+ const roleRecords = await em.find(DashboardRoleWidgets, {
39
+ roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
40
+ deletedAt: null
41
+ });
42
+ const byRole = /* @__PURE__ */ new Map();
43
+ for (const record of roleRecords) {
44
+ const role = String(record.roleId);
45
+ if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue;
46
+ if (record.tenantId && !ctx.tenantId) continue;
47
+ if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue;
48
+ if (record.organizationId && !ctx.organizationId) continue;
49
+ const current = byRole.get(role);
50
+ if (!current || specificity(record) > specificity(current)) {
51
+ byRole.set(role, record);
52
+ }
53
+ }
54
+ const allowedByRole = /* @__PURE__ */ new Set();
55
+ for (const record of byRole.values()) {
56
+ for (const id of record.widgetIdsJson) {
57
+ if (allWidgetIds.includes(id)) allowedByRole.add(id);
58
+ }
59
+ }
60
+ baseSet = allowedByRole.size > 0 ? allowedByRole : new Set(allWidgetIds);
66
61
  }
67
62
  if (baseSet.size === 0) return [];
68
63
  const filtered = widgets.filter((widget) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/dashboards/lib/access.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { DashboardRoleWidgets, DashboardUserWidgets } from '../data/entities'\nimport { UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { hasAllFeatures as userHasAllFeatures } from '@open-mercato/shared/security/features'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\ntype LoadedWidget = {\n metadata: {\n id: string\n features?: string[]\n }\n}\n\ntype AccessContext = {\n userId: string\n tenantId: string | null\n organizationId: string | null\n features: string[]\n isSuperAdmin: boolean\n}\n\nfunction specificity(record: DashboardRoleWidgets): number {\n let score = 0\n if (record.tenantId) score += 1\n if (record.organizationId) score += 2\n return score\n}\n\nexport async function resolveAllowedWidgetIds(\n em: EntityManager,\n ctx: AccessContext,\n widgets: LoadedWidget[],\n): Promise<string[]> {\n const allWidgetIds = widgets.map((w) => w.metadata.id)\n\n // Load user override (if any)\n const userRecord = await em.findOne(DashboardUserWidgets, {\n userId: ctx.userId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n })\n\n let allowedByUser: Set<string> | null = null\n if (userRecord) {\n if (userRecord.mode === 'override') {\n allowedByUser = new Set(userRecord.widgetIdsJson.filter((id) => allWidgetIds.includes(id)))\n } else {\n allowedByUser = null\n }\n }\n\n if (allowedByUser && allowedByUser.size === 0) {\n return Array.from(allowedByUser)\n }\n\n // Aggregate role-level settings\n const userRoles = await findWithDecryption(\n em,\n UserRole,\n { user: ctx.userId as any, deletedAt: null },\n { populate: ['role'] },\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n const roleRecords = await em.find(DashboardRoleWidgets, {\n roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },\n deletedAt: null,\n })\n\n const byRole = new Map<string, DashboardRoleWidgets>()\n for (const record of roleRecords) {\n const role = String(record.roleId)\n if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue\n if (record.tenantId && !ctx.tenantId) continue\n if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue\n if (record.organizationId && !ctx.organizationId) continue\n const current = byRole.get(role)\n if (!current || specificity(record) > specificity(current)) {\n byRole.set(role, record)\n }\n }\n\n const allowedByRole = new Set<string>()\n for (const record of byRole.values()) {\n for (const id of record.widgetIdsJson) {\n if (allWidgetIds.includes(id)) allowedByRole.add(id)\n }\n }\n\n let baseSet: Set<string>\n if (allowedByUser) {\n baseSet = allowedByUser\n } else if (allowedByRole.size > 0) {\n baseSet = allowedByRole\n } else {\n baseSet = new Set(allWidgetIds)\n }\n\n if (baseSet.size === 0) return []\n\n const filtered = widgets.filter((widget) => {\n if (!baseSet.has(widget.metadata.id)) return false\n if (ctx.isSuperAdmin) return true\n return userHasAllFeatures(ctx.features, widget.metadata.features ?? [])\n })\n\n return filtered.map((widget) => widget.metadata.id)\n}\n"],
5
- "mappings": "AACA,SAAS,sBAAsB,4BAA4B;AAC3D,SAAS,gBAAgB;AACzB,SAAS,kBAAkB,0BAA0B;AACrD,SAAS,0BAA0B;AAiBnC,SAAS,YAAY,QAAsC;AACzD,MAAI,QAAQ;AACZ,MAAI,OAAO,SAAU,UAAS;AAC9B,MAAI,OAAO,eAAgB,UAAS;AACpC,SAAO;AACT;AAEA,eAAsB,wBACpB,IACA,KACA,SACmB;AACnB,QAAM,eAAe,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;AAGrD,QAAM,aAAa,MAAM,GAAG,QAAQ,sBAAsB;AAAA,IACxD,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,WAAW;AAAA,EACb,CAAC;AAED,MAAI,gBAAoC;AACxC,MAAI,YAAY;AACd,QAAI,WAAW,SAAS,YAAY;AAClC,sBAAgB,IAAI,IAAI,WAAW,cAAc,OAAO,CAAC,OAAO,aAAa,SAAS,EAAE,CAAC,CAAC;AAAA,IAC5F,OAAO;AACL,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,iBAAiB,cAAc,SAAS,GAAG;AAC7C,WAAO,MAAM,KAAK,aAAa;AAAA,EACjC;AAGA,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,IACA;AAAA,IACA,EAAE,MAAM,IAAI,QAAe,WAAW,KAAK;AAAA,IAC3C,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,IACrB,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AAAA,EAC/D;AACA,QAAM,cAAc,MAAM,GAAG,KAAK,sBAAsB;AAAA,IACtD,QAAQ,EAAE,KAAK,UAAU,IAAI,CAAC,OAAO,OAAO,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;AAAA,IACrE,WAAW;AAAA,EACb,CAAC;AAED,QAAM,SAAS,oBAAI,IAAkC;AACrD,aAAW,UAAU,aAAa;AAChC,UAAM,OAAO,OAAO,OAAO,MAAM;AACjC,QAAI,OAAO,YAAY,IAAI,YAAY,OAAO,aAAa,IAAI,SAAU;AACzE,QAAI,OAAO,YAAY,CAAC,IAAI,SAAU;AACtC,QAAI,OAAO,kBAAkB,IAAI,kBAAkB,OAAO,mBAAmB,IAAI,eAAgB;AACjG,QAAI,OAAO,kBAAkB,CAAC,IAAI,eAAgB;AAClD,UAAM,UAAU,OAAO,IAAI,IAAI;AAC/B,QAAI,CAAC,WAAW,YAAY,MAAM,IAAI,YAAY,OAAO,GAAG;AAC1D,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,gBAAgB,oBAAI,IAAY;AACtC,aAAW,UAAU,OAAO,OAAO,GAAG;AACpC,eAAW,MAAM,OAAO,eAAe;AACrC,UAAI,aAAa,SAAS,EAAE,EAAG,eAAc,IAAI,EAAE;AAAA,IACrD;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,eAAe;AACjB,cAAU;AAAA,EACZ,WAAW,cAAc,OAAO,GAAG;AACjC,cAAU;AAAA,EACZ,OAAO;AACL,cAAU,IAAI,IAAI,YAAY;AAAA,EAChC;AAEA,MAAI,QAAQ,SAAS,EAAG,QAAO,CAAC;AAEhC,QAAM,WAAW,QAAQ,OAAO,CAAC,WAAW;AAC1C,QAAI,CAAC,QAAQ,IAAI,OAAO,SAAS,EAAE,EAAG,QAAO;AAC7C,QAAI,IAAI,aAAc,QAAO;AAC7B,WAAO,mBAAmB,IAAI,UAAU,OAAO,SAAS,YAAY,CAAC,CAAC;AAAA,EACxE,CAAC;AAED,SAAO,SAAS,IAAI,CAAC,WAAW,OAAO,SAAS,EAAE;AACpD;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { DashboardRoleWidgets, DashboardUserWidgets } from '../data/entities'\nimport { UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { hasAllFeatures as userHasAllFeatures } from '@open-mercato/shared/security/features'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\ntype LoadedWidget = {\n metadata: {\n id: string\n features?: string[]\n }\n}\n\ntype AccessContext = {\n userId: string\n tenantId: string | null\n organizationId: string | null\n features: string[]\n isSuperAdmin: boolean\n}\n\nfunction specificity(record: DashboardRoleWidgets): number {\n let score = 0\n if (record.tenantId) score += 1\n if (record.organizationId) score += 2\n return score\n}\n\nexport async function resolveAllowedWidgetIds(\n em: EntityManager,\n ctx: AccessContext,\n widgets: LoadedWidget[],\n): Promise<string[]> {\n const allWidgetIds = widgets.map((w) => w.metadata.id)\n\n // Load user override (if any)\n const userRecord = await em.findOne(DashboardUserWidgets, {\n userId: ctx.userId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n })\n\n let allowedByUser: Set<string> | null = null\n if (userRecord) {\n if (userRecord.mode === 'override') {\n allowedByUser = new Set(userRecord.widgetIdsJson.filter((id) => allWidgetIds.includes(id)))\n } else {\n allowedByUser = null\n }\n }\n\n let baseSet: Set<string>\n if (allowedByUser) {\n // A user override fully determines visibility, so role-level lookups would\n // be discarded \u2014 skip them entirely. An empty override is handled by the\n // shared `baseSet.size === 0` guard below.\n baseSet = allowedByUser\n } else {\n // No user override: aggregate role-level settings.\n const userRoles = await findWithDecryption(\n em,\n UserRole,\n { user: ctx.userId as any, deletedAt: null },\n { populate: ['role'] },\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n const roleRecords = await em.find(DashboardRoleWidgets, {\n roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },\n deletedAt: null,\n })\n\n const byRole = new Map<string, DashboardRoleWidgets>()\n for (const record of roleRecords) {\n const role = String(record.roleId)\n if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue\n if (record.tenantId && !ctx.tenantId) continue\n if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue\n if (record.organizationId && !ctx.organizationId) continue\n const current = byRole.get(role)\n if (!current || specificity(record) > specificity(current)) {\n byRole.set(role, record)\n }\n }\n\n const allowedByRole = new Set<string>()\n for (const record of byRole.values()) {\n for (const id of record.widgetIdsJson) {\n if (allWidgetIds.includes(id)) allowedByRole.add(id)\n }\n }\n\n baseSet = allowedByRole.size > 0 ? allowedByRole : new Set(allWidgetIds)\n }\n\n if (baseSet.size === 0) return []\n\n const filtered = widgets.filter((widget) => {\n if (!baseSet.has(widget.metadata.id)) return false\n if (ctx.isSuperAdmin) return true\n return userHasAllFeatures(ctx.features, widget.metadata.features ?? [])\n })\n\n return filtered.map((widget) => widget.metadata.id)\n}\n"],
5
+ "mappings": "AACA,SAAS,sBAAsB,4BAA4B;AAC3D,SAAS,gBAAgB;AACzB,SAAS,kBAAkB,0BAA0B;AACrD,SAAS,0BAA0B;AAiBnC,SAAS,YAAY,QAAsC;AACzD,MAAI,QAAQ;AACZ,MAAI,OAAO,SAAU,UAAS;AAC9B,MAAI,OAAO,eAAgB,UAAS;AACpC,SAAO;AACT;AAEA,eAAsB,wBACpB,IACA,KACA,SACmB;AACnB,QAAM,eAAe,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;AAGrD,QAAM,aAAa,MAAM,GAAG,QAAQ,sBAAsB;AAAA,IACxD,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,WAAW;AAAA,EACb,CAAC;AAED,MAAI,gBAAoC;AACxC,MAAI,YAAY;AACd,QAAI,WAAW,SAAS,YAAY;AAClC,sBAAgB,IAAI,IAAI,WAAW,cAAc,OAAO,CAAC,OAAO,aAAa,SAAS,EAAE,CAAC,CAAC;AAAA,IAC5F,OAAO;AACL,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,eAAe;AAIjB,cAAU;AAAA,EACZ,OAAO;AAEL,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,MACA,EAAE,MAAM,IAAI,QAAe,WAAW,KAAK;AAAA,MAC3C,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,MACrB,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AAAA,IAC/D;AACA,UAAM,cAAc,MAAM,GAAG,KAAK,sBAAsB;AAAA,MACtD,QAAQ,EAAE,KAAK,UAAU,IAAI,CAAC,OAAO,OAAO,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;AAAA,MACrE,WAAW;AAAA,IACb,CAAC;AAED,UAAM,SAAS,oBAAI,IAAkC;AACrD,eAAW,UAAU,aAAa;AAChC,YAAM,OAAO,OAAO,OAAO,MAAM;AACjC,UAAI,OAAO,YAAY,IAAI,YAAY,OAAO,aAAa,IAAI,SAAU;AACzE,UAAI,OAAO,YAAY,CAAC,IAAI,SAAU;AACtC,UAAI,OAAO,kBAAkB,IAAI,kBAAkB,OAAO,mBAAmB,IAAI,eAAgB;AACjG,UAAI,OAAO,kBAAkB,CAAC,IAAI,eAAgB;AAClD,YAAM,UAAU,OAAO,IAAI,IAAI;AAC/B,UAAI,CAAC,WAAW,YAAY,MAAM,IAAI,YAAY,OAAO,GAAG;AAC1D,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB;AAAA,IACF;AAEA,UAAM,gBAAgB,oBAAI,IAAY;AACtC,eAAW,UAAU,OAAO,OAAO,GAAG;AACpC,iBAAW,MAAM,OAAO,eAAe;AACrC,YAAI,aAAa,SAAS,EAAE,EAAG,eAAc,IAAI,EAAE;AAAA,MACrD;AAAA,IACF;AAEA,cAAU,cAAc,OAAO,IAAI,gBAAgB,IAAI,IAAI,YAAY;AAAA,EACzE;AAEA,MAAI,QAAQ,SAAS,EAAG,QAAO,CAAC;AAEhC,QAAM,WAAW,QAAQ,OAAO,CAAC,WAAW;AAC1C,QAAI,CAAC,QAAQ,IAAI,OAAO,SAAS,EAAE,EAAG,QAAO;AAC7C,QAAI,IAAI,aAAc,QAAO;AAC7B,WAAO,mBAAmB,IAAI,UAAU,OAAO,SAAS,YAAY,CAAC,CAAC;AAAA,EACxE,CAAC;AAED,SAAO,SAAS,IAAI,CAAC,WAAW,OAAO,SAAS,EAAE;AACpD;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.5751.1.39143f001b",
3
+ "version": "0.6.6-develop.5754.1.c908b2af3f",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -245,16 +245,16 @@
245
245
  "zod": "^4.4.3"
246
246
  },
247
247
  "peerDependencies": {
248
- "@open-mercato/ai-assistant": "0.6.6-develop.5751.1.39143f001b",
249
- "@open-mercato/shared": "0.6.6-develop.5751.1.39143f001b",
250
- "@open-mercato/ui": "0.6.6-develop.5751.1.39143f001b",
248
+ "@open-mercato/ai-assistant": "0.6.6-develop.5754.1.c908b2af3f",
249
+ "@open-mercato/shared": "0.6.6-develop.5754.1.c908b2af3f",
250
+ "@open-mercato/ui": "0.6.6-develop.5754.1.c908b2af3f",
251
251
  "react": "^19.0.0",
252
252
  "react-dom": "^19.0.0"
253
253
  },
254
254
  "devDependencies": {
255
- "@open-mercato/ai-assistant": "0.6.6-develop.5751.1.39143f001b",
256
- "@open-mercato/shared": "0.6.6-develop.5751.1.39143f001b",
257
- "@open-mercato/ui": "0.6.6-develop.5751.1.39143f001b",
255
+ "@open-mercato/ai-assistant": "0.6.6-develop.5754.1.c908b2af3f",
256
+ "@open-mercato/shared": "0.6.6-develop.5754.1.c908b2af3f",
257
+ "@open-mercato/ui": "0.6.6-develop.5754.1.c908b2af3f",
258
258
  "@testing-library/dom": "^10.4.1",
259
259
  "@testing-library/jest-dom": "^6.9.1",
260
260
  "@testing-library/react": "^16.3.1",
@@ -50,50 +50,47 @@ export async function resolveAllowedWidgetIds(
50
50
  }
51
51
  }
52
52
 
53
- if (allowedByUser && allowedByUser.size === 0) {
54
- return Array.from(allowedByUser)
55
- }
56
-
57
- // Aggregate role-level settings
58
- const userRoles = await findWithDecryption(
59
- em,
60
- UserRole,
61
- { user: ctx.userId as any, deletedAt: null },
62
- { populate: ['role'] },
63
- { tenantId: ctx.tenantId, organizationId: ctx.organizationId },
64
- )
65
- const roleRecords = await em.find(DashboardRoleWidgets, {
66
- roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
67
- deletedAt: null,
68
- })
53
+ let baseSet: Set<string>
54
+ if (allowedByUser) {
55
+ // A user override fully determines visibility, so role-level lookups would
56
+ // be discarded — skip them entirely. An empty override is handled by the
57
+ // shared `baseSet.size === 0` guard below.
58
+ baseSet = allowedByUser
59
+ } else {
60
+ // No user override: aggregate role-level settings.
61
+ const userRoles = await findWithDecryption(
62
+ em,
63
+ UserRole,
64
+ { user: ctx.userId as any, deletedAt: null },
65
+ { populate: ['role'] },
66
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId },
67
+ )
68
+ const roleRecords = await em.find(DashboardRoleWidgets, {
69
+ roleId: { $in: userRoles.map((ur) => String(ur.role?.id || ur.role)) },
70
+ deletedAt: null,
71
+ })
69
72
 
70
- const byRole = new Map<string, DashboardRoleWidgets>()
71
- for (const record of roleRecords) {
72
- const role = String(record.roleId)
73
- if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue
74
- if (record.tenantId && !ctx.tenantId) continue
75
- if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue
76
- if (record.organizationId && !ctx.organizationId) continue
77
- const current = byRole.get(role)
78
- if (!current || specificity(record) > specificity(current)) {
79
- byRole.set(role, record)
73
+ const byRole = new Map<string, DashboardRoleWidgets>()
74
+ for (const record of roleRecords) {
75
+ const role = String(record.roleId)
76
+ if (record.tenantId && ctx.tenantId && record.tenantId !== ctx.tenantId) continue
77
+ if (record.tenantId && !ctx.tenantId) continue
78
+ if (record.organizationId && ctx.organizationId && record.organizationId !== ctx.organizationId) continue
79
+ if (record.organizationId && !ctx.organizationId) continue
80
+ const current = byRole.get(role)
81
+ if (!current || specificity(record) > specificity(current)) {
82
+ byRole.set(role, record)
83
+ }
80
84
  }
81
- }
82
85
 
83
- const allowedByRole = new Set<string>()
84
- for (const record of byRole.values()) {
85
- for (const id of record.widgetIdsJson) {
86
- if (allWidgetIds.includes(id)) allowedByRole.add(id)
86
+ const allowedByRole = new Set<string>()
87
+ for (const record of byRole.values()) {
88
+ for (const id of record.widgetIdsJson) {
89
+ if (allWidgetIds.includes(id)) allowedByRole.add(id)
90
+ }
87
91
  }
88
- }
89
92
 
90
- let baseSet: Set<string>
91
- if (allowedByUser) {
92
- baseSet = allowedByUser
93
- } else if (allowedByRole.size > 0) {
94
- baseSet = allowedByRole
95
- } else {
96
- baseSet = new Set(allWidgetIds)
93
+ baseSet = allowedByRole.size > 0 ? allowedByRole : new Set(allWidgetIds)
97
94
  }
98
95
 
99
96
  if (baseSet.size === 0) return []