@open-mercato/core 0.6.6-develop.6330.1.a261878aa8 → 0.6.6-develop.6332.1.6e73f0f55b

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 (253) hide show
  1. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +3 -0
  2. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  3. package/dist/modules/auth/api/logout.js +2 -3
  4. package/dist/modules/auth/api/logout.js.map +2 -2
  5. package/dist/modules/auth/api/roles/acl/route.js +2 -2
  6. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  7. package/dist/modules/auth/api/session/refresh.js +5 -6
  8. package/dist/modules/auth/api/session/refresh.js.map +2 -2
  9. package/dist/modules/auth/api/users/acl/route.js +2 -2
  10. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  11. package/dist/modules/auth/backend/roles/[id]/edit/page.js +12 -0
  12. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  13. package/dist/modules/auth/backend/users/[id]/edit/page.js +12 -0
  14. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  15. package/dist/modules/auth/data/entities.js +2 -2
  16. package/dist/modules/auth/data/entities.js.map +2 -2
  17. package/dist/modules/auth/lib/requestRedirect.js +31 -3
  18. package/dist/modules/auth/lib/requestRedirect.js.map +2 -2
  19. package/dist/modules/business_rules/api/rules/route.js +3 -3
  20. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  21. package/dist/modules/business_rules/api/sets/route.js +3 -3
  22. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  23. package/dist/modules/business_rules/backend/rules/[id]/page.js +12 -1
  24. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
  25. package/dist/modules/business_rules/backend/sets/[id]/page.js +12 -1
  26. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  27. package/dist/modules/catalog/api/product-media/route.js.map +2 -2
  28. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +12 -0
  29. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  30. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
  31. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  32. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +12 -1
  33. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  34. package/dist/modules/catalog/components/PriceKindSettings.js +13 -3
  35. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  36. package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
  37. package/dist/modules/currencies/backend/currencies/[id]/page.js +15 -3
  38. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  39. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  40. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  41. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +12 -1
  42. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  43. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -2
  44. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  45. package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -3
  46. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  47. package/dist/modules/customer_accounts/api/admin/users/[id].js +3 -3
  48. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  49. package/dist/modules/customers/api/addresses/route.js +4 -2
  50. package/dist/modules/customers/api/addresses/route.js.map +2 -2
  51. package/dist/modules/customers/api/tags/route.js +8 -3
  52. package/dist/modules/customers/api/tags/route.js.map +2 -2
  53. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +13 -2
  54. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  55. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +24 -9
  56. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
  57. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +53 -23
  58. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
  59. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +13 -3
  60. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +2 -2
  61. package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -2
  62. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  63. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +13 -2
  64. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  65. package/dist/modules/customers/commands/interactions.js +5 -5
  66. package/dist/modules/customers/commands/interactions.js.map +2 -2
  67. package/dist/modules/customers/commands/pipeline-stages.js +24 -2
  68. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  69. package/dist/modules/customers/commands/pipelines.js +24 -2
  70. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  71. package/dist/modules/customers/components/detail/AddressesSection.js +46 -29
  72. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  73. package/dist/modules/customers/components/detail/DealForm.js +5 -1
  74. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  75. package/dist/modules/customers/components/detail/notesAdapter.js +25 -18
  76. package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
  77. package/dist/modules/data_sync/api/schedules/[id]/route.js +38 -19
  78. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  79. package/dist/modules/data_sync/api/schedules/route.js +1 -1
  80. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  81. package/dist/modules/data_sync/backend/data-sync/page.js +32 -15
  82. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  83. package/dist/modules/data_sync/lib/sync-schedule-service.js +19 -5
  84. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  85. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
  86. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  87. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +3 -3
  88. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  89. package/dist/modules/dictionaries/components/DictionariesManager.js +12 -1
  90. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  91. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  92. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +12 -0
  93. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  94. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +12 -0
  95. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  96. package/dist/modules/entities/api/entities.js +2 -2
  97. package/dist/modules/entities/api/entities.js.map +2 -2
  98. package/dist/modules/entities/api/records.js +7 -5
  99. package/dist/modules/entities/api/records.js.map +2 -2
  100. package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
  101. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  102. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  103. package/dist/modules/feature_toggles/data/entities.js +1 -1
  104. package/dist/modules/feature_toggles/data/entities.js.map +2 -2
  105. package/dist/modules/feature_toggles/data/validators.js +2 -1
  106. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  107. package/dist/modules/feature_toggles/lib/queries.js +2 -1
  108. package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
  109. package/dist/modules/inbox_ops/api/settings/route.js +2 -2
  110. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  111. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +12 -1
  112. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  113. package/dist/modules/resources/backend/resources/resources/[id]/page.js +12 -1
  114. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  115. package/dist/modules/resources/components/detail/notesAdapter.js +25 -18
  116. package/dist/modules/resources/components/detail/notesAdapter.js.map +2 -2
  117. package/dist/modules/sales/backend/sales/documents/[id]/page.js +14 -1
  118. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  119. package/dist/modules/sales/commands/documents.js +11 -10
  120. package/dist/modules/sales/commands/documents.js.map +2 -2
  121. package/dist/modules/sales/commands/payments.js +6 -1
  122. package/dist/modules/sales/commands/payments.js.map +2 -2
  123. package/dist/modules/sales/commands/returns.js +3 -3
  124. package/dist/modules/sales/commands/returns.js.map +2 -2
  125. package/dist/modules/sales/commands/shared.js +3 -3
  126. package/dist/modules/sales/commands/shared.js.map +2 -2
  127. package/dist/modules/sales/commands/shipments.js +6 -1
  128. package/dist/modules/sales/commands/shipments.js.map +2 -2
  129. package/dist/modules/sales/components/documents/PaymentDialog.js +6 -3
  130. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  131. package/dist/modules/sales/components/documents/PaymentsSection.js +7 -3
  132. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  133. package/dist/modules/sales/components/documents/ShipmentDialog.js +6 -3
  134. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  135. package/dist/modules/sales/components/documents/ShipmentsSection.js +7 -3
  136. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  137. package/dist/modules/sales/di.js +39 -3
  138. package/dist/modules/sales/di.js.map +2 -2
  139. package/dist/modules/sales/setup.js +2 -0
  140. package/dist/modules/sales/setup.js.map +2 -2
  141. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +12 -1
  142. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  143. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +12 -1
  144. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  145. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +12 -1
  146. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  147. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -1
  148. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  149. package/dist/modules/staff/commands/job-histories.js +3 -3
  150. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  151. package/dist/modules/staff/components/detail/addressesAdapter.js +33 -24
  152. package/dist/modules/staff/components/detail/addressesAdapter.js.map +2 -2
  153. package/dist/modules/staff/components/detail/notesAdapter.js +25 -18
  154. package/dist/modules/staff/components/detail/notesAdapter.js.map +2 -2
  155. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +37 -0
  156. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  157. package/dist/modules/translations/components/TranslationManager.js +7 -1
  158. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  159. package/dist/modules/workflows/api/definitions/[id]/route.js +3 -3
  160. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  161. package/dist/modules/workflows/backend/definitions/[id]/page.js +12 -1
  162. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  163. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +11 -1
  164. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  165. package/package.json +7 -7
  166. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +3 -0
  167. package/src/modules/auth/api/logout.ts +2 -3
  168. package/src/modules/auth/api/roles/acl/route.ts +2 -2
  169. package/src/modules/auth/api/session/refresh.ts +5 -6
  170. package/src/modules/auth/api/users/acl/route.ts +2 -2
  171. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +17 -0
  172. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -0
  173. package/src/modules/auth/data/entities.ts +2 -2
  174. package/src/modules/auth/lib/requestRedirect.ts +44 -2
  175. package/src/modules/business_rules/api/rules/route.ts +3 -3
  176. package/src/modules/business_rules/api/sets/route.ts +3 -3
  177. package/src/modules/business_rules/backend/rules/[id]/page.tsx +17 -1
  178. package/src/modules/business_rules/backend/sets/[id]/page.tsx +18 -1
  179. package/src/modules/catalog/api/product-media/route.ts +4 -0
  180. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +17 -0
  181. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -0
  182. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +16 -1
  183. package/src/modules/catalog/components/PriceKindSettings.tsx +15 -7
  184. package/src/modules/catalog/lib/bulkDelete.ts +6 -0
  185. package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -3
  186. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  187. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +17 -1
  188. package/src/modules/currencies/backend/exchange-rates/page.tsx +3 -2
  189. package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -3
  190. package/src/modules/customer_accounts/api/admin/users/[id].ts +3 -3
  191. package/src/modules/customers/api/addresses/route.ts +2 -0
  192. package/src/modules/customers/api/tags/route.ts +6 -1
  193. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +19 -2
  194. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +29 -8
  195. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +47 -20
  196. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +13 -3
  197. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
  198. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -2
  199. package/src/modules/customers/commands/interactions.ts +5 -5
  200. package/src/modules/customers/commands/pipeline-stages.ts +26 -2
  201. package/src/modules/customers/commands/pipelines.ts +26 -2
  202. package/src/modules/customers/components/detail/AddressesSection.tsx +50 -28
  203. package/src/modules/customers/components/detail/DealForm.tsx +12 -0
  204. package/src/modules/customers/components/detail/notesAdapter.ts +29 -18
  205. package/src/modules/customers/i18n/de.json +2 -0
  206. package/src/modules/customers/i18n/en.json +2 -0
  207. package/src/modules/customers/i18n/es.json +2 -0
  208. package/src/modules/customers/i18n/pl.json +2 -0
  209. package/src/modules/data_sync/api/schedules/[id]/route.ts +38 -20
  210. package/src/modules/data_sync/api/schedules/route.ts +1 -1
  211. package/src/modules/data_sync/backend/data-sync/page.tsx +32 -15
  212. package/src/modules/data_sync/lib/sync-schedule-service.ts +30 -5
  213. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
  214. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -3
  215. package/src/modules/dictionaries/components/DictionariesManager.tsx +21 -1
  216. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -0
  217. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -0
  218. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +17 -0
  219. package/src/modules/entities/api/entities.ts +2 -2
  220. package/src/modules/entities/api/records.ts +7 -5
  221. package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
  222. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +12 -0
  223. package/src/modules/feature_toggles/data/entities.ts +1 -1
  224. package/src/modules/feature_toggles/data/validators.ts +1 -0
  225. package/src/modules/feature_toggles/lib/queries.ts +1 -0
  226. package/src/modules/inbox_ops/api/settings/route.ts +2 -2
  227. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +17 -1
  228. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +17 -1
  229. package/src/modules/resources/components/detail/notesAdapter.ts +29 -18
  230. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +17 -1
  231. package/src/modules/sales/commands/documents.ts +11 -10
  232. package/src/modules/sales/commands/payments.ts +11 -0
  233. package/src/modules/sales/commands/returns.ts +3 -3
  234. package/src/modules/sales/commands/shared.ts +10 -4
  235. package/src/modules/sales/commands/shipments.ts +14 -0
  236. package/src/modules/sales/components/documents/PaymentDialog.tsx +7 -3
  237. package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -3
  238. package/src/modules/sales/components/documents/ShipmentDialog.tsx +7 -3
  239. package/src/modules/sales/components/documents/ShipmentsSection.tsx +8 -3
  240. package/src/modules/sales/di.ts +68 -9
  241. package/src/modules/sales/setup.ts +2 -0
  242. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +17 -1
  243. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +17 -1
  244. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +17 -1
  245. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -1
  246. package/src/modules/staff/commands/job-histories.ts +3 -3
  247. package/src/modules/staff/components/detail/addressesAdapter.ts +40 -23
  248. package/src/modules/staff/components/detail/notesAdapter.ts +28 -18
  249. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +74 -0
  250. package/src/modules/translations/components/TranslationManager.tsx +14 -1
  251. package/src/modules/workflows/api/definitions/[id]/route.ts +3 -3
  252. package/src/modules/workflows/backend/definitions/[id]/page.tsx +18 -1
  253. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +19 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/auth/api/users/acl/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { logCrudAccess } from '@open-mercato/shared/lib/crud/factory'\nimport { forbidden, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { UserAcl } from '@open-mercato/core/modules/auth/data/entities'\nimport {\n assertActorCanAccessUserTarget,\n assertActorCanGrantAcl,\n assertActorCanModifySuperAdminUserTarget,\n normalizeGrantFeatureList,\n} from '@open-mercato/core/modules/auth/lib/grantChecks'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport type { EntityManager } from '@mikro-orm/postgresql'\n\nconst getSchema = z.object({ userId: z.string().uuid() })\nconst putSchema = z.object({\n userId: z.string().uuid(),\n isSuperAdmin: z.boolean().optional(),\n features: z.array(z.string()).optional(),\n organizations: z.array(z.string()).nullable().optional(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['auth.acl.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['auth.acl.manage'] },\n}\n\nconst userAclResponseSchema = z.object({\n hasCustomAcl: z.boolean(),\n isSuperAdmin: z.boolean(),\n features: z.array(z.string()),\n organizations: z.array(z.string()).nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst userAclUpdateResponseSchema = z.object({\n ok: z.literal(true),\n sanitized: z.boolean(),\n})\n\nconst userAclErrorSchema = z.object({ error: z.string() })\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const url = new URL(req.url)\n const parsed = getSchema.safeParse({ userId: url.searchParams.get('userId') })\n if (!parsed.success) return NextResponse.json({ error: 'Invalid input' }, { status: 400 })\n const container = await createRequestContainer()\n const em = container.resolve('em') as any\n const rbacService = container.resolve('rbacService') as any\n const actorAcl = auth.sub\n ? await rbacService.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n : null\n if (!actorAcl?.isSuperAdmin && auth.sub) {\n try {\n await assertActorCanModifySuperAdminUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n await assertActorCanAccessUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n }\n const acl = await em.findOne(UserAcl, { user: parsed.data.userId as any, tenantId: auth.tenantId as any })\n const response = acl\n ? {\n hasCustomAcl: true,\n isSuperAdmin: !!acl.isSuperAdmin,\n features: Array.isArray(acl.featuresJson) ? acl.featuresJson : [],\n organizations: Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null,\n updatedAt: acl.updatedAt instanceof Date ? acl.updatedAt.toISOString() : null,\n }\n : { hasCustomAcl: false, isSuperAdmin: false, features: [], organizations: null, updatedAt: null }\n\n await logCrudAccess({\n container,\n auth,\n request: req,\n items: [{ id: parsed.data.userId, ...response }],\n idField: 'id',\n resourceKind: 'auth.user_acl',\n organizationId: auth.orgId ?? null,\n tenantId: auth.tenantId ?? null,\n query: { userId: parsed.data.userId },\n accessType: 'read:item',\n })\n\n return NextResponse.json(response)\n}\n\nexport async function PUT(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const body = await req.json().catch(() => ({}))\n const parsed = putSchema.safeParse(body)\n if (!parsed.success) return NextResponse.json({ error: 'Invalid input' }, { status: 400 })\n const container = await createRequestContainer()\n const em = container.resolve('em') as any\n const rbacService = container.resolve('rbacService') as any\n\n const actorAcl = auth.sub\n ? await rbacService.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n : null\n const actorIsSuperAdmin = !!actorAcl?.isSuperAdmin\n\n if (!actorIsSuperAdmin && auth.sub) {\n try {\n await assertActorCanModifySuperAdminUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n await assertActorCanAccessUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n }\n\n const requestedFeatures = normalizeGrantFeatureList(parsed.data.features)\n const organizations = normalizeOrganizations(parsed.data.organizations)\n\n let acl = await em.findOne(UserAcl, { user: parsed.data.userId as any, tenantId: auth.tenantId as any })\n // Optimistic lock: refuse a stale per-user ACL overwrite so concurrent edits\n // cannot silently clobber each other (#2055). Strictly additive \u2014 a no-op when\n // the client sends no expected-version header; skipped when no ACL row exists.\n if (acl) {\n try {\n enforceCommandOptimisticLock({\n resourceKind: 'auth.user_acl',\n resourceId: acl.id,\n current: acl.updatedAt ?? null,\n request: req,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n }\n const existingIsSuperAdmin = acl ? !!acl.isSuperAdmin : false\n const existingFeatures = acl ? normalizeGrantFeatureList(acl.featuresJson) : []\n\n const requestedIsSuperAdmin = parsed.data.isSuperAdmin ?? false\n\n try {\n await assertActorCanGrantAcl({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n isSuperAdmin: requestedIsSuperAdmin,\n features: requestedFeatures,\n organizations,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n\n const effectiveFeatures = actorIsSuperAdmin\n ? requestedFeatures\n : sanitizeTenantFeatures(requestedFeatures)\n\n let effectiveIsSuperAdmin = requestedIsSuperAdmin\n\n if (!actorIsSuperAdmin) {\n if (requestedIsSuperAdmin && !existingIsSuperAdmin) {\n throw forbidden('Only super administrators can grant super admin access.')\n }\n if (existingIsSuperAdmin && requestedIsSuperAdmin === false) {\n effectiveIsSuperAdmin = false\n } else {\n effectiveIsSuperAdmin = existingIsSuperAdmin\n }\n }\n\n const hasCustomAcl = effectiveIsSuperAdmin || effectiveFeatures.length > 0\n\n // Persist the ACL mutation inside a transaction so the per-user permission\n // write (or removal) commits atomically (proper ACL-edit transaction handling).\n if (!hasCustomAcl) {\n if (acl) {\n const aclToRemove = acl\n await withAtomicFlush(em, [() => em.remove(aclToRemove)], { transaction: true })\n }\n } else {\n if (!acl) {\n acl = em.create(UserAcl, { user: parsed.data.userId as any, tenantId: auth.tenantId as any })\n }\n const aclRecord = acl as any\n await withAtomicFlush(\n em,\n [\n () => {\n aclRecord.isSuperAdmin = effectiveIsSuperAdmin\n aclRecord.featuresJson = effectiveFeatures\n aclRecord.organizationsJson = organizations\n em.persist(aclRecord)\n },\n ],\n { transaction: true },\n )\n }\n\n // Invalidate cache for this user\n await rbacService.invalidateUserCache(parsed.data.userId)\n try {\n const cache = container.resolve('cache') as any\n if (cache) await cache.deleteByTags([`rbac:user:${parsed.data.userId}`])\n } catch {}\n\n return NextResponse.json({\n ok: true,\n sanitized: !actorIsSuperAdmin && (hasRestrictedChanges(requestedFeatures, effectiveFeatures, existingFeatures) || requestedIsSuperAdmin !== effectiveIsSuperAdmin),\n })\n}\n\nfunction normalizeOrganizations(organizations: unknown): string[] | null {\n if (!Array.isArray(organizations)) return null\n return normalizeGrantFeatureList(organizations)\n}\n\nfunction sanitizeTenantFeatures(features: string[]): string[] {\n return features.filter((feature) => !isTenantRestrictedFeature(feature))\n}\n\nfunction isTenantRestrictedFeature(feature: string): boolean {\n if (feature === '*' || feature === 'directory.*') return true\n if (feature.startsWith('directory.tenants')) return true\n return false\n}\n\nfunction hasRestrictedChanges(requested: string[], effective: string[], existing: string[]): boolean {\n if (requested.length === effective.length) return false\n const effectiveSet = new Set(effective)\n const existingSet = new Set(existing)\n // If the effective set matches existing, we only trimmed restricted duplicates and should not report\n if (effectiveSet.size === existingSet.size) {\n let identical = true\n for (const value of effectiveSet) {\n if (!existingSet.has(value)) {\n identical = false\n break\n }\n }\n if (identical) return false\n }\n return true\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'User ACL management',\n methods: {\n GET: {\n summary: 'Fetch user ACL',\n description: 'Returns custom ACL overrides for a user within the current tenant, if any.',\n query: getSchema,\n responses: [\n { status: 200, description: 'User ACL entry', schema: userAclResponseSchema },\n { status: 400, description: 'Invalid user id', schema: userAclErrorSchema },\n { status: 401, description: 'Unauthorized', schema: userAclErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update user ACL',\n description: 'Configures per-user ACL overrides, including super admin access, feature list, and organization scope.',\n requestBody: {\n contentType: 'application/json',\n schema: putSchema,\n },\n responses: [\n { status: 200, description: 'User ACL updated', schema: userAclUpdateResponseSchema },\n { status: 400, description: 'Invalid payload', schema: userAclErrorSchema },\n { status: 401, description: 'Unauthorized', schema: userAclErrorSchema },\n { status: 403, description: 'Insufficient privileges to modify ACL', schema: userAclErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { logCrudAccess } from '@open-mercato/shared/lib/crud/factory'\nimport { forbidden, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { UserAcl } from '@open-mercato/core/modules/auth/data/entities'\nimport {\n assertActorCanAccessUserTarget,\n assertActorCanGrantAcl,\n assertActorCanModifySuperAdminUserTarget,\n normalizeGrantFeatureList,\n} from '@open-mercato/core/modules/auth/lib/grantChecks'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport type { EntityManager } from '@mikro-orm/postgresql'\n\nconst getSchema = z.object({ userId: z.string().uuid() })\nconst putSchema = z.object({\n userId: z.string().uuid(),\n isSuperAdmin: z.boolean().optional(),\n features: z.array(z.string()).optional(),\n organizations: z.array(z.string()).nullable().optional(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['auth.acl.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['auth.acl.manage'] },\n}\n\nconst userAclResponseSchema = z.object({\n hasCustomAcl: z.boolean(),\n isSuperAdmin: z.boolean(),\n features: z.array(z.string()),\n organizations: z.array(z.string()).nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst userAclUpdateResponseSchema = z.object({\n ok: z.literal(true),\n sanitized: z.boolean(),\n})\n\nconst userAclErrorSchema = z.object({ error: z.string() })\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const url = new URL(req.url)\n const parsed = getSchema.safeParse({ userId: url.searchParams.get('userId') })\n if (!parsed.success) return NextResponse.json({ error: 'Invalid input' }, { status: 400 })\n const container = await createRequestContainer()\n const em = container.resolve('em') as any\n const rbacService = container.resolve('rbacService') as any\n const actorAcl = auth.sub\n ? await rbacService.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n : null\n if (!actorAcl?.isSuperAdmin && auth.sub) {\n try {\n await assertActorCanModifySuperAdminUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n await assertActorCanAccessUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n }\n const acl = await em.findOne(UserAcl, { user: parsed.data.userId as any, tenantId: auth.tenantId as any })\n const response = acl\n ? {\n hasCustomAcl: true,\n isSuperAdmin: !!acl.isSuperAdmin,\n features: Array.isArray(acl.featuresJson) ? acl.featuresJson : [],\n organizations: Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null,\n updatedAt: acl.updatedAt instanceof Date ? acl.updatedAt.toISOString() : null,\n }\n : { hasCustomAcl: false, isSuperAdmin: false, features: [], organizations: null, updatedAt: null }\n\n await logCrudAccess({\n container,\n auth,\n request: req,\n items: [{ id: parsed.data.userId, ...response }],\n idField: 'id',\n resourceKind: 'auth.user_acl',\n organizationId: auth.orgId ?? null,\n tenantId: auth.tenantId ?? null,\n query: { userId: parsed.data.userId },\n accessType: 'read:item',\n })\n\n return NextResponse.json(response)\n}\n\nexport async function PUT(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const body = await req.json().catch(() => ({}))\n const parsed = putSchema.safeParse(body)\n if (!parsed.success) return NextResponse.json({ error: 'Invalid input' }, { status: 400 })\n const container = await createRequestContainer()\n const em = container.resolve('em') as any\n const rbacService = container.resolve('rbacService') as any\n\n const actorAcl = auth.sub\n ? await rbacService.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n : null\n const actorIsSuperAdmin = !!actorAcl?.isSuperAdmin\n\n if (!actorIsSuperAdmin && auth.sub) {\n try {\n await assertActorCanModifySuperAdminUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n await assertActorCanAccessUserTarget({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n targetUserId: parsed.data.userId,\n actorIsSuperAdmin: false,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n }\n\n const requestedFeatures = normalizeGrantFeatureList(parsed.data.features)\n const organizations = normalizeOrganizations(parsed.data.organizations)\n\n let acl = await em.findOne(UserAcl, { user: parsed.data.userId as any, tenantId: auth.tenantId as any })\n // Optimistic lock: refuse a stale per-user ACL overwrite so concurrent edits\n // cannot silently clobber each other (#2055). Strictly additive \u2014 a no-op when\n // the client sends no expected-version header; skipped when no ACL row exists.\n if (acl) {\n try {\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: 'auth.user_acl',\n resourceId: acl.id,\n current: acl.updatedAt ?? null,\n request: req,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n }\n const existingIsSuperAdmin = acl ? !!acl.isSuperAdmin : false\n const existingFeatures = acl ? normalizeGrantFeatureList(acl.featuresJson) : []\n\n const requestedIsSuperAdmin = parsed.data.isSuperAdmin ?? false\n\n try {\n await assertActorCanGrantAcl({\n em: em as EntityManager,\n rbacService: rbacService as RbacService,\n actorUserId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n isSuperAdmin: requestedIsSuperAdmin,\n features: requestedFeatures,\n organizations,\n })\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n\n const effectiveFeatures = actorIsSuperAdmin\n ? requestedFeatures\n : sanitizeTenantFeatures(requestedFeatures)\n\n let effectiveIsSuperAdmin = requestedIsSuperAdmin\n\n if (!actorIsSuperAdmin) {\n if (requestedIsSuperAdmin && !existingIsSuperAdmin) {\n throw forbidden('Only super administrators can grant super admin access.')\n }\n if (existingIsSuperAdmin && requestedIsSuperAdmin === false) {\n effectiveIsSuperAdmin = false\n } else {\n effectiveIsSuperAdmin = existingIsSuperAdmin\n }\n }\n\n const hasCustomAcl = effectiveIsSuperAdmin || effectiveFeatures.length > 0\n\n // Persist the ACL mutation inside a transaction so the per-user permission\n // write (or removal) commits atomically (proper ACL-edit transaction handling).\n if (!hasCustomAcl) {\n if (acl) {\n const aclToRemove = acl\n await withAtomicFlush(em, [() => em.remove(aclToRemove)], { transaction: true })\n }\n } else {\n if (!acl) {\n acl = em.create(UserAcl, { user: parsed.data.userId as any, tenantId: auth.tenantId as any })\n }\n const aclRecord = acl as any\n await withAtomicFlush(\n em,\n [\n () => {\n aclRecord.isSuperAdmin = effectiveIsSuperAdmin\n aclRecord.featuresJson = effectiveFeatures\n aclRecord.organizationsJson = organizations\n em.persist(aclRecord)\n },\n ],\n { transaction: true },\n )\n }\n\n // Invalidate cache for this user\n await rbacService.invalidateUserCache(parsed.data.userId)\n try {\n const cache = container.resolve('cache') as any\n if (cache) await cache.deleteByTags([`rbac:user:${parsed.data.userId}`])\n } catch {}\n\n return NextResponse.json({\n ok: true,\n sanitized: !actorIsSuperAdmin && (hasRestrictedChanges(requestedFeatures, effectiveFeatures, existingFeatures) || requestedIsSuperAdmin !== effectiveIsSuperAdmin),\n })\n}\n\nfunction normalizeOrganizations(organizations: unknown): string[] | null {\n if (!Array.isArray(organizations)) return null\n return normalizeGrantFeatureList(organizations)\n}\n\nfunction sanitizeTenantFeatures(features: string[]): string[] {\n return features.filter((feature) => !isTenantRestrictedFeature(feature))\n}\n\nfunction isTenantRestrictedFeature(feature: string): boolean {\n if (feature === '*' || feature === 'directory.*') return true\n if (feature.startsWith('directory.tenants')) return true\n return false\n}\n\nfunction hasRestrictedChanges(requested: string[], effective: string[], existing: string[]): boolean {\n if (requested.length === effective.length) return false\n const effectiveSet = new Set(effective)\n const existingSet = new Set(existing)\n // If the effective set matches existing, we only trimmed restricted duplicates and should not report\n if (effectiveSet.size === existingSet.size) {\n let identical = true\n for (const value of effectiveSet) {\n if (!existingSet.has(value)) {\n identical = false\n break\n }\n }\n if (identical) return false\n }\n return true\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'User ACL management',\n methods: {\n GET: {\n summary: 'Fetch user ACL',\n description: 'Returns custom ACL overrides for a user within the current tenant, if any.',\n query: getSchema,\n responses: [\n { status: 200, description: 'User ACL entry', schema: userAclResponseSchema },\n { status: 400, description: 'Invalid user id', schema: userAclErrorSchema },\n { status: 401, description: 'Unauthorized', schema: userAclErrorSchema },\n ],\n },\n PUT: {\n summary: 'Update user ACL',\n description: 'Configures per-user ACL overrides, including super admin access, feature list, and organization scope.',\n requestBody: {\n contentType: 'application/json',\n schema: putSchema,\n },\n responses: [\n { status: 200, description: 'User ACL updated', schema: userAclUpdateResponseSchema },\n { status: 400, description: 'Invalid payload', schema: userAclErrorSchema },\n { status: 401, description: 'Unauthorized', schema: userAclErrorSchema },\n { status: 403, description: 'Insufficient privileges to modify ACL', schema: userAclErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,11 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { usePathname } from "next/navigation";
4
5
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
5
6
  import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
6
7
  import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
8
+ import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from "@open-mercato/ui/backend/injection/recordContext";
7
9
  import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
8
10
  import { deleteCrud, updateCrud } from "@open-mercato/ui/backend/utils/crud";
9
11
  import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
@@ -17,6 +19,7 @@ import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-
17
19
  function EditRolePage({ params }) {
18
20
  const id = params?.id;
19
21
  const t = useT();
22
+ const pathname = usePathname();
20
23
  const [initial, setInitial] = React.useState(null);
21
24
  const [loading, setLoading] = React.useState(true);
22
25
  const [aclData, setAclData] = React.useState({ isSuperAdmin: false, features: [], organizations: null });
@@ -156,6 +159,15 @@ function EditRolePage({ params }) {
156
159
  ) : null
157
160
  }
158
161
  ], [aclData, actorIsSuperAdmin, detailFieldIds, id, initial, loading, selectedTenantId, t]);
162
+ useSetCurrentRecordInjectionContext(
163
+ buildRecordInjectionContext({
164
+ resourceKind: "auth.role",
165
+ resourceId: id || null,
166
+ updatedAt: initial?.updatedAt ?? null,
167
+ data: initial,
168
+ path: pathname
169
+ })
170
+ );
159
171
  if (!id) return null;
160
172
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
161
173
  CrudForm,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/auth/backend/roles/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { AclEditor, type AclData } from '@open-mercato/core/modules/auth/components/AclEditor'\nimport { WidgetVisibilityEditor, type WidgetVisibilityEditorHandle } from '@open-mercato/core/modules/dashboards/components/WidgetVisibilityEditor'\nimport { E } from '#generated/entities.ids.generated'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\n\ntype EditRoleFormValues = {\n name?: string\n tenantId?: string | null\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype RoleRecord = {\n id: string\n name: string\n tenantId: string | null\n tenantName?: string | null\n usersCount?: number | null\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype RoleListResponse = {\n items?: RoleRecord[]\n isSuperAdmin?: boolean\n}\n\nexport default function EditRolePage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const [initial, setInitial] = React.useState<RoleRecord | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [aclData, setAclData] = React.useState<AclData>({ isSuperAdmin: false, features: [], organizations: null })\n const [aclUpdatedAt, setAclUpdatedAt] = React.useState<string | null>(null)\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const widgetEditorRef = React.useRef<WidgetVisibilityEditorHandle | null>(null)\n\n React.useEffect(() => {\n if (!id) return\n const roleId = id\n let cancelled = false\n async function load() {\n try {\n const { ok, result } = await apiCall<RoleListResponse>(`/api/auth/roles?id=${encodeURIComponent(roleId)}`)\n if (!ok) throw new Error(t('auth.roles.form.errors.load', 'Failed to load role'))\n const foundList = Array.isArray(result?.items) ? result?.items : []\n const found = (foundList?.[0] ?? null) as RoleRecord | null\n if (!cancelled) {\n setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n setInitial(found ? { ...found, ...extractCustomFieldEntries(found) } : null)\n const tenant = found && typeof found.tenantId === 'string' ? found.tenantId : null\n setSelectedTenantId(tenant)\n }\n } catch {\n if (!cancelled) {\n setInitial(null)\n setSelectedTenantId(null)\n }\n }\n if (!cancelled) setLoading(false)\n }\n load()\n return () => { cancelled = true }\n }, [id, t])\n\n const preloadedTenants = React.useMemo(() => {\n if (!selectedTenantId) return null\n const name = initial?.tenantId === selectedTenantId\n ? (initial?.tenantName ?? selectedTenantId)\n : selectedTenantId\n return [{ id: selectedTenantId, name, isActive: true }]\n }, [initial, selectedTenantId])\n\n const fields = React.useMemo<CrudField[]>(() => {\n const disabled = !!(initial && typeof initial.usersCount === 'number' && initial.usersCount > 0)\n const list: CrudField[] = [\n {\n id: 'name',\n label: t('auth.roles.form.field.name', 'Name'),\n type: 'text',\n required: true,\n disabled,\n },\n ]\n if (actorIsSuperAdmin) {\n list.push({\n id: 'tenantId',\n label: t('auth.roles.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n disabled,\n component: ({ value, setValue }) => {\n const normalizedValue = typeof value === 'string'\n ? value\n : (typeof selectedTenantId === 'string' ? selectedTenantId : null)\n return (\n <TenantSelect\n id=\"tenantId\"\n value={normalizedValue}\n onChange={(next) => {\n const resolved = next ?? null\n setValue(resolved)\n if (selectedTenantId !== resolved) {\n setAclData((prev) => ({ ...prev, organizations: null }))\n }\n setSelectedTenantId(resolved)\n }}\n includeEmptyOption\n disabled={disabled}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n tenants={preloadedTenants}\n />\n )\n },\n })\n }\n return list\n }, [actorIsSuperAdmin, initial, preloadedTenants, selectedTenantId, t])\n\n const detailFieldIds = React.useMemo(() => {\n const base = ['name']\n if (actorIsSuperAdmin) base.push('tenantId')\n return base\n }, [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => ([\n { id: 'details', title: t('auth.roles.form.group.details', 'Details'), column: 1, fields: detailFieldIds },\n { id: 'customFields', title: t('entities.customFields.title', 'Custom Fields'), column: 2, kind: 'customFields' },\n {\n id: 'acl',\n title: t('auth.roles.form.group.access', 'Access'),\n column: 1,\n component: () => {\n if (!id) return null\n const initialTenantId = initial?.tenantId ?? null\n const tenantReassigned = actorIsSuperAdmin\n && initial != null\n && (selectedTenantId ?? null) !== (initialTenantId ?? null)\n return (\n <div className=\"space-y-3\">\n {tenantReassigned ? (\n <Alert status=\"warning\" style=\"lighter\">\n {t(\n 'auth.roles.form.tenantReassignWarning',\n 'This role is being reassigned to a different tenant. The permissions selected here will be saved under the new tenant when you submit.',\n )}\n </Alert>\n ) : null}\n <AclEditor\n kind=\"role\"\n targetId={String(id)}\n canEditOrganizations\n value={aclData}\n onChange={setAclData}\n onVersionChange={setAclUpdatedAt}\n currentUserIsSuperAdmin={actorIsSuperAdmin}\n tenantId={selectedTenantId ?? null}\n preserveOnTenantChange\n />\n </div>\n )\n },\n },\n {\n id: 'dashboardWidgets',\n title: t('auth.roles.form.group.widgets', 'Dashboard Widgets'),\n column: 2,\n component: () => (id && !loading\n ? (\n <WidgetVisibilityEditor\n kind=\"role\"\n targetId={String(id)}\n tenantId={selectedTenantId ?? (initial?.tenantId ?? null)}\n preserveOnTenantChange\n ref={widgetEditorRef}\n />\n )\n : null),\n },\n ]), [aclData, actorIsSuperAdmin, detailFieldIds, id, initial, loading, selectedTenantId, t])\n\n if (!id) return null\n return (\n <Page>\n <PageBody>\n <CrudForm<EditRoleFormValues>\n title={t('auth.roles.form.title.edit', 'Edit Role')}\n backHref=\"/backend/roles\"\n versionHistory={{ resourceKind: 'auth.role', resourceId: id ? String(id) : '' }}\n entityId={E.auth.role}\n fields={fields}\n groups={groups}\n initialValues={initial || { id, tenantId: null }}\n isLoading={loading}\n loadingMessage={t('auth.roles.form.loading', 'Loading data...')}\n cancelHref=\"/backend/roles\"\n successRedirect={`/backend/roles?flash=${encodeURIComponent(t('auth.roles.flash.updated', 'Role saved'))}&type=success`}\n onSubmit={async (values) => {\n const customFields = collectCustomFieldValues(values)\n const payload: Record<string, unknown> = { id }\n if (values.name !== undefined) payload.name = values.name\n let effectiveTenantId: string | null = selectedTenantId ?? (initial?.tenantId ?? null)\n if (actorIsSuperAdmin) {\n const rawTenant = typeof values.tenantId === 'string' ? values.tenantId.trim() : selectedTenantId\n effectiveTenantId = rawTenant && rawTenant.length ? rawTenant : null\n payload.tenantId = effectiveTenantId\n }\n if (Object.keys(customFields).length) {\n payload.customFields = customFields\n }\n const roleOptimisticLockHeader = buildOptimisticLockHeader(initial?.updatedAt)\n if (Object.keys(roleOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(roleOptimisticLockHeader, () => updateCrud('auth/roles', payload))\n } else {\n await updateCrud('auth/roles', payload)\n }\n // Optimistic lock the ACL save against the loaded RoleAcl version so a\n // concurrent permission edit cannot silently overwrite (#2055). CrudForm\n // surfaces the 409 as the unified conflict bar.\n const aclLockHeader = buildOptimisticLockHeader(aclUpdatedAt)\n const saveRoleAcl = () => updateCrud('auth/roles/acl', { roleId: id, tenantId: effectiveTenantId, ...aclData }, {\n errorMessage: t('auth.roles.form.errors.aclUpdate', 'Failed to update role access control'),\n })\n if (Object.keys(aclLockHeader).length > 0) {\n await withScopedApiRequestHeaders(aclLockHeader, saveRoleAcl)\n } else {\n await saveRoleAcl()\n }\n await widgetEditorRef.current?.save()\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }}\n onDelete={async () => {\n const roleOptimisticLockHeader = buildOptimisticLockHeader(initial?.updatedAt)\n const deleteRole = () => deleteCrud('auth/roles', String(id), {\n errorMessage: t('auth.roles.form.errors.delete', 'Failed to delete role'),\n })\n if (Object.keys(roleOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(roleOptimisticLockHeader, deleteRole)\n } else {\n await deleteRole()\n }\n }}\n deleteRedirect={`/backend/roles?flash=${encodeURIComponent(t('auth.roles.flash.deleted', 'Role deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { usePathname } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { AclEditor, type AclData } from '@open-mercato/core/modules/auth/components/AclEditor'\nimport { WidgetVisibilityEditor, type WidgetVisibilityEditorHandle } from '@open-mercato/core/modules/dashboards/components/WidgetVisibilityEditor'\nimport { E } from '#generated/entities.ids.generated'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\n\ntype EditRoleFormValues = {\n name?: string\n tenantId?: string | null\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype RoleRecord = {\n id: string\n name: string\n tenantId: string | null\n tenantName?: string | null\n usersCount?: number | null\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype RoleListResponse = {\n items?: RoleRecord[]\n isSuperAdmin?: boolean\n}\n\nexport default function EditRolePage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const pathname = usePathname()\n const [initial, setInitial] = React.useState<RoleRecord | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [aclData, setAclData] = React.useState<AclData>({ isSuperAdmin: false, features: [], organizations: null })\n const [aclUpdatedAt, setAclUpdatedAt] = React.useState<string | null>(null)\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const widgetEditorRef = React.useRef<WidgetVisibilityEditorHandle | null>(null)\n\n React.useEffect(() => {\n if (!id) return\n const roleId = id\n let cancelled = false\n async function load() {\n try {\n const { ok, result } = await apiCall<RoleListResponse>(`/api/auth/roles?id=${encodeURIComponent(roleId)}`)\n if (!ok) throw new Error(t('auth.roles.form.errors.load', 'Failed to load role'))\n const foundList = Array.isArray(result?.items) ? result?.items : []\n const found = (foundList?.[0] ?? null) as RoleRecord | null\n if (!cancelled) {\n setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n setInitial(found ? { ...found, ...extractCustomFieldEntries(found) } : null)\n const tenant = found && typeof found.tenantId === 'string' ? found.tenantId : null\n setSelectedTenantId(tenant)\n }\n } catch {\n if (!cancelled) {\n setInitial(null)\n setSelectedTenantId(null)\n }\n }\n if (!cancelled) setLoading(false)\n }\n load()\n return () => { cancelled = true }\n }, [id, t])\n\n const preloadedTenants = React.useMemo(() => {\n if (!selectedTenantId) return null\n const name = initial?.tenantId === selectedTenantId\n ? (initial?.tenantName ?? selectedTenantId)\n : selectedTenantId\n return [{ id: selectedTenantId, name, isActive: true }]\n }, [initial, selectedTenantId])\n\n const fields = React.useMemo<CrudField[]>(() => {\n const disabled = !!(initial && typeof initial.usersCount === 'number' && initial.usersCount > 0)\n const list: CrudField[] = [\n {\n id: 'name',\n label: t('auth.roles.form.field.name', 'Name'),\n type: 'text',\n required: true,\n disabled,\n },\n ]\n if (actorIsSuperAdmin) {\n list.push({\n id: 'tenantId',\n label: t('auth.roles.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n disabled,\n component: ({ value, setValue }) => {\n const normalizedValue = typeof value === 'string'\n ? value\n : (typeof selectedTenantId === 'string' ? selectedTenantId : null)\n return (\n <TenantSelect\n id=\"tenantId\"\n value={normalizedValue}\n onChange={(next) => {\n const resolved = next ?? null\n setValue(resolved)\n if (selectedTenantId !== resolved) {\n setAclData((prev) => ({ ...prev, organizations: null }))\n }\n setSelectedTenantId(resolved)\n }}\n includeEmptyOption\n disabled={disabled}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n tenants={preloadedTenants}\n />\n )\n },\n })\n }\n return list\n }, [actorIsSuperAdmin, initial, preloadedTenants, selectedTenantId, t])\n\n const detailFieldIds = React.useMemo(() => {\n const base = ['name']\n if (actorIsSuperAdmin) base.push('tenantId')\n return base\n }, [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => ([\n { id: 'details', title: t('auth.roles.form.group.details', 'Details'), column: 1, fields: detailFieldIds },\n { id: 'customFields', title: t('entities.customFields.title', 'Custom Fields'), column: 2, kind: 'customFields' },\n {\n id: 'acl',\n title: t('auth.roles.form.group.access', 'Access'),\n column: 1,\n component: () => {\n if (!id) return null\n const initialTenantId = initial?.tenantId ?? null\n const tenantReassigned = actorIsSuperAdmin\n && initial != null\n && (selectedTenantId ?? null) !== (initialTenantId ?? null)\n return (\n <div className=\"space-y-3\">\n {tenantReassigned ? (\n <Alert status=\"warning\" style=\"lighter\">\n {t(\n 'auth.roles.form.tenantReassignWarning',\n 'This role is being reassigned to a different tenant. The permissions selected here will be saved under the new tenant when you submit.',\n )}\n </Alert>\n ) : null}\n <AclEditor\n kind=\"role\"\n targetId={String(id)}\n canEditOrganizations\n value={aclData}\n onChange={setAclData}\n onVersionChange={setAclUpdatedAt}\n currentUserIsSuperAdmin={actorIsSuperAdmin}\n tenantId={selectedTenantId ?? null}\n preserveOnTenantChange\n />\n </div>\n )\n },\n },\n {\n id: 'dashboardWidgets',\n title: t('auth.roles.form.group.widgets', 'Dashboard Widgets'),\n column: 2,\n component: () => (id && !loading\n ? (\n <WidgetVisibilityEditor\n kind=\"role\"\n targetId={String(id)}\n tenantId={selectedTenantId ?? (initial?.tenantId ?? null)}\n preserveOnTenantChange\n ref={widgetEditorRef}\n />\n )\n : null),\n },\n ]), [aclData, actorIsSuperAdmin, detailFieldIds, id, initial, loading, selectedTenantId, t])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `auth.role` + id explicitly.\n // The resourceKind mirrors the CrudForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same role.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'auth.role',\n resourceId: id || null,\n updatedAt: initial?.updatedAt ?? null,\n data: initial as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (!id) return null\n return (\n <Page>\n <PageBody>\n <CrudForm<EditRoleFormValues>\n title={t('auth.roles.form.title.edit', 'Edit Role')}\n backHref=\"/backend/roles\"\n versionHistory={{ resourceKind: 'auth.role', resourceId: id ? String(id) : '' }}\n entityId={E.auth.role}\n fields={fields}\n groups={groups}\n initialValues={initial || { id, tenantId: null }}\n isLoading={loading}\n loadingMessage={t('auth.roles.form.loading', 'Loading data...')}\n cancelHref=\"/backend/roles\"\n successRedirect={`/backend/roles?flash=${encodeURIComponent(t('auth.roles.flash.updated', 'Role saved'))}&type=success`}\n onSubmit={async (values) => {\n const customFields = collectCustomFieldValues(values)\n const payload: Record<string, unknown> = { id }\n if (values.name !== undefined) payload.name = values.name\n let effectiveTenantId: string | null = selectedTenantId ?? (initial?.tenantId ?? null)\n if (actorIsSuperAdmin) {\n const rawTenant = typeof values.tenantId === 'string' ? values.tenantId.trim() : selectedTenantId\n effectiveTenantId = rawTenant && rawTenant.length ? rawTenant : null\n payload.tenantId = effectiveTenantId\n }\n if (Object.keys(customFields).length) {\n payload.customFields = customFields\n }\n const roleOptimisticLockHeader = buildOptimisticLockHeader(initial?.updatedAt)\n if (Object.keys(roleOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(roleOptimisticLockHeader, () => updateCrud('auth/roles', payload))\n } else {\n await updateCrud('auth/roles', payload)\n }\n // Optimistic lock the ACL save against the loaded RoleAcl version so a\n // concurrent permission edit cannot silently overwrite (#2055). CrudForm\n // surfaces the 409 as the unified conflict bar.\n const aclLockHeader = buildOptimisticLockHeader(aclUpdatedAt)\n const saveRoleAcl = () => updateCrud('auth/roles/acl', { roleId: id, tenantId: effectiveTenantId, ...aclData }, {\n errorMessage: t('auth.roles.form.errors.aclUpdate', 'Failed to update role access control'),\n })\n if (Object.keys(aclLockHeader).length > 0) {\n await withScopedApiRequestHeaders(aclLockHeader, saveRoleAcl)\n } else {\n await saveRoleAcl()\n }\n await widgetEditorRef.current?.save()\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }}\n onDelete={async () => {\n const roleOptimisticLockHeader = buildOptimisticLockHeader(initial?.updatedAt)\n const deleteRole = () => deleteCrud('auth/roles', String(id), {\n errorMessage: t('auth.roles.form.errors.delete', 'Failed to delete role'),\n })\n if (Object.keys(roleOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(roleOptimisticLockHeader, deleteRole)\n } else {\n await deleteRole()\n }\n }}\n deleteRedirect={`/backend/roles?flash=${encodeURIComponent(t('auth.roles.flash.deleted', 'Role deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { usePathname } from "next/navigation";
4
5
  import { E } from "../../../../../../generated/entities.ids.generated.js";
5
6
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
6
7
  import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
@@ -20,6 +21,7 @@ import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-
20
21
  import { formatPasswordRequirements, getPasswordPolicy } from "@open-mercato/shared/lib/auth/passwordPolicy";
21
22
  import { UserConsentsPanel } from "@open-mercato/core/modules/auth/components/UserConsentsPanel";
22
23
  import { RecordNotFoundState, ErrorMessage } from "@open-mercato/ui/backend/detail";
24
+ import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from "@open-mercato/ui/backend/injection/recordContext";
23
25
  import { normalizeDisplayNameInput } from "@open-mercato/core/modules/auth/lib/displayName";
24
26
  function TenantAwareOrganizationSelectInput({
25
27
  fieldId,
@@ -61,6 +63,7 @@ function TenantAwareOrganizationSelectInput({
61
63
  function EditUserPage({ params }) {
62
64
  const id = params?.id;
63
65
  const t = useT();
66
+ const pathname = usePathname();
64
67
  const tRef = React.useRef(t);
65
68
  tRef.current = t;
66
69
  const [initialUser, setInitialUser] = React.useState(null);
@@ -373,6 +376,15 @@ function EditUserPage({ params }) {
373
376
  ...customFieldValues
374
377
  };
375
378
  }, [initialUser, customFieldValues, selectedTenantId]);
379
+ useSetCurrentRecordInjectionContext(
380
+ buildRecordInjectionContext({
381
+ resourceKind: "auth.user",
382
+ resourceId: id || null,
383
+ updatedAt: initialUser?.updatedAt ?? null,
384
+ data: initialUser,
385
+ path: pathname
386
+ })
387
+ );
376
388
  if (isNotFound) {
377
389
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
378
390
  RecordNotFoundState,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/auth/backend/users/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { E } from '#generated/entities.ids.generated'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup, type CrudFieldOption } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { AclEditor, type AclData } from '@open-mercato/core/modules/auth/components/AclEditor'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { fetchRoleOptions } from '@open-mercato/core/modules/auth/backend/users/roleOptions'\nimport { WidgetVisibilityEditor, type WidgetVisibilityEditorHandle } from '@open-mercato/core/modules/dashboards/components/WidgetVisibilityEditor'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { formatPasswordRequirements, getPasswordPolicy } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { UserConsentsPanel } from '@open-mercato/core/modules/auth/components/UserConsentsPanel'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { normalizeDisplayNameInput } from '@open-mercato/core/modules/auth/lib/displayName'\n\ntype EditUserFormValues = {\n email: string\n name: string\n password: string\n tenantId: string | null\n organizationId: string | null\n roles: string[]\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype LoadedUser = {\n id: string\n email: string\n name: string | null\n organizationId: string | null\n tenantId: string | null\n tenantName: string | null\n organizationName: string | null\n roles: string[]\n roleIds: string[]\n hasPassword: boolean\n updatedAt: string | null\n}\n\ntype UserApiItem = {\n id?: string | null\n email?: string | null\n name?: string | null\n organizationId?: string | null\n tenantId?: string | null\n tenantName?: string | null\n organizationName?: string | null\n roles?: unknown\n roleIds?: unknown\n hasPassword?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n}\n\ntype UserListResponse = {\n items?: UserApiItem[]\n isSuperAdmin?: boolean\n}\n\ntype RoleLookupResponse = {\n items?: Array<{ id?: string | null; name?: string | null }>\n}\n\ntype FeatureCheckResponse = {\n ok?: boolean\n}\n\ntype TenantAwareOrganizationSelectProps = {\n fieldId: string\n value: string | null\n setValue: (value: string | null) => void\n tenantId: string | null\n includeInactiveIds?: Iterable<string | null | undefined>\n}\n\nfunction TenantAwareOrganizationSelectInput({\n fieldId,\n value,\n setValue,\n tenantId,\n includeInactiveIds,\n}: TenantAwareOrganizationSelectProps) {\n const prevTenantRef = React.useRef<string | null>(tenantId)\n const hydratedRef = React.useRef(false)\n const handleChange = React.useCallback((next: string | null) => {\n setValue(next ?? null)\n }, [setValue])\n\n React.useEffect(() => {\n if (!hydratedRef.current) {\n hydratedRef.current = true\n prevTenantRef.current = tenantId\n return\n }\n if (prevTenantRef.current !== tenantId) {\n prevTenantRef.current = tenantId\n setValue(null)\n }\n }, [tenantId, setValue])\n\n return (\n <OrganizationSelect\n id={fieldId}\n value={value}\n onChange={handleChange}\n required\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n includeInactiveIds={includeInactiveIds}\n tenantId={tenantId}\n />\n )\n}\n\nexport default function EditUserPage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const tRef = React.useRef(t)\n tRef.current = t\n const [initialUser, setInitialUser] = React.useState<LoadedUser | null>(null)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [canEditOrgs, setCanEditOrgs] = React.useState(false)\n const [aclData, setAclData] = React.useState<AclData>({ isSuperAdmin: false, features: [], organizations: null })\n const [aclUpdatedAt, setAclUpdatedAt] = React.useState<string | null>(null)\n const [customFieldValues, setCustomFieldValues] = React.useState<Record<string, unknown>>({})\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [actorResolved, setActorResolved] = React.useState(false)\n const [initialRoleOptions, setInitialRoleOptions] = React.useState<CrudFieldOption[]>([])\n const widgetEditorRef = React.useRef<WidgetVisibilityEditorHandle | null>(null)\n const [resendingInvite, setResendingInvite] = React.useState(false)\n\n const handleResendInvite = React.useCallback(async () => {\n if (!id) return\n setResendingInvite(true)\n try {\n const { ok, result } = await apiCall<{ ok?: boolean; warning?: string }>('/api/auth/users/resend-invite', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n if (ok) {\n if (result?.warning === 'invite_email_failed') {\n flash(tRef.current('auth.users.flash.inviteEmailFailed', 'Invite token created but the email could not be sent. Please check your email provider configuration.'), 'warning')\n } else {\n flash(tRef.current('auth.users.flash.inviteSent', 'Invitation email sent'), 'success')\n }\n }\n } catch (err) {\n console.error('Failed to resend invite:', err)\n flash(tRef.current('auth.users.form.errors.inviteResend', 'Failed to send invitation email'), 'error')\n } finally {\n setResendingInvite(false)\n }\n }, [id])\n const passwordPolicy = React.useMemo(() => getPasswordPolicy(), [])\n const passwordRequirements = React.useMemo(\n () => formatPasswordRequirements(passwordPolicy, t),\n [passwordPolicy, t],\n )\n const passwordDescription = React.useMemo(() => (\n passwordRequirements\n ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })\n : undefined\n ), [passwordRequirements, t])\n\n React.useEffect(() => {\n if (!initialUser) {\n setInitialRoleOptions([])\n return\n }\n const roleIds = initialUser.roleIds\n .map((roleId) => (typeof roleId === 'string' ? roleId.trim() : ''))\n .filter((roleId) => roleId.length > 0)\n const seedOptions = roleIds.map((roleId, index) => {\n const label = typeof initialUser.roles[index] === 'string' && initialUser.roles[index].trim().length\n ? initialUser.roles[index]\n : roleId\n return { value: roleId, label }\n })\n setInitialRoleOptions(seedOptions)\n if (!roleIds.length) return\n let cancelled = false\n Promise.all(roleIds.map(async (roleId) => {\n const response = await apiCall<RoleLookupResponse>(\n `/api/auth/roles?id=${encodeURIComponent(roleId)}&page=1&pageSize=1`,\n undefined,\n { fallback: { items: [] } },\n )\n if (!response.ok || !Array.isArray(response.result?.items)) return null\n const item = response.result.items.find((entry) => entry?.id === roleId) ?? response.result.items[0]\n const name = typeof item?.name === 'string' && item.name.trim().length ? item.name.trim() : null\n return name ? { value: roleId, label: name } : null\n }))\n .then((fetched) => {\n if (cancelled) return\n const byId = new Map(seedOptions.map((option) => [option.value, option]))\n fetched.forEach((option) => {\n if (option) byId.set(option.value, option)\n })\n setInitialRoleOptions(roleIds.map((roleId) => byId.get(roleId) ?? { value: roleId, label: roleId }))\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [initialUser])\n\n React.useEffect(() => {\n if (!id) {\n setLoading(false)\n setError(tRef.current('auth.users.form.errors.noId', 'No user ID provided'))\n return\n }\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n setCustomFieldValues({})\n try {\n const { ok, result } = await apiCall<UserListResponse>(\n `/api/auth/users?id=${encodeURIComponent(String(id))}&page=1&pageSize=1`,\n )\n if (!ok) throw new Error(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n const item = Array.isArray(result?.items) ? result?.items?.[0] : undefined\n if (!cancelled) {\n setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n setActorResolved(true)\n if (!item) {\n setIsNotFound(true)\n setCustomFieldValues({})\n setInitialUser(null)\n setSelectedTenantId(null)\n } else {\n const roleNames = Array.isArray(item.roles)\n ? item.roles\n .map((role) => (typeof role === 'string' ? role : role == null ? '' : String(role)))\n .filter((role) => role.trim().length > 0)\n : []\n const roleIds = Array.isArray(item.roleIds)\n ? (item.roleIds as string[]).filter((rid) => typeof rid === 'string' && rid.trim().length > 0)\n : []\n setInitialUser({\n id: item.id ? String(item.id) : String(id),\n email: item.email ? String(item.email) : '',\n name: item.name ? String(item.name) : null,\n organizationId: item.organizationId ? String(item.organizationId) : null,\n tenantId: item.tenantId ? String(item.tenantId) : null,\n tenantName: item.tenantName ? String(item.tenantName) : null,\n organizationName: item.organizationName ? String(item.organizationName) : null,\n roles: roleNames,\n roleIds: roleIds.length > 0 ? roleIds : roleNames,\n hasPassword: item.hasPassword !== false,\n updatedAt: typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null,\n })\n setSelectedTenantId(item.tenantId ? String(item.tenantId) : null)\n const custom = extractCustomFieldEntries(item as Record<string, unknown>)\n setCustomFieldValues(custom)\n }\n }\n } catch (err) {\n console.error('Failed to load user:', err)\n if (!cancelled) setError(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n if (!cancelled) setCustomFieldValues({})\n if (!cancelled) setActorResolved(true)\n }\n if (!cancelled) setLoading(false)\n try {\n const featureCheck = await apiCall<FeatureCheckResponse>(\n '/api/auth/feature-check',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: ['directory.organizations.view'] }),\n },\n { fallback: { ok: false } },\n )\n if (!cancelled) setCanEditOrgs(Boolean(featureCheck.result?.ok))\n } catch (err) {\n console.error('Failed to check features:', err)\n }\n }\n load()\n return () => { cancelled = true }\n }, [id])\n\n const selectedOrgId = initialUser?.organizationId ? String(initialUser.organizationId) : null\n const preloadedTenants = React.useMemo(() => {\n if (!selectedTenantId) return null\n const name = initialUser?.tenantId === selectedTenantId\n ? (initialUser?.tenantName ?? selectedTenantId)\n : selectedTenantId\n return [{ id: selectedTenantId, name, isActive: true }]\n }, [initialUser, selectedTenantId])\n\n // Block role loading until we know whether the actor is a super admin. Without this guard the\n // initial (non-super-admin) branch fires before the flag resolves and the server returns roles\n // from other tenants because the real caller is a super admin without tenantId scoping.\n const loadRoleOptions = React.useCallback(async (query?: string): Promise<CrudFieldOption[]> => {\n if (!actorResolved) return []\n if (actorIsSuperAdmin) {\n if (!selectedTenantId) return []\n return fetchRoleOptions(query, { tenantId: selectedTenantId, includeSuperAdmin: true })\n }\n return fetchRoleOptions(query)\n }, [actorIsSuperAdmin, actorResolved, selectedTenantId])\n\n const userHasPassword = initialUser?.hasPassword !== false\n const fields: CrudField[] = React.useMemo(() => {\n const items: CrudField[] = [\n { id: 'email', label: t('auth.users.form.field.email', 'Email'), type: 'text', required: true },\n { id: 'name', label: t('auth.users.form.field.name', 'Display name'), type: 'text' },\n {\n id: 'password',\n label: userHasPassword\n ? t('auth.users.form.field.newPassword', 'New Password')\n : t('auth.users.form.field.setPassword', 'Set Password'),\n type: 'password' as const,\n description: [\n userHasPassword\n ? t('auth.users.form.field.passwordChangeHint', 'Leave blank to keep current password')\n : t('auth.users.form.field.passwordInviteHint', 'Optionally set a password for this user (they were invited via email)'),\n passwordDescription,\n ].filter(Boolean).join('. '),\n },\n ]\n if (actorIsSuperAdmin) {\n items.push({\n id: 'tenantId',\n label: t('auth.users.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => {\n const normalizedValue = typeof value === 'string'\n ? value\n : (typeof selectedTenantId === 'string' ? selectedTenantId : null)\n return (\n <TenantSelect\n id=\"tenantId\"\n value={normalizedValue}\n onChange={(next) => {\n const resolved = next ?? null\n setValue(resolved)\n setSelectedTenantId(resolved)\n setAclData({ isSuperAdmin: false, features: [], organizations: null })\n }}\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n required\n tenants={preloadedTenants}\n />\n )\n },\n })\n }\n items.push({\n id: 'organizationId',\n label: t('auth.users.form.field.organization', 'Organization'),\n type: 'custom',\n required: true,\n component: ({ id, value, setValue }) => {\n const normalizedValue = typeof value === 'string' ? (value.length > 0 ? value : null) : null\n return (\n <TenantAwareOrganizationSelectInput\n fieldId={id}\n value={normalizedValue}\n setValue={(next) => setValue(next ?? null)}\n tenantId={selectedTenantId}\n includeInactiveIds={selectedOrgId ? [selectedOrgId] : undefined}\n />\n )\n },\n })\n items.push({\n id: 'roles',\n label: t('auth.users.form.field.roles', 'Roles'),\n type: 'tags',\n options: initialRoleOptions,\n loadOptions: loadRoleOptions,\n })\n return items\n }, [actorIsSuperAdmin, initialRoleOptions, loadRoleOptions, passwordDescription, preloadedTenants, selectedOrgId, selectedTenantId, t, userHasPassword])\n\n const detailFieldIds = React.useMemo(() => {\n const base: string[] = ['email', 'name', 'password', 'organizationId', 'roles']\n if (actorIsSuperAdmin) base.splice(2, 0, 'tenantId')\n return base\n }, [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => [\n { id: 'details', title: t('auth.users.form.group.details', 'Details'), column: 1, fields: detailFieldIds },\n { id: 'custom', title: t('auth.users.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n {\n id: 'acl',\n title: t('auth.users.form.group.access', 'Access'),\n column: 1,\n component: () => (id\n ? (\n <AclEditor\n kind=\"user\"\n targetId={String(id)}\n canEditOrganizations={canEditOrgs}\n value={aclData}\n onChange={setAclData}\n onVersionChange={setAclUpdatedAt}\n userRoles={initialUser?.roles || []}\n currentUserIsSuperAdmin={actorIsSuperAdmin}\n tenantId={selectedTenantId ?? null}\n />\n )\n : null),\n },\n {\n id: 'dashboardWidgets',\n title: t('auth.users.form.group.widgets', 'Dashboard Widgets'),\n column: 2,\n component: () => (id && initialUser\n ? (\n <WidgetVisibilityEditor\n kind=\"user\"\n targetId={String(id)}\n tenantId={selectedTenantId ?? null}\n organizationId={initialUser?.organizationId ?? null}\n ref={widgetEditorRef}\n />\n ) : null\n ),\n },\n {\n id: 'consents',\n title: t('auth.users.form.group.consents', 'Consents'),\n column: 2,\n component: () => (id ? <UserConsentsPanel userId={String(id)} /> : null),\n },\n ], [aclData, actorIsSuperAdmin, canEditOrgs, detailFieldIds, id, initialUser, selectedTenantId, t])\n\n const initialValues = React.useMemo(() => {\n if (initialUser) {\n return {\n email: initialUser.email,\n name: initialUser.name ?? '',\n password: '',\n tenantId: initialUser.tenantId,\n organizationId: initialUser.organizationId,\n roles: initialUser.roleIds,\n updatedAt: initialUser.updatedAt,\n ...customFieldValues,\n }\n }\n return {\n email: '',\n name: '',\n password: '',\n tenantId: selectedTenantId ?? null,\n organizationId: null,\n roles: [],\n ...customFieldValues,\n }\n }, [initialUser, customFieldValues, selectedTenantId])\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('auth.users.form.errors.notFound', 'User not found')}\n backHref=\"/backend/users\"\n backLabel={t('auth.users.form.actions.backToList', 'Back to users')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<EditUserFormValues>\n title={t('auth.users.form.title.edit', 'Edit User')}\n backHref=\"/backend/users\"\n versionHistory={{ resourceKind: 'auth.user', resourceId: id ? String(id) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.auth.user}\n initialValues={initialValues}\n isLoading={loading}\n loadingMessage={t('auth.users.form.loading', 'Loading user data...')}\n submitLabel={t('auth.users.form.action.save', 'Save')}\n cancelHref=\"/backend/users\"\n extraActions={id && !userHasPassword ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={resendingInvite}\n onClick={handleResendInvite}\n >\n {resendingInvite\n ? t('auth.users.form.action.resendingInvite', 'Sending...')\n : t('auth.users.form.action.resendInvite', 'Resend Invite')}\n </Button>\n ) : undefined}\n successRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.updated', 'User saved'))}&type=success`}\n onSubmit={async (values) => {\n if (!id) return\n const customFields = collectCustomFieldValues(values)\n const payload = {\n id: id ? String(id) : '',\n email: values.email,\n name: normalizeDisplayNameInput(values.name),\n password: values.password && values.password.trim() ? values.password : undefined,\n organizationId: values.organizationId ? values.organizationId : undefined,\n roles: Array.isArray(values.roles) ? values.roles : [],\n ...(Object.keys(customFields).length ? { customFields } : {}),\n }\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, () => updateCrud('auth/users', payload))\n } else {\n await updateCrud('auth/users', payload)\n }\n // Optimistic lock the ACL save against the loaded UserAcl version so a\n // concurrent permission edit cannot silently overwrite (#2055). CrudForm\n // surfaces the 409 as the unified conflict bar.\n const aclLockHeader = buildOptimisticLockHeader(aclUpdatedAt)\n const saveUserAcl = () => updateCrud('auth/users/acl', { userId: id, ...aclData }, {\n errorMessage: t('auth.users.form.errors.aclUpdate', 'Failed to update user access control'),\n })\n if (Object.keys(aclLockHeader).length > 0) {\n await withScopedApiRequestHeaders(aclLockHeader, saveUserAcl)\n } else {\n await saveUserAcl()\n }\n await widgetEditorRef.current?.save()\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }}\n onDelete={async () => {\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n const deleteUser = () => deleteCrud('auth/users', String(id), {\n errorMessage: t('auth.users.form.errors.delete', 'Failed to delete user'),\n })\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, deleteUser)\n } else {\n await deleteUser()\n }\n }}\n deleteRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.deleted', 'User deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { usePathname } from 'next/navigation'\nimport { E } from '#generated/entities.ids.generated'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup, type CrudFieldOption } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { AclEditor, type AclData } from '@open-mercato/core/modules/auth/components/AclEditor'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { fetchRoleOptions } from '@open-mercato/core/modules/auth/backend/users/roleOptions'\nimport { WidgetVisibilityEditor, type WidgetVisibilityEditorHandle } from '@open-mercato/core/modules/dashboards/components/WidgetVisibilityEditor'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { formatPasswordRequirements, getPasswordPolicy } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { UserConsentsPanel } from '@open-mercato/core/modules/auth/components/UserConsentsPanel'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { normalizeDisplayNameInput } from '@open-mercato/core/modules/auth/lib/displayName'\n\ntype EditUserFormValues = {\n email: string\n name: string\n password: string\n tenantId: string | null\n organizationId: string | null\n roles: string[]\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype LoadedUser = {\n id: string\n email: string\n name: string | null\n organizationId: string | null\n tenantId: string | null\n tenantName: string | null\n organizationName: string | null\n roles: string[]\n roleIds: string[]\n hasPassword: boolean\n updatedAt: string | null\n}\n\ntype UserApiItem = {\n id?: string | null\n email?: string | null\n name?: string | null\n organizationId?: string | null\n tenantId?: string | null\n tenantName?: string | null\n organizationName?: string | null\n roles?: unknown\n roleIds?: unknown\n hasPassword?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n}\n\ntype UserListResponse = {\n items?: UserApiItem[]\n isSuperAdmin?: boolean\n}\n\ntype RoleLookupResponse = {\n items?: Array<{ id?: string | null; name?: string | null }>\n}\n\ntype FeatureCheckResponse = {\n ok?: boolean\n}\n\ntype TenantAwareOrganizationSelectProps = {\n fieldId: string\n value: string | null\n setValue: (value: string | null) => void\n tenantId: string | null\n includeInactiveIds?: Iterable<string | null | undefined>\n}\n\nfunction TenantAwareOrganizationSelectInput({\n fieldId,\n value,\n setValue,\n tenantId,\n includeInactiveIds,\n}: TenantAwareOrganizationSelectProps) {\n const prevTenantRef = React.useRef<string | null>(tenantId)\n const hydratedRef = React.useRef(false)\n const handleChange = React.useCallback((next: string | null) => {\n setValue(next ?? null)\n }, [setValue])\n\n React.useEffect(() => {\n if (!hydratedRef.current) {\n hydratedRef.current = true\n prevTenantRef.current = tenantId\n return\n }\n if (prevTenantRef.current !== tenantId) {\n prevTenantRef.current = tenantId\n setValue(null)\n }\n }, [tenantId, setValue])\n\n return (\n <OrganizationSelect\n id={fieldId}\n value={value}\n onChange={handleChange}\n required\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n includeInactiveIds={includeInactiveIds}\n tenantId={tenantId}\n />\n )\n}\n\nexport default function EditUserPage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const pathname = usePathname()\n const tRef = React.useRef(t)\n tRef.current = t\n const [initialUser, setInitialUser] = React.useState<LoadedUser | null>(null)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [canEditOrgs, setCanEditOrgs] = React.useState(false)\n const [aclData, setAclData] = React.useState<AclData>({ isSuperAdmin: false, features: [], organizations: null })\n const [aclUpdatedAt, setAclUpdatedAt] = React.useState<string | null>(null)\n const [customFieldValues, setCustomFieldValues] = React.useState<Record<string, unknown>>({})\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [actorResolved, setActorResolved] = React.useState(false)\n const [initialRoleOptions, setInitialRoleOptions] = React.useState<CrudFieldOption[]>([])\n const widgetEditorRef = React.useRef<WidgetVisibilityEditorHandle | null>(null)\n const [resendingInvite, setResendingInvite] = React.useState(false)\n\n const handleResendInvite = React.useCallback(async () => {\n if (!id) return\n setResendingInvite(true)\n try {\n const { ok, result } = await apiCall<{ ok?: boolean; warning?: string }>('/api/auth/users/resend-invite', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n if (ok) {\n if (result?.warning === 'invite_email_failed') {\n flash(tRef.current('auth.users.flash.inviteEmailFailed', 'Invite token created but the email could not be sent. Please check your email provider configuration.'), 'warning')\n } else {\n flash(tRef.current('auth.users.flash.inviteSent', 'Invitation email sent'), 'success')\n }\n }\n } catch (err) {\n console.error('Failed to resend invite:', err)\n flash(tRef.current('auth.users.form.errors.inviteResend', 'Failed to send invitation email'), 'error')\n } finally {\n setResendingInvite(false)\n }\n }, [id])\n const passwordPolicy = React.useMemo(() => getPasswordPolicy(), [])\n const passwordRequirements = React.useMemo(\n () => formatPasswordRequirements(passwordPolicy, t),\n [passwordPolicy, t],\n )\n const passwordDescription = React.useMemo(() => (\n passwordRequirements\n ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })\n : undefined\n ), [passwordRequirements, t])\n\n React.useEffect(() => {\n if (!initialUser) {\n setInitialRoleOptions([])\n return\n }\n const roleIds = initialUser.roleIds\n .map((roleId) => (typeof roleId === 'string' ? roleId.trim() : ''))\n .filter((roleId) => roleId.length > 0)\n const seedOptions = roleIds.map((roleId, index) => {\n const label = typeof initialUser.roles[index] === 'string' && initialUser.roles[index].trim().length\n ? initialUser.roles[index]\n : roleId\n return { value: roleId, label }\n })\n setInitialRoleOptions(seedOptions)\n if (!roleIds.length) return\n let cancelled = false\n Promise.all(roleIds.map(async (roleId) => {\n const response = await apiCall<RoleLookupResponse>(\n `/api/auth/roles?id=${encodeURIComponent(roleId)}&page=1&pageSize=1`,\n undefined,\n { fallback: { items: [] } },\n )\n if (!response.ok || !Array.isArray(response.result?.items)) return null\n const item = response.result.items.find((entry) => entry?.id === roleId) ?? response.result.items[0]\n const name = typeof item?.name === 'string' && item.name.trim().length ? item.name.trim() : null\n return name ? { value: roleId, label: name } : null\n }))\n .then((fetched) => {\n if (cancelled) return\n const byId = new Map(seedOptions.map((option) => [option.value, option]))\n fetched.forEach((option) => {\n if (option) byId.set(option.value, option)\n })\n setInitialRoleOptions(roleIds.map((roleId) => byId.get(roleId) ?? { value: roleId, label: roleId }))\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [initialUser])\n\n React.useEffect(() => {\n if (!id) {\n setLoading(false)\n setError(tRef.current('auth.users.form.errors.noId', 'No user ID provided'))\n return\n }\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n setCustomFieldValues({})\n try {\n const { ok, result } = await apiCall<UserListResponse>(\n `/api/auth/users?id=${encodeURIComponent(String(id))}&page=1&pageSize=1`,\n )\n if (!ok) throw new Error(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n const item = Array.isArray(result?.items) ? result?.items?.[0] : undefined\n if (!cancelled) {\n setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n setActorResolved(true)\n if (!item) {\n setIsNotFound(true)\n setCustomFieldValues({})\n setInitialUser(null)\n setSelectedTenantId(null)\n } else {\n const roleNames = Array.isArray(item.roles)\n ? item.roles\n .map((role) => (typeof role === 'string' ? role : role == null ? '' : String(role)))\n .filter((role) => role.trim().length > 0)\n : []\n const roleIds = Array.isArray(item.roleIds)\n ? (item.roleIds as string[]).filter((rid) => typeof rid === 'string' && rid.trim().length > 0)\n : []\n setInitialUser({\n id: item.id ? String(item.id) : String(id),\n email: item.email ? String(item.email) : '',\n name: item.name ? String(item.name) : null,\n organizationId: item.organizationId ? String(item.organizationId) : null,\n tenantId: item.tenantId ? String(item.tenantId) : null,\n tenantName: item.tenantName ? String(item.tenantName) : null,\n organizationName: item.organizationName ? String(item.organizationName) : null,\n roles: roleNames,\n roleIds: roleIds.length > 0 ? roleIds : roleNames,\n hasPassword: item.hasPassword !== false,\n updatedAt: typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null,\n })\n setSelectedTenantId(item.tenantId ? String(item.tenantId) : null)\n const custom = extractCustomFieldEntries(item as Record<string, unknown>)\n setCustomFieldValues(custom)\n }\n }\n } catch (err) {\n console.error('Failed to load user:', err)\n if (!cancelled) setError(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n if (!cancelled) setCustomFieldValues({})\n if (!cancelled) setActorResolved(true)\n }\n if (!cancelled) setLoading(false)\n try {\n const featureCheck = await apiCall<FeatureCheckResponse>(\n '/api/auth/feature-check',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: ['directory.organizations.view'] }),\n },\n { fallback: { ok: false } },\n )\n if (!cancelled) setCanEditOrgs(Boolean(featureCheck.result?.ok))\n } catch (err) {\n console.error('Failed to check features:', err)\n }\n }\n load()\n return () => { cancelled = true }\n }, [id])\n\n const selectedOrgId = initialUser?.organizationId ? String(initialUser.organizationId) : null\n const preloadedTenants = React.useMemo(() => {\n if (!selectedTenantId) return null\n const name = initialUser?.tenantId === selectedTenantId\n ? (initialUser?.tenantName ?? selectedTenantId)\n : selectedTenantId\n return [{ id: selectedTenantId, name, isActive: true }]\n }, [initialUser, selectedTenantId])\n\n // Block role loading until we know whether the actor is a super admin. Without this guard the\n // initial (non-super-admin) branch fires before the flag resolves and the server returns roles\n // from other tenants because the real caller is a super admin without tenantId scoping.\n const loadRoleOptions = React.useCallback(async (query?: string): Promise<CrudFieldOption[]> => {\n if (!actorResolved) return []\n if (actorIsSuperAdmin) {\n if (!selectedTenantId) return []\n return fetchRoleOptions(query, { tenantId: selectedTenantId, includeSuperAdmin: true })\n }\n return fetchRoleOptions(query)\n }, [actorIsSuperAdmin, actorResolved, selectedTenantId])\n\n const userHasPassword = initialUser?.hasPassword !== false\n const fields: CrudField[] = React.useMemo(() => {\n const items: CrudField[] = [\n { id: 'email', label: t('auth.users.form.field.email', 'Email'), type: 'text', required: true },\n { id: 'name', label: t('auth.users.form.field.name', 'Display name'), type: 'text' },\n {\n id: 'password',\n label: userHasPassword\n ? t('auth.users.form.field.newPassword', 'New Password')\n : t('auth.users.form.field.setPassword', 'Set Password'),\n type: 'password' as const,\n description: [\n userHasPassword\n ? t('auth.users.form.field.passwordChangeHint', 'Leave blank to keep current password')\n : t('auth.users.form.field.passwordInviteHint', 'Optionally set a password for this user (they were invited via email)'),\n passwordDescription,\n ].filter(Boolean).join('. '),\n },\n ]\n if (actorIsSuperAdmin) {\n items.push({\n id: 'tenantId',\n label: t('auth.users.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => {\n const normalizedValue = typeof value === 'string'\n ? value\n : (typeof selectedTenantId === 'string' ? selectedTenantId : null)\n return (\n <TenantSelect\n id=\"tenantId\"\n value={normalizedValue}\n onChange={(next) => {\n const resolved = next ?? null\n setValue(resolved)\n setSelectedTenantId(resolved)\n setAclData({ isSuperAdmin: false, features: [], organizations: null })\n }}\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n required\n tenants={preloadedTenants}\n />\n )\n },\n })\n }\n items.push({\n id: 'organizationId',\n label: t('auth.users.form.field.organization', 'Organization'),\n type: 'custom',\n required: true,\n component: ({ id, value, setValue }) => {\n const normalizedValue = typeof value === 'string' ? (value.length > 0 ? value : null) : null\n return (\n <TenantAwareOrganizationSelectInput\n fieldId={id}\n value={normalizedValue}\n setValue={(next) => setValue(next ?? null)}\n tenantId={selectedTenantId}\n includeInactiveIds={selectedOrgId ? [selectedOrgId] : undefined}\n />\n )\n },\n })\n items.push({\n id: 'roles',\n label: t('auth.users.form.field.roles', 'Roles'),\n type: 'tags',\n options: initialRoleOptions,\n loadOptions: loadRoleOptions,\n })\n return items\n }, [actorIsSuperAdmin, initialRoleOptions, loadRoleOptions, passwordDescription, preloadedTenants, selectedOrgId, selectedTenantId, t, userHasPassword])\n\n const detailFieldIds = React.useMemo(() => {\n const base: string[] = ['email', 'name', 'password', 'organizationId', 'roles']\n if (actorIsSuperAdmin) base.splice(2, 0, 'tenantId')\n return base\n }, [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => [\n { id: 'details', title: t('auth.users.form.group.details', 'Details'), column: 1, fields: detailFieldIds },\n { id: 'custom', title: t('auth.users.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n {\n id: 'acl',\n title: t('auth.users.form.group.access', 'Access'),\n column: 1,\n component: () => (id\n ? (\n <AclEditor\n kind=\"user\"\n targetId={String(id)}\n canEditOrganizations={canEditOrgs}\n value={aclData}\n onChange={setAclData}\n onVersionChange={setAclUpdatedAt}\n userRoles={initialUser?.roles || []}\n currentUserIsSuperAdmin={actorIsSuperAdmin}\n tenantId={selectedTenantId ?? null}\n />\n )\n : null),\n },\n {\n id: 'dashboardWidgets',\n title: t('auth.users.form.group.widgets', 'Dashboard Widgets'),\n column: 2,\n component: () => (id && initialUser\n ? (\n <WidgetVisibilityEditor\n kind=\"user\"\n targetId={String(id)}\n tenantId={selectedTenantId ?? null}\n organizationId={initialUser?.organizationId ?? null}\n ref={widgetEditorRef}\n />\n ) : null\n ),\n },\n {\n id: 'consents',\n title: t('auth.users.form.group.consents', 'Consents'),\n column: 2,\n component: () => (id ? <UserConsentsPanel userId={String(id)} /> : null),\n },\n ], [aclData, actorIsSuperAdmin, canEditOrgs, detailFieldIds, id, initialUser, selectedTenantId, t])\n\n const initialValues = React.useMemo(() => {\n if (initialUser) {\n return {\n email: initialUser.email,\n name: initialUser.name ?? '',\n password: '',\n tenantId: initialUser.tenantId,\n organizationId: initialUser.organizationId,\n roles: initialUser.roleIds,\n updatedAt: initialUser.updatedAt,\n ...customFieldValues,\n }\n }\n return {\n email: '',\n name: '',\n password: '',\n tenantId: selectedTenantId ?? null,\n organizationId: null,\n roles: [],\n ...customFieldValues,\n }\n }, [initialUser, customFieldValues, selectedTenantId])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `auth.user` + id explicitly.\n // The resourceKind mirrors the CrudForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same user.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'auth.user',\n resourceId: id || null,\n updatedAt: initialUser?.updatedAt ?? null,\n data: initialUser as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('auth.users.form.errors.notFound', 'User not found')}\n backHref=\"/backend/users\"\n backLabel={t('auth.users.form.actions.backToList', 'Back to users')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<EditUserFormValues>\n title={t('auth.users.form.title.edit', 'Edit User')}\n backHref=\"/backend/users\"\n versionHistory={{ resourceKind: 'auth.user', resourceId: id ? String(id) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.auth.user}\n initialValues={initialValues}\n isLoading={loading}\n loadingMessage={t('auth.users.form.loading', 'Loading user data...')}\n submitLabel={t('auth.users.form.action.save', 'Save')}\n cancelHref=\"/backend/users\"\n extraActions={id && !userHasPassword ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={resendingInvite}\n onClick={handleResendInvite}\n >\n {resendingInvite\n ? t('auth.users.form.action.resendingInvite', 'Sending...')\n : t('auth.users.form.action.resendInvite', 'Resend Invite')}\n </Button>\n ) : undefined}\n successRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.updated', 'User saved'))}&type=success`}\n onSubmit={async (values) => {\n if (!id) return\n const customFields = collectCustomFieldValues(values)\n const payload = {\n id: id ? String(id) : '',\n email: values.email,\n name: normalizeDisplayNameInput(values.name),\n password: values.password && values.password.trim() ? values.password : undefined,\n organizationId: values.organizationId ? values.organizationId : undefined,\n roles: Array.isArray(values.roles) ? values.roles : [],\n ...(Object.keys(customFields).length ? { customFields } : {}),\n }\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, () => updateCrud('auth/users', payload))\n } else {\n await updateCrud('auth/users', payload)\n }\n // Optimistic lock the ACL save against the loaded UserAcl version so a\n // concurrent permission edit cannot silently overwrite (#2055). CrudForm\n // surfaces the 409 as the unified conflict bar.\n const aclLockHeader = buildOptimisticLockHeader(aclUpdatedAt)\n const saveUserAcl = () => updateCrud('auth/users/acl', { userId: id, ...aclData }, {\n errorMessage: t('auth.users.form.errors.aclUpdate', 'Failed to update user access control'),\n })\n if (Object.keys(aclLockHeader).length > 0) {\n await withScopedApiRequestHeaders(aclLockHeader, saveUserAcl)\n } else {\n await saveUserAcl()\n }\n await widgetEditorRef.current?.save()\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }}\n onDelete={async () => {\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n const deleteUser = () => deleteCrud('auth/users', String(id), {\n errorMessage: t('auth.users.form.errors.delete', 'Failed to delete user'),\n })\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, deleteUser)\n } else {\n await deleteUser()\n }\n }}\n deleteRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.deleted', 'User deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["id"]
7
7
  }
@@ -302,7 +302,7 @@ __decorateClass([
302
302
  Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
303
303
  ], RoleAcl.prototype, "createdAt", 2);
304
304
  __decorateClass([
305
- Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date(), nullable: true })
305
+ Property({ name: "updated_at", type: Date, onCreate: () => /* @__PURE__ */ new Date(), onUpdate: () => /* @__PURE__ */ new Date(), nullable: true })
306
306
  ], RoleAcl.prototype, "updatedAt", 2);
307
307
  __decorateClass([
308
308
  Property({ name: "deleted_at", type: Date, nullable: true })
@@ -338,7 +338,7 @@ __decorateClass([
338
338
  Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
339
339
  ], UserAcl.prototype, "createdAt", 2);
340
340
  __decorateClass([
341
- Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date(), nullable: true })
341
+ Property({ name: "updated_at", type: Date, onCreate: () => /* @__PURE__ */ new Date(), onUpdate: () => /* @__PURE__ */ new Date(), nullable: true })
342
342
  ], UserAcl.prototype, "updatedAt", 2);
343
343
  __decorateClass([
344
344
  Property({ name: "deleted_at", type: Date, nullable: true })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/data/entities.ts"],
4
- "sourcesContent": ["import { Entity, Index, ManyToOne, PrimaryKey, Property, Unique } from '@mikro-orm/decorators/legacy'\n\n@Entity({ tableName: 'users' })\n// Email uniqueness is per-tenant, enforced by a partial unique index\n// (`users_tenant_email_hash_uniq`) on `(tenant_id, email_hash)` over live rows\n// (`WHERE deleted_at IS NULL AND email_hash IS NOT NULL`), owned by raw SQL in\n// Migration20260610120000. It keys on the deterministic `email_hash`, not `email`, because\n// `email` is encrypted at rest with a per-row IV (see encryption.ts) \u2014 its ciphertext is\n// non-deterministic, so a unique index on it would not detect duplicates. A `@Unique`\n// decorator can't express a partial, tenant-scoped index, so the entity omits it \u2014 the\n// migration is the source of truth. A global unique constraint contradicts the multi-tenant\n// login flow and leaks cross-tenant account existence (#2934). Mirrors\n// `customer_users_tenant_email_hash_uniq`.\nexport class User {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ type: 'text' })\n email!: string\n\n @Property({ name: 'email_hash', type: 'text', nullable: true })\n @Index({ name: 'users_email_hash_idx' })\n emailHash?: string | null\n\n @Property({ type: 'text', nullable: true })\n name?: string | null\n\n @Property({ name: 'password_hash', type: 'text', nullable: true })\n passwordHash?: string | null\n\n @Property({ name: 'is_confirmed', type: 'boolean', default: true })\n isConfirmed: boolean = true\n\n @Property({ name: 'last_login_at', type: Date, nullable: true })\n lastLoginAt?: Date\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'roles' })\n@Unique({ properties: ['tenantId', 'name'] })\nexport class Role {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ type: 'text' })\n name!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'user_sidebar_preferences' })\n// Uniqueness is enforced by a partial unique index (`user_sidebar_preferences_active_unique_idx`)\n// scoped to live rows (`WHERE deleted_at IS NULL`) and owned by raw SQL in\n// Migration20260427143311. A `@Unique` decorator can't express a partial index,\n// so the entity intentionally omits it \u2014 the migration is the source of truth.\nexport class UserSidebarPreference {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ type: 'text' })\n locale!: string\n\n @Property({ name: 'settings_json', type: 'json', nullable: true })\n settingsJson?: unknown\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'role_sidebar_preferences' })\n// Uniqueness is enforced by a partial unique index (`role_sidebar_preferences_active_unique_idx`)\n// scoped to live rows (`WHERE deleted_at IS NULL`) and owned by raw SQL in\n// Migration20260427143311. A `@Unique` decorator can't express a partial index,\n// so the entity intentionally omits it \u2014 the migration is the source of truth.\nexport class RoleSidebarPreference {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => Role)\n role!: Role\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ type: 'text' })\n locale!: string\n\n @Property({ name: 'settings_json', type: 'json', nullable: true })\n settingsJson?: unknown\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'sidebar_variants' })\n// Uniqueness is enforced by a partial unique index (`sidebar_variants_active_name_unique_idx`)\n// scoped to live rows (`WHERE deleted_at IS NULL`) and owned by raw SQL in\n// Migration20260427143311. A `@Unique` decorator can't express a partial index,\n// so the entity intentionally omits it \u2014 the migration is the source of truth.\nexport class SidebarVariant {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ type: 'text' })\n locale!: string\n\n @Property({ type: 'text' })\n name!: string\n\n @Property({ name: 'settings_json', type: 'json', nullable: true })\n settingsJson?: unknown\n\n @Property({ name: 'is_active', type: 'boolean', default: false })\n isActive: boolean = false\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'user_roles' })\n@Index({ name: 'user_roles_user_id_idx', properties: ['user'] })\n@Index({ name: 'user_roles_role_id_idx', properties: ['role'] })\nexport class UserRole {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @ManyToOne(() => Role)\n role!: Role\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'sessions' })\nexport class Session {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ type: 'text', unique: true })\n token!: string\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'last_used_at', type: Date, nullable: true })\n lastUsedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'password_resets' })\nexport class PasswordReset {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ type: 'text', unique: true })\n token!: string\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'used_at', type: Date, nullable: true })\n usedAt?: Date\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// RBAC: Role-level ACL\n@Entity({ tableName: 'role_acls' })\nexport class RoleAcl {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => Role)\n role!: Role\n\n // Tenant scope is mandatory for ACL evaluation\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n // Feature list (string-based). Use JSON array to preserve order and allow wildcards like \"example.*\".\n @Property({ name: 'features_json', type: 'json', nullable: true })\n featuresJson?: string[] | null\n\n // If true, user with this role can do everything regardless of features\n @Property({ name: 'is_super_admin', type: 'boolean', default: false })\n isSuperAdmin: boolean = false\n\n // Visible organizations within the tenant; null/empty means all organizations\n @Property({ name: 'organizations_json', type: 'json', nullable: true })\n organizationsJson?: string[] | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// RBAC: Per-user ACL override\n@Entity({ tableName: 'user_acls' })\nexport class UserAcl {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n // Tenant scope is mandatory for ACL evaluation\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n // Feature list (string-based). Use JSON array to preserve order and allow wildcards like \"example.*\".\n @Property({ name: 'features_json', type: 'json', nullable: true })\n featuresJson?: string[] | null\n\n // If true, this user can do everything regardless of features\n @Property({ name: 'is_super_admin', type: 'boolean', default: false })\n isSuperAdmin: boolean = false\n\n // Visible organizations within the tenant; null/empty means all organizations\n @Property({ name: 'organizations_json', type: 'json', nullable: true })\n organizationsJson?: string[] | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'user_consents' })\n@Unique({ properties: ['userId', 'tenantId', 'consentType'] })\nexport class UserConsent {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'consent_type', type: 'text' })\n consentType!: string\n\n @Property({ name: 'is_granted', type: 'boolean', default: false })\n isGranted: boolean = false\n\n @Property({ name: 'granted_at', type: Date, nullable: true })\n grantedAt?: Date | null\n\n @Property({ name: 'withdrawn_at', type: Date, nullable: true })\n withdrawnAt?: Date | null\n\n @Property({ type: 'text', nullable: true })\n source?: string | null\n\n @Property({ name: 'ip_address', type: 'text', nullable: true })\n ipAddress?: string | null\n\n @Property({ name: 'integrity_hash', type: 'text', nullable: true })\n integrityHash?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Entity, Index, ManyToOne, PrimaryKey, Property, Unique } from '@mikro-orm/decorators/legacy'\n\n@Entity({ tableName: 'users' })\n// Email uniqueness is per-tenant, enforced by a partial unique index\n// (`users_tenant_email_hash_uniq`) on `(tenant_id, email_hash)` over live rows\n// (`WHERE deleted_at IS NULL AND email_hash IS NOT NULL`), owned by raw SQL in\n// Migration20260610120000. It keys on the deterministic `email_hash`, not `email`, because\n// `email` is encrypted at rest with a per-row IV (see encryption.ts) \u2014 its ciphertext is\n// non-deterministic, so a unique index on it would not detect duplicates. A `@Unique`\n// decorator can't express a partial, tenant-scoped index, so the entity omits it \u2014 the\n// migration is the source of truth. A global unique constraint contradicts the multi-tenant\n// login flow and leaks cross-tenant account existence (#2934). Mirrors\n// `customer_users_tenant_email_hash_uniq`.\nexport class User {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ type: 'text' })\n email!: string\n\n @Property({ name: 'email_hash', type: 'text', nullable: true })\n @Index({ name: 'users_email_hash_idx' })\n emailHash?: string | null\n\n @Property({ type: 'text', nullable: true })\n name?: string | null\n\n @Property({ name: 'password_hash', type: 'text', nullable: true })\n passwordHash?: string | null\n\n @Property({ name: 'is_confirmed', type: 'boolean', default: true })\n isConfirmed: boolean = true\n\n @Property({ name: 'last_login_at', type: Date, nullable: true })\n lastLoginAt?: Date\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'roles' })\n@Unique({ properties: ['tenantId', 'name'] })\nexport class Role {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ type: 'text' })\n name!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'user_sidebar_preferences' })\n// Uniqueness is enforced by a partial unique index (`user_sidebar_preferences_active_unique_idx`)\n// scoped to live rows (`WHERE deleted_at IS NULL`) and owned by raw SQL in\n// Migration20260427143311. A `@Unique` decorator can't express a partial index,\n// so the entity intentionally omits it \u2014 the migration is the source of truth.\nexport class UserSidebarPreference {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ type: 'text' })\n locale!: string\n\n @Property({ name: 'settings_json', type: 'json', nullable: true })\n settingsJson?: unknown\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'role_sidebar_preferences' })\n// Uniqueness is enforced by a partial unique index (`role_sidebar_preferences_active_unique_idx`)\n// scoped to live rows (`WHERE deleted_at IS NULL`) and owned by raw SQL in\n// Migration20260427143311. A `@Unique` decorator can't express a partial index,\n// so the entity intentionally omits it \u2014 the migration is the source of truth.\nexport class RoleSidebarPreference {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => Role)\n role!: Role\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ type: 'text' })\n locale!: string\n\n @Property({ name: 'settings_json', type: 'json', nullable: true })\n settingsJson?: unknown\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'sidebar_variants' })\n// Uniqueness is enforced by a partial unique index (`sidebar_variants_active_name_unique_idx`)\n// scoped to live rows (`WHERE deleted_at IS NULL`) and owned by raw SQL in\n// Migration20260427143311. A `@Unique` decorator can't express a partial index,\n// so the entity intentionally omits it \u2014 the migration is the source of truth.\nexport class SidebarVariant {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ type: 'text' })\n locale!: string\n\n @Property({ type: 'text' })\n name!: string\n\n @Property({ name: 'settings_json', type: 'json', nullable: true })\n settingsJson?: unknown\n\n @Property({ name: 'is_active', type: 'boolean', default: false })\n isActive: boolean = false\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'user_roles' })\n@Index({ name: 'user_roles_user_id_idx', properties: ['user'] })\n@Index({ name: 'user_roles_role_id_idx', properties: ['role'] })\nexport class UserRole {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @ManyToOne(() => Role)\n role!: Role\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'sessions' })\nexport class Session {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ type: 'text', unique: true })\n token!: string\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'last_used_at', type: Date, nullable: true })\n lastUsedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'password_resets' })\nexport class PasswordReset {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n @Property({ type: 'text', unique: true })\n token!: string\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'used_at', type: Date, nullable: true })\n usedAt?: Date\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// RBAC: Role-level ACL\n@Entity({ tableName: 'role_acls' })\nexport class RoleAcl {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => Role)\n role!: Role\n\n // Tenant scope is mandatory for ACL evaluation\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n // Feature list (string-based). Use JSON array to preserve order and allow wildcards like \"example.*\".\n @Property({ name: 'features_json', type: 'json', nullable: true })\n featuresJson?: string[] | null\n\n // If true, user with this role can do everything regardless of features\n @Property({ name: 'is_super_admin', type: 'boolean', default: false })\n isSuperAdmin: boolean = false\n\n // Visible organizations within the tenant; null/empty means all organizations\n @Property({ name: 'organizations_json', type: 'json', nullable: true })\n organizationsJson?: string[] | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// RBAC: Per-user ACL override\n@Entity({ tableName: 'user_acls' })\nexport class UserAcl {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @ManyToOne(() => User)\n user!: User\n\n // Tenant scope is mandatory for ACL evaluation\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n // Feature list (string-based). Use JSON array to preserve order and allow wildcards like \"example.*\".\n @Property({ name: 'features_json', type: 'json', nullable: true })\n featuresJson?: string[] | null\n\n // If true, this user can do everything regardless of features\n @Property({ name: 'is_super_admin', type: 'boolean', default: false })\n isSuperAdmin: boolean = false\n\n // Visible organizations within the tenant; null/empty means all organizations\n @Property({ name: 'organizations_json', type: 'json', nullable: true })\n organizationsJson?: string[] | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'user_consents' })\n@Unique({ properties: ['userId', 'tenantId', 'consentType'] })\nexport class UserConsent {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'consent_type', type: 'text' })\n consentType!: string\n\n @Property({ name: 'is_granted', type: 'boolean', default: false })\n isGranted: boolean = false\n\n @Property({ name: 'granted_at', type: Date, nullable: true })\n grantedAt?: Date | null\n\n @Property({ name: 'withdrawn_at', type: Date, nullable: true })\n withdrawnAt?: Date | null\n\n @Property({ type: 'text', nullable: true })\n source?: string | null\n\n @Property({ name: 'ip_address', type: 'text', nullable: true })\n ipAddress?: string | null\n\n @Property({ name: 'integrity_hash', type: 'text', nullable: true })\n integrityHash?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date(), nullable: true })\n updatedAt?: Date\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }