@open-mercato/core 0.6.4-develop.4217.1.c9aa050183 → 0.6.4-develop.4239.1.4a264a5828

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 (408) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +37 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +7 -0
  4. package/dist/generated/entities/staff_time_entry_segment/index.js +23 -0
  5. package/dist/generated/entities/staff_time_entry_segment/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +35 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +7 -0
  8. package/dist/generated/entities/staff_time_project_member/index.js +29 -0
  9. package/dist/generated/entities/staff_time_project_member/index.js.map +7 -0
  10. package/dist/generated/entities.ids.generated.js +5 -1
  11. package/dist/generated/entities.ids.generated.js.map +2 -2
  12. package/dist/generated/entity-fields-registry.js +64 -0
  13. package/dist/generated/entity-fields-registry.js.map +2 -2
  14. package/dist/helpers/integration/timesheetFixtures.js +50 -0
  15. package/dist/helpers/integration/timesheetFixtures.js.map +7 -0
  16. package/dist/modules/attachments/api/library/[id]/route.js +20 -16
  17. package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
  18. package/dist/modules/attachments/api/route.js +18 -14
  19. package/dist/modules/attachments/api/route.js.map +2 -2
  20. package/dist/modules/auth/api/roles/acl/route.js +10 -4
  21. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  22. package/dist/modules/auth/api/sidebar/preferences/route.js +27 -20
  23. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  24. package/dist/modules/auth/api/users/acl/route.js +16 -11
  25. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  26. package/dist/modules/auth/commands/users.js +87 -71
  27. package/dist/modules/auth/commands/users.js.map +2 -2
  28. package/dist/modules/auth/services/sidebarPreferencesService.js +39 -30
  29. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  30. package/dist/modules/business_rules/backend/logs/[id]/page.js +24 -5
  31. package/dist/modules/business_rules/backend/logs/[id]/page.js.map +2 -2
  32. package/dist/modules/catalog/api/offers/route.js +15 -5
  33. package/dist/modules/catalog/api/offers/route.js.map +2 -2
  34. package/dist/modules/catalog/commands/categories.js +61 -12
  35. package/dist/modules/catalog/commands/categories.js.map +2 -2
  36. package/dist/modules/catalog/commands/products.js +79 -54
  37. package/dist/modules/catalog/commands/products.js.map +2 -2
  38. package/dist/modules/catalog/commands/variants.js +29 -16
  39. package/dist/modules/catalog/commands/variants.js.map +2 -2
  40. package/dist/modules/currencies/backend/currencies/[id]/page.js +19 -2
  41. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  42. package/dist/modules/currencies/commands/currencies.js +15 -8
  43. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  44. package/dist/modules/customer_accounts/api/admin/users.js +27 -26
  45. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  46. package/dist/modules/customer_accounts/api/password/reset-confirm.js +5 -5
  47. package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +2 -2
  48. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +11 -10
  49. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  50. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +27 -7
  51. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  52. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +27 -7
  53. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  54. package/dist/modules/customers/backend/customers/people/[id]/page.js +29 -8
  55. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  56. package/dist/modules/customers/commands/addresses.js +35 -21
  57. package/dist/modules/customers/commands/addresses.js.map +2 -2
  58. package/dist/modules/customers/commands/companies.js +163 -162
  59. package/dist/modules/customers/commands/companies.js.map +2 -2
  60. package/dist/modules/customers/commands/deals.js +3 -4
  61. package/dist/modules/customers/commands/deals.js.map +2 -2
  62. package/dist/modules/customers/commands/interactions.js +19 -22
  63. package/dist/modules/customers/commands/interactions.js.map +2 -2
  64. package/dist/modules/customers/commands/people.js +18 -15
  65. package/dist/modules/customers/commands/people.js.map +2 -2
  66. package/dist/modules/customers/commands/personCompanyLinks.js +105 -94
  67. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  68. package/dist/modules/customers/commands/pipeline-stages.js +30 -23
  69. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  70. package/dist/modules/customers/commands/pipelines.js +27 -20
  71. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  72. package/dist/modules/customers/commands/tags.js +13 -5
  73. package/dist/modules/customers/commands/tags.js.map +2 -2
  74. package/dist/modules/dashboards/api/users/widgets/route.js +0 -1
  75. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  76. package/dist/modules/dashboards/api/widgets/data/route.js +29 -1
  77. package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
  78. package/dist/modules/data_sync/lib/sync-engine.js +4 -4
  79. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  80. package/dist/modules/data_sync/lib/sync-run-service.js +51 -27
  81. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  82. package/dist/modules/directory/commands/organizations.js +192 -158
  83. package/dist/modules/directory/commands/organizations.js.map +3 -3
  84. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +22 -16
  85. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
  86. package/dist/modules/messages/commands/messages.js +77 -75
  87. package/dist/modules/messages/commands/messages.js.map +2 -2
  88. package/dist/modules/messages/commands/shared.js +132 -132
  89. package/dist/modules/messages/commands/shared.js.map +2 -2
  90. package/dist/modules/perspectives/api/[tableId]/route.js +37 -26
  91. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  92. package/dist/modules/progress/acl.js +8 -4
  93. package/dist/modules/progress/acl.js.map +2 -2
  94. package/dist/modules/resources/commands/resources.js +125 -117
  95. package/dist/modules/resources/commands/resources.js.map +2 -2
  96. package/dist/modules/resources/commands/tags.js +7 -3
  97. package/dist/modules/resources/commands/tags.js.map +2 -2
  98. package/dist/modules/sales/api/quotes/send/route.js +12 -11
  99. package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
  100. package/dist/modules/sales/commands/documents.js +629 -478
  101. package/dist/modules/sales/commands/documents.js.map +2 -2
  102. package/dist/modules/sales/commands/payments.js +146 -146
  103. package/dist/modules/sales/commands/payments.js.map +2 -2
  104. package/dist/modules/sales/commands/returns.js +68 -60
  105. package/dist/modules/sales/commands/returns.js.map +2 -2
  106. package/dist/modules/staff/acl.js +10 -1
  107. package/dist/modules/staff/acl.js.map +2 -2
  108. package/dist/modules/staff/analytics.js +33 -0
  109. package/dist/modules/staff/analytics.js.map +7 -0
  110. package/dist/modules/staff/api/guards.js +31 -0
  111. package/dist/modules/staff/api/guards.js.map +7 -0
  112. package/dist/modules/staff/api/interceptors.js +96 -0
  113. package/dist/modules/staff/api/interceptors.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +170 -0
  115. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/my-projects/route.js +103 -0
  117. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +147 -0
  119. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +171 -0
  121. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +7 -0
  122. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +180 -0
  123. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +7 -0
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +155 -0
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +7 -0
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +173 -0
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +7 -0
  128. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +260 -0
  129. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +7 -0
  130. package/dist/modules/staff/api/timesheets/time-entries/route.js +188 -0
  131. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +7 -0
  132. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +159 -0
  133. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +7 -0
  134. package/dist/modules/staff/api/timesheets/time-projects/route.js +230 -0
  135. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +7 -0
  136. package/dist/modules/staff/backend/staff/timesheets/page.js +710 -0
  137. package/dist/modules/staff/backend/staff/timesheets/page.js.map +7 -0
  138. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +22 -0
  139. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +7 -0
  140. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +125 -0
  141. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +7 -0
  142. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +16 -0
  143. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +7 -0
  144. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +418 -0
  145. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +7 -0
  146. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +16 -0
  147. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +7 -0
  148. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +79 -0
  149. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +7 -0
  150. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +16 -0
  151. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +602 -0
  153. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +25 -0
  155. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +123 -0
  157. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +7 -0
  158. package/dist/modules/staff/cli.js +38 -1
  159. package/dist/modules/staff/cli.js.map +2 -2
  160. package/dist/modules/staff/commands/index.js +2 -0
  161. package/dist/modules/staff/commands/index.js.map +2 -2
  162. package/dist/modules/staff/commands/leave-requests.js +30 -28
  163. package/dist/modules/staff/commands/leave-requests.js.map +3 -3
  164. package/dist/modules/staff/commands/team-members.js +21 -20
  165. package/dist/modules/staff/commands/team-members.js.map +2 -2
  166. package/dist/modules/staff/commands/timesheets-entries.js +409 -0
  167. package/dist/modules/staff/commands/timesheets-entries.js.map +7 -0
  168. package/dist/modules/staff/commands/timesheets-projects.js +618 -0
  169. package/dist/modules/staff/commands/timesheets-projects.js.map +7 -0
  170. package/dist/modules/staff/data/enrichers.js +104 -0
  171. package/dist/modules/staff/data/enrichers.js.map +7 -0
  172. package/dist/modules/staff/data/entities.js +226 -1
  173. package/dist/modules/staff/data/entities.js.map +2 -2
  174. package/dist/modules/staff/data/validators.js +113 -1
  175. package/dist/modules/staff/data/validators.js.map +2 -2
  176. package/dist/modules/staff/events.js +13 -1
  177. package/dist/modules/staff/events.js.map +2 -2
  178. package/dist/modules/staff/lib/crud.js +7 -1
  179. package/dist/modules/staff/lib/crud.js.map +2 -2
  180. package/dist/modules/staff/lib/staffMemberResolver.js +15 -0
  181. package/dist/modules/staff/lib/staffMemberResolver.js.map +7 -0
  182. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js +60 -0
  183. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js.map +7 -0
  184. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js +260 -0
  185. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js.map +7 -0
  186. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js +41 -0
  187. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js.map +7 -0
  188. package/dist/modules/staff/lib/timesheets-projects/initials.js +10 -0
  189. package/dist/modules/staff/lib/timesheets-projects/initials.js.map +7 -0
  190. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js +12 -0
  191. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js.map +7 -0
  192. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js +55 -0
  193. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js.map +7 -0
  194. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js +66 -0
  195. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js.map +7 -0
  196. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +81 -0
  197. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +7 -0
  198. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js +58 -0
  199. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js.map +7 -0
  200. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js +152 -0
  201. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js.map +7 -0
  202. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +37 -0
  203. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +7 -0
  204. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js +57 -0
  205. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js.map +7 -0
  206. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js +50 -0
  207. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js.map +7 -0
  208. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js +163 -0
  209. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js.map +7 -0
  210. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js +209 -0
  211. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js.map +7 -0
  212. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js +52 -0
  213. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js.map +7 -0
  214. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +77 -0
  215. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +7 -0
  216. package/dist/modules/staff/lib/timesheets-ui/ListView.js +173 -0
  217. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +7 -0
  218. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js +32 -0
  219. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js.map +7 -0
  220. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +270 -0
  221. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +7 -0
  222. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js +57 -0
  223. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js.map +7 -0
  224. package/dist/modules/staff/lib/timesheets-ui/colors.js +43 -0
  225. package/dist/modules/staff/lib/timesheets-ui/colors.js.map +7 -0
  226. package/dist/modules/staff/migrations/Migration20260326135612.js +24 -0
  227. package/dist/modules/staff/migrations/Migration20260326135612.js.map +7 -0
  228. package/dist/modules/staff/migrations/Migration20260413102715.js +23 -0
  229. package/dist/modules/staff/migrations/Migration20260413102715.js.map +7 -0
  230. package/dist/modules/staff/migrations/Migration20260413111602.js +13 -0
  231. package/dist/modules/staff/migrations/Migration20260413111602.js.map +7 -0
  232. package/dist/modules/staff/migrations/Migration20260511112759.js +19 -0
  233. package/dist/modules/staff/migrations/Migration20260511112759.js.map +7 -0
  234. package/dist/modules/staff/search.js +35 -0
  235. package/dist/modules/staff/search.js.map +2 -2
  236. package/dist/modules/staff/setup.js +15 -1
  237. package/dist/modules/staff/setup.js.map +2 -2
  238. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js +16 -0
  239. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js.map +7 -0
  240. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +126 -0
  241. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +7 -0
  242. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js +26 -0
  243. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js.map +7 -0
  244. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js +15 -0
  245. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js.map +7 -0
  246. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +238 -0
  247. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +7 -0
  248. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js +26 -0
  249. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js.map +7 -0
  250. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +145 -0
  251. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +7 -0
  252. package/dist/modules/staff/widgets/injection-table.js +12 -0
  253. package/dist/modules/staff/widgets/injection-table.js.map +7 -0
  254. package/dist/modules/sync_excel/api/import/route.js +19 -17
  255. package/dist/modules/sync_excel/api/import/route.js.map +2 -2
  256. package/dist/modules/translations/commands/translations.js +22 -19
  257. package/dist/modules/translations/commands/translations.js.map +2 -2
  258. package/dist/modules/workflows/backend/events/[id]/page.js +24 -6
  259. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  260. package/dist/modules/workflows/backend/instances/[id]/page.js +27 -5
  261. package/dist/modules/workflows/backend/instances/[id]/page.js.map +2 -2
  262. package/dist/modules/workflows/backend/tasks/[id]/page.js +25 -6
  263. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  264. package/generated/entities/staff_time_entry/index.ts +17 -0
  265. package/generated/entities/staff_time_entry_segment/index.ts +10 -0
  266. package/generated/entities/staff_time_project/index.ts +16 -0
  267. package/generated/entities/staff_time_project_member/index.ts +13 -0
  268. package/generated/entities.ids.generated.ts +5 -1
  269. package/generated/entity-fields-registry.ts +64 -0
  270. package/package.json +7 -7
  271. package/src/helpers/integration/timesheetFixtures.ts +61 -0
  272. package/src/modules/attachments/api/library/[id]/route.ts +24 -17
  273. package/src/modules/attachments/api/route.ts +20 -14
  274. package/src/modules/auth/api/roles/acl/route.ts +11 -5
  275. package/src/modules/auth/api/sidebar/preferences/route.ts +33 -24
  276. package/src/modules/auth/api/users/acl/route.ts +17 -12
  277. package/src/modules/auth/commands/users.ts +96 -80
  278. package/src/modules/auth/services/sidebarPreferencesService.ts +40 -32
  279. package/src/modules/business_rules/backend/logs/[id]/page.tsx +32 -7
  280. package/src/modules/catalog/api/offers/route.ts +20 -5
  281. package/src/modules/catalog/commands/categories.ts +61 -12
  282. package/src/modules/catalog/commands/products.ts +93 -60
  283. package/src/modules/catalog/commands/variants.ts +29 -16
  284. package/src/modules/currencies/backend/currencies/[id]/page.tsx +21 -2
  285. package/src/modules/currencies/commands/currencies.ts +27 -14
  286. package/src/modules/currencies/i18n/de.json +1 -0
  287. package/src/modules/currencies/i18n/en.json +1 -0
  288. package/src/modules/currencies/i18n/es.json +1 -0
  289. package/src/modules/currencies/i18n/pl.json +1 -0
  290. package/src/modules/customer_accounts/api/admin/users.ts +31 -26
  291. package/src/modules/customer_accounts/api/password/reset-confirm.ts +5 -6
  292. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +14 -13
  293. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -11
  294. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +34 -11
  295. package/src/modules/customers/backend/customers/people/[id]/page.tsx +35 -11
  296. package/src/modules/customers/commands/addresses.ts +35 -23
  297. package/src/modules/customers/commands/companies.ts +166 -165
  298. package/src/modules/customers/commands/deals.ts +2 -4
  299. package/src/modules/customers/commands/interactions.ts +20 -26
  300. package/src/modules/customers/commands/people.ts +18 -15
  301. package/src/modules/customers/commands/personCompanyLinks.ts +109 -100
  302. package/src/modules/customers/commands/pipeline-stages.ts +31 -27
  303. package/src/modules/customers/commands/pipelines.ts +29 -23
  304. package/src/modules/customers/commands/tags.ts +13 -5
  305. package/src/modules/dashboards/api/users/widgets/route.ts +0 -1
  306. package/src/modules/dashboards/api/widgets/data/route.ts +36 -1
  307. package/src/modules/data_sync/lib/sync-engine.ts +4 -5
  308. package/src/modules/data_sync/lib/sync-run-service.ts +57 -28
  309. package/src/modules/directory/commands/organizations.ts +203 -166
  310. package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +26 -18
  311. package/src/modules/messages/commands/messages.ts +82 -80
  312. package/src/modules/messages/commands/shared.ts +138 -133
  313. package/src/modules/perspectives/api/[tableId]/route.ts +38 -27
  314. package/src/modules/progress/acl.ts +4 -0
  315. package/src/modules/resources/commands/resources.ts +127 -117
  316. package/src/modules/resources/commands/tags.ts +7 -3
  317. package/src/modules/sales/api/quotes/send/route.ts +17 -12
  318. package/src/modules/sales/commands/documents.ts +673 -481
  319. package/src/modules/sales/commands/payments.ts +158 -152
  320. package/src/modules/sales/commands/returns.ts +74 -63
  321. package/src/modules/staff/acl.ts +11 -0
  322. package/src/modules/staff/analytics.ts +30 -0
  323. package/src/modules/staff/api/guards.ts +59 -0
  324. package/src/modules/staff/api/interceptors.ts +122 -0
  325. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +191 -0
  326. package/src/modules/staff/api/timesheets/my-projects/route.ts +115 -0
  327. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +159 -0
  328. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +187 -0
  329. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +191 -0
  330. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +168 -0
  331. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +191 -0
  332. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +292 -0
  333. package/src/modules/staff/api/timesheets/time-entries/route.ts +193 -0
  334. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +167 -0
  335. package/src/modules/staff/api/timesheets/time-projects/route.ts +244 -0
  336. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +20 -0
  337. package/src/modules/staff/backend/staff/timesheets/page.tsx +899 -0
  338. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +12 -0
  339. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +141 -0
  340. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +12 -0
  341. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +579 -0
  342. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +12 -0
  343. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +90 -0
  344. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +23 -0
  345. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +765 -0
  346. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +138 -0
  347. package/src/modules/staff/cli.ts +40 -1
  348. package/src/modules/staff/commands/index.ts +2 -0
  349. package/src/modules/staff/commands/leave-requests.ts +37 -29
  350. package/src/modules/staff/commands/team-members.ts +25 -20
  351. package/src/modules/staff/commands/timesheets-entries.ts +504 -0
  352. package/src/modules/staff/commands/timesheets-projects.ts +699 -0
  353. package/src/modules/staff/data/enrichers.ts +134 -0
  354. package/src/modules/staff/data/entities.ts +198 -0
  355. package/src/modules/staff/data/validators.ts +129 -0
  356. package/src/modules/staff/events.ts +13 -0
  357. package/src/modules/staff/i18n/de.json +209 -1
  358. package/src/modules/staff/i18n/en.json +209 -1
  359. package/src/modules/staff/i18n/es.json +209 -1
  360. package/src/modules/staff/i18n/pl.json +209 -1
  361. package/src/modules/staff/lib/crud.ts +8 -0
  362. package/src/modules/staff/lib/staffMemberResolver.ts +22 -0
  363. package/src/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.ts +89 -0
  364. package/src/modules/staff/lib/timesheets-projects/computeProjectsKpis.ts +311 -0
  365. package/src/modules/staff/lib/timesheets-projects/dateBuckets.ts +37 -0
  366. package/src/modules/staff/lib/timesheets-projects/initials.ts +6 -0
  367. package/src/modules/staff/lib/timesheets-projects/kpiMath.ts +8 -0
  368. package/src/modules/staff/lib/timesheets-projects/listProjectMembersPreview.ts +83 -0
  369. package/src/modules/staff/lib/timesheets-projects-ui/HoursSparkline.tsx +75 -0
  370. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +110 -0
  371. package/src/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.tsx +73 -0
  372. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.tsx +185 -0
  373. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +53 -0
  374. package/src/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.tsx +63 -0
  375. package/src/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.ts +63 -0
  376. package/src/modules/staff/lib/timesheets-ui/AddRowDropdown.tsx +188 -0
  377. package/src/modules/staff/lib/timesheets-ui/CalendarPicker.tsx +229 -0
  378. package/src/modules/staff/lib/timesheets-ui/ColorPicker.tsx +65 -0
  379. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +99 -0
  380. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +230 -0
  381. package/src/modules/staff/lib/timesheets-ui/ProjectColorDot.tsx +40 -0
  382. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +327 -0
  383. package/src/modules/staff/lib/timesheets-ui/ViewSwitcher.tsx +60 -0
  384. package/src/modules/staff/lib/timesheets-ui/colors.ts +58 -0
  385. package/src/modules/staff/migrations/.snapshot-open-mercato.json +1148 -0
  386. package/src/modules/staff/migrations/Migration20260326135612.ts +26 -0
  387. package/src/modules/staff/migrations/Migration20260413102715.ts +25 -0
  388. package/src/modules/staff/migrations/Migration20260413111602.ts +13 -0
  389. package/src/modules/staff/migrations/Migration20260511112759.ts +21 -0
  390. package/src/modules/staff/search.ts +35 -0
  391. package/src/modules/staff/setup.ts +15 -0
  392. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.ts +17 -0
  393. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +158 -0
  394. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.ts +25 -0
  395. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/config.ts +15 -0
  396. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +297 -0
  397. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.ts +25 -0
  398. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +161 -0
  399. package/src/modules/staff/widgets/injection-table.ts +10 -0
  400. package/src/modules/sync_excel/api/import/route.ts +23 -18
  401. package/src/modules/translations/commands/translations.ts +49 -41
  402. package/src/modules/workflows/backend/events/[id]/page.tsx +32 -10
  403. package/src/modules/workflows/backend/instances/[id]/page.tsx +33 -9
  404. package/src/modules/workflows/backend/tasks/[id]/page.tsx +33 -10
  405. package/src/modules/workflows/i18n/de.json +1 -0
  406. package/src/modules/workflows/i18n/en.json +1 -0
  407. package/src/modules/workflows/i18n/es.json +1 -0
  408. package/src/modules/workflows/i18n/pl.json +1 -0
@@ -7,6 +7,7 @@ import {
7
7
  } from "../data/validators.js";
8
8
  import { ensureOrganizationScope, ensureTenantScope } from "./shared.js";
9
9
  import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
10
+ import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
10
11
  const createPipelineCommand = {
11
12
  id: "customers.pipelines.create",
12
13
  async execute(rawInput, ctx) {
@@ -14,13 +15,6 @@ const createPipelineCommand = {
14
15
  ensureTenantScope(ctx, parsed.tenantId);
15
16
  ensureOrganizationScope(ctx, parsed.organizationId);
16
17
  const em = ctx.container.resolve("em").fork();
17
- if (parsed.isDefault) {
18
- await em.nativeUpdate(
19
- CustomerPipeline,
20
- { organizationId: parsed.organizationId, tenantId: parsed.tenantId, isDefault: true },
21
- { isDefault: false }
22
- );
23
- }
24
18
  const pipeline = em.create(CustomerPipeline, {
25
19
  organizationId: parsed.organizationId,
26
20
  tenantId: parsed.tenantId,
@@ -29,8 +23,18 @@ const createPipelineCommand = {
29
23
  createdAt: /* @__PURE__ */ new Date(),
30
24
  updatedAt: /* @__PURE__ */ new Date()
31
25
  });
32
- em.persist(pipeline);
33
- await em.flush();
26
+ await withAtomicFlush(em, [
27
+ async () => {
28
+ if (parsed.isDefault) {
29
+ await em.nativeUpdate(
30
+ CustomerPipeline,
31
+ { organizationId: parsed.organizationId, tenantId: parsed.tenantId, isDefault: true },
32
+ { isDefault: false }
33
+ );
34
+ }
35
+ em.persist(pipeline);
36
+ }
37
+ ], { transaction: true });
34
38
  return { pipelineId: pipeline.id };
35
39
  }
36
40
  };
@@ -43,17 +47,20 @@ const updatePipelineCommand = {
43
47
  if (!pipeline) throw new CrudHttpError(404, { error: "Pipeline not found" });
44
48
  ensureTenantScope(ctx, pipeline.tenantId);
45
49
  ensureOrganizationScope(ctx, pipeline.organizationId);
46
- if (parsed.isDefault && !pipeline.isDefault) {
47
- await em.nativeUpdate(
48
- CustomerPipeline,
49
- { organizationId: pipeline.organizationId, tenantId: pipeline.tenantId, isDefault: true },
50
- { isDefault: false }
51
- );
52
- }
53
- if (parsed.name !== void 0) pipeline.name = parsed.name;
54
- if (parsed.isDefault !== void 0) pipeline.isDefault = parsed.isDefault;
55
- pipeline.updatedAt = /* @__PURE__ */ new Date();
56
- await em.flush();
50
+ await withAtomicFlush(em, [
51
+ async () => {
52
+ if (parsed.isDefault && !pipeline.isDefault) {
53
+ await em.nativeUpdate(
54
+ CustomerPipeline,
55
+ { organizationId: pipeline.organizationId, tenantId: pipeline.tenantId, isDefault: true },
56
+ { isDefault: false }
57
+ );
58
+ }
59
+ if (parsed.name !== void 0) pipeline.name = parsed.name;
60
+ if (parsed.isDefault !== void 0) pipeline.isDefault = parsed.isDefault;
61
+ pipeline.updatedAt = /* @__PURE__ */ new Date();
62
+ }
63
+ ], { transaction: true });
57
64
  }
58
65
  };
59
66
  const deletePipelineCommand = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/commands/pipelines.ts"],
4
- "sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerPipeline, CustomerDeal } from '../data/entities'\nimport {\n pipelineCreateSchema,\n pipelineUpdateSchema,\n pipelineDeleteSchema,\n type PipelineCreateInput,\n type PipelineUpdateInput,\n type PipelineDeleteInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope } from './shared'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\n\nconst createPipelineCommand: CommandHandler<PipelineCreateInput, { pipelineId: string }> = {\n id: 'customers.pipelines.create',\n async execute(rawInput, ctx) {\n const parsed = pipelineCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n if (parsed.isDefault) {\n await em.nativeUpdate(\n CustomerPipeline,\n { organizationId: parsed.organizationId, tenantId: parsed.tenantId, isDefault: true },\n { isDefault: false }\n )\n }\n\n const pipeline = em.create(CustomerPipeline, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n name: parsed.name,\n isDefault: parsed.isDefault ?? false,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(pipeline)\n await em.flush()\n\n return { pipelineId: pipeline.id }\n },\n}\n\nconst updatePipelineCommand: CommandHandler<PipelineUpdateInput, void> = {\n id: 'customers.pipelines.update',\n async execute(rawInput, ctx) {\n const parsed = pipelineUpdateSchema.parse(rawInput)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const pipeline = await em.findOne(CustomerPipeline, { id: parsed.id })\n if (!pipeline) throw new CrudHttpError(404, { error: 'Pipeline not found' })\n\n ensureTenantScope(ctx, pipeline.tenantId)\n ensureOrganizationScope(ctx, pipeline.organizationId)\n\n if (parsed.isDefault && !pipeline.isDefault) {\n await em.nativeUpdate(\n CustomerPipeline,\n { organizationId: pipeline.organizationId, tenantId: pipeline.tenantId, isDefault: true },\n { isDefault: false }\n )\n }\n\n if (parsed.name !== undefined) pipeline.name = parsed.name\n if (parsed.isDefault !== undefined) pipeline.isDefault = parsed.isDefault\n pipeline.updatedAt = new Date()\n\n await em.flush()\n },\n}\n\nconst deletePipelineCommand: CommandHandler<PipelineDeleteInput, void> = {\n id: 'customers.pipelines.delete',\n async execute(rawInput, ctx) {\n const parsed = pipelineDeleteSchema.parse(rawInput)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const pipeline = await em.findOne(CustomerPipeline, { id: parsed.id })\n if (!pipeline) throw new CrudHttpError(404, { error: 'Pipeline not found' })\n\n ensureTenantScope(ctx, pipeline.tenantId)\n ensureOrganizationScope(ctx, pipeline.organizationId)\n\n const activeDealsCount = await em.count(CustomerDeal, {\n pipelineId: parsed.id,\n deletedAt: null,\n })\n if (activeDealsCount > 0) {\n throw new CrudHttpError(409, { error: 'Cannot delete pipeline with active deals' })\n }\n\n em.remove(pipeline)\n await em.flush()\n },\n}\n\nregisterCommand(createPipelineCommand)\nregisterCommand(updatePipelineCommand)\nregisterCommand(deletePipelineCommand)\n\nexport { createPipelineCommand, updatePipelineCommand, deletePipelineCommand }\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerPipeline, CustomerDeal } from '../data/entities'\nimport {\n pipelineCreateSchema,\n pipelineUpdateSchema,\n pipelineDeleteSchema,\n type PipelineCreateInput,\n type PipelineUpdateInput,\n type PipelineDeleteInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope } from './shared'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\n\nconst createPipelineCommand: CommandHandler<PipelineCreateInput, { pipelineId: string }> = {\n id: 'customers.pipelines.create',\n async execute(rawInput, ctx) {\n const parsed = pipelineCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n const pipeline = em.create(CustomerPipeline, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n name: parsed.name,\n isDefault: parsed.isDefault ?? false,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n\n await withAtomicFlush(em, [\n async () => {\n if (parsed.isDefault) {\n await em.nativeUpdate(\n CustomerPipeline,\n { organizationId: parsed.organizationId, tenantId: parsed.tenantId, isDefault: true },\n { isDefault: false }\n )\n }\n em.persist(pipeline)\n },\n ], { transaction: true })\n\n return { pipelineId: pipeline.id }\n },\n}\n\nconst updatePipelineCommand: CommandHandler<PipelineUpdateInput, void> = {\n id: 'customers.pipelines.update',\n async execute(rawInput, ctx) {\n const parsed = pipelineUpdateSchema.parse(rawInput)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const pipeline = await em.findOne(CustomerPipeline, { id: parsed.id })\n if (!pipeline) throw new CrudHttpError(404, { error: 'Pipeline not found' })\n\n ensureTenantScope(ctx, pipeline.tenantId)\n ensureOrganizationScope(ctx, pipeline.organizationId)\n\n await withAtomicFlush(em, [\n async () => {\n if (parsed.isDefault && !pipeline.isDefault) {\n await em.nativeUpdate(\n CustomerPipeline,\n { organizationId: pipeline.organizationId, tenantId: pipeline.tenantId, isDefault: true },\n { isDefault: false }\n )\n }\n\n if (parsed.name !== undefined) pipeline.name = parsed.name\n if (parsed.isDefault !== undefined) pipeline.isDefault = parsed.isDefault\n pipeline.updatedAt = new Date()\n },\n ], { transaction: true })\n },\n}\n\nconst deletePipelineCommand: CommandHandler<PipelineDeleteInput, void> = {\n id: 'customers.pipelines.delete',\n async execute(rawInput, ctx) {\n const parsed = pipelineDeleteSchema.parse(rawInput)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const pipeline = await em.findOne(CustomerPipeline, { id: parsed.id })\n if (!pipeline) throw new CrudHttpError(404, { error: 'Pipeline not found' })\n\n ensureTenantScope(ctx, pipeline.tenantId)\n ensureOrganizationScope(ctx, pipeline.organizationId)\n\n const activeDealsCount = await em.count(CustomerDeal, {\n pipelineId: parsed.id,\n deletedAt: null,\n })\n if (activeDealsCount > 0) {\n throw new CrudHttpError(409, { error: 'Cannot delete pipeline with active deals' })\n }\n\n em.remove(pipeline)\n await em.flush()\n },\n}\n\nregisterCommand(createPipelineCommand)\nregisterCommand(updatePipelineCommand)\nregisterCommand(deletePipelineCommand)\n\nexport { createPipelineCommand, updatePipelineCommand, deletePipelineCommand }\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -18,6 +18,7 @@ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
18
18
  import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
19
19
  import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
20
20
  import { emitCustomersEvent } from "../events.js";
21
+ import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
21
22
  const tagCrudEvents = {
22
23
  module: "customers",
23
24
  entity: "tag",
@@ -236,9 +237,12 @@ const deleteTagCommand = {
236
237
  if (!tag) throw new CrudHttpError(404, { error: "Tag not found" });
237
238
  ensureTenantScope(ctx, tag.tenantId);
238
239
  ensureOrganizationScope(ctx, tag.organizationId);
239
- await em.nativeDelete(CustomerTagAssignment, { tag });
240
- em.remove(tag);
241
- await em.flush();
240
+ await withAtomicFlush(em, [
241
+ async () => {
242
+ await em.nativeDelete(CustomerTagAssignment, { tag });
243
+ em.remove(tag);
244
+ }
245
+ ], { transaction: true });
242
246
  const de = ctx.container.resolve("dataEngine");
243
247
  await emitCrudSideEffects({
244
248
  dataEngine: de,
@@ -294,7 +298,12 @@ const deleteTagCommand = {
294
298
  tag.color = before.color;
295
299
  tag.description = before.description;
296
300
  }
297
- await em.flush();
301
+ const restoredTag = tag;
302
+ await withAtomicFlush(em, [
303
+ () => {
304
+ em.persist(restoredTag);
305
+ }
306
+ ], { transaction: true });
298
307
  const de = ctx.container.resolve("dataEngine");
299
308
  await emitCrudUndoSideEffects({
300
309
  dataEngine: de,
@@ -411,7 +420,6 @@ const unassignTagCommand = {
411
420
  });
412
421
  if (!existing) throw new CrudHttpError(404, { error: "Tag assignment not found" });
413
422
  await em.remove(existing).flush();
414
- await em.flush();
415
423
  const de = ctx.container.resolve("dataEngine");
416
424
  await emitCrudSideEffects({
417
425
  dataEngine: de,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/commands/tags.ts"],
4
- "sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerTag, CustomerTagAssignment } from '../data/entities'\nimport {\n tagCreateSchema,\n tagUpdateSchema,\n tagAssignmentSchema,\n type TagCreateInput,\n type TagUpdateInput,\n type TagAssignmentInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n requireCustomerEntity,\n ensureSameScope,\n loadEntityTagIds,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { emitCustomersEvent } from '../events'\n\nconst tagCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'tag',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype TagSnapshot = {\n id: string\n organizationId: string\n tenantId: string\n slug: string\n label: string\n color: string | null\n description: string | null\n}\n\ntype TagUndoPayload = {\n before?: TagSnapshot | null\n after?: TagSnapshot | null\n}\n\ntype TagAssignmentSnapshot = {\n tagId: string\n entityId: string\n organizationId: string\n tenantId: string\n}\n\ntype TagAssignmentUndoPayload = {\n before?: TagAssignmentSnapshot | null\n}\n\nasync function loadTagSnapshot(em: EntityManager, id: string): Promise<TagSnapshot | null> {\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) return null\n return {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n slug: tag.slug,\n label: tag.label,\n color: tag.color ?? null,\n description: tag.description ?? null,\n }\n}\n\nconst createTagCommand: CommandHandler<TagCreateInput, { tagId: string }> = {\n id: 'customers.tags.create',\n async execute(rawInput, ctx) {\n const parsed = tagCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n\n const tag = em.create(CustomerTag, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n slug: parsed.slug,\n label: parsed.label,\n color: parsed.color ?? null,\n description: parsed.description ?? null,\n })\n em.persist(tag)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadTagSnapshot(em, result.tagId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTagSnapshot(em, result.tagId)\n return {\n actionLabel: translate('customers.audit.tags.create', 'Create tag'),\n resourceKind: 'customers.tag',\n resourceId: result.tagId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const tagId = logEntry?.resourceId ?? null\n if (!tagId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: tagId })\n if (tag) {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n await em.flush()\n }\n },\n}\n\nconst updateTagCommand: CommandHandler<TagUpdateInput, { tagId: string }> = {\n id: 'customers.tags.update',\n async prepare(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n\n if (parsed.slug !== undefined && parsed.slug !== tag.slug) {\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n id: { $ne: tag.id },\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n tag.slug = parsed.slug\n }\n if (parsed.label !== undefined) tag.label = parsed.label\n if (parsed.color !== undefined) tag.color = parsed.color ?? null\n if (parsed.description !== undefined) tag.description = parsed.description ?? null\n\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const afterSnapshot = await loadTagSnapshot(em, before.id)\n const changes =\n afterSnapshot && before\n ? buildChanges(\n before as unknown as Record<string, unknown>,\n afterSnapshot as unknown as Record<string, unknown>,\n ['slug', 'label', 'color', 'description']\n )\n : {}\n return {\n actionLabel: translate('customers.audit.tags.update', 'Update tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst deleteTagCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { tagId: string }> = {\n id: 'customers.tags.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.tags.delete', 'Delete tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string }> = {\n id: 'customers.tags.assign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.tagId, tenantId: parsed.tenantId, organizationId: parsed.organizationId })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, parsed.organizationId, parsed.tenantId)\n const tagIds = await loadEntityTagIds(em, entity)\n if (tagIds.includes(parsed.tagId)) {\n throw new CrudHttpError(409, { error: 'Tag already assigned' })\n }\n\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n em.persist(assignment)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: assignment,\n identifiers: {\n id: String(assignment.id),\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.assigned', {\n id: String(assignment.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: assignment.id }\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const assignment = await findOneWithDecryption(\n em,\n CustomerTagAssignment,\n { id: result.assignmentId },\n { populate: ['tag', 'entity'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null },\n )\n if (!assignment) return null\n const tagId = typeof assignment.tag === 'string' ? assignment.tag : assignment.tag.id\n const entityId = typeof assignment.entity === 'string' ? assignment.entity : assignment.entity.id\n return {\n actionLabel: translate('customers.audit.tags.assign', 'Assign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: result.assignmentId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n payload: {\n undo: {\n before: {\n tagId,\n entityId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await em.nativeDelete(CustomerTagAssignment, {\n tag: before.tagId,\n entity: before.entityId,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n },\n}\n\nconst unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string | null }> = {\n id: 'customers.tags.unassign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await em.findOne(CustomerTagAssignment, {\n tag: parsed.tagId,\n entity: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n })\n if (!existing) throw new CrudHttpError(404, { error: 'Tag assignment not found' })\n await em.remove(existing).flush()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: existing,\n identifiers: {\n id: String(existing.id),\n organizationId: existing.organizationId,\n tenantId: existing.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.removed', {\n id: String(existing.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: existing.id ?? null }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const parsed = tagAssignmentSchema.parse(input)\n return {\n actionLabel: translate('customers.audit.tags.unassign', 'Unassign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: parsed.tagId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: {\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: before.tagId })\n const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, before.organizationId, before.tenantId)\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const existing = await em.findOne(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n if (!existing) {\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n em.persist(assignment)\n await em.flush()\n }\n },\n}\n\nregisterCommand(createTagCommand)\nregisterCommand(updateTagCommand)\nregisterCommand(deleteTagCommand)\nregisterCommand(assignTagCommand)\nregisterCommand(unassignTagCommand)\n"],
5
- "mappings": "AAAA,SAAS,uBAAuB;AAEhC,SAAS,qBAAqB,yBAAyB,cAAc,iBAAiB;AAGtF,SAAS,aAAa,6BAA6B;AACnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAE9B,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AAEnC,MAAM,gBAAkC;AAAA,EACtC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,gBAAgB,IAAI,YAAY;AAAA,IAChC,UAAU,IAAI,YAAY;AAAA,EAC5B;AACF;AA4BA,eAAe,gBAAgB,IAAmB,IAAyC;AACzF,QAAM,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,GAAG,CAAC;AAChD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,gBAAgB,IAAI;AAAA,IACpB,UAAU,IAAI;AAAA,IACd,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,OAAO,IAAI,SAAS;AAAA,IACpB,aAAa,IAAI,eAAe;AAAA,EAClC;AACF;AAEA,MAAM,mBAAsE;AAAA,EAC1E,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,gBAAgB,MAAM,QAAQ;AAC7C,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAElD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,YAAY,MAAM,GAAG,QAAQ,aAAa;AAAA,MAC9C,MAAM,OAAO;AAAA,MACb,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,QAAI,UAAW,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAEhF,UAAM,MAAM,GAAG,OAAO,aAAa;AAAA,MACjC,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,MACjB,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,MACd,OAAO,OAAO,SAAS;AAAA,MACvB,aAAa,OAAO,eAAe;AAAA,IACrC,CAAC;AACD,OAAG,QAAQ,GAAG;AACd,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,IAAI;AAAA,QACR,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAED,WAAO,EAAE,OAAO,IAAI,GAAG;AAAA,EACzB;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,MAAM,gBAAgB,IAAI,OAAO,KAAK;AAAA,EAC/C;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,IAAI,MAAM;AACnC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,WAAW,MAAM,gBAAgB,IAAI,OAAO,KAAK;AACvD,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,YAAY;AAAA,MAClE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,UAAU,YAAY;AAAA,MAChC,gBAAgB,UAAU,kBAAkB;AAAA,MAC5C,eAAe,YAAY;AAAA,MAC3B,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,OAAO,YAAY;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,QAAQ,UAAU,cAAc;AACtC,QAAI,CAAC,MAAO;AACZ,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,IAAI,MAAM,CAAC;AACvD,QAAI,KAAK;AACP,YAAM,GAAG,aAAa,uBAAuB,EAAE,IAAI,CAAC;AACpD,SAAG,OAAO,GAAG;AACb,YAAM,GAAG,MAAM;AAAA,IACjB;AAAA,EACF;AACF;AAEA,MAAM,mBAAsE;AAAA,EAC1E,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,gBAAgB,MAAM,QAAQ;AAC7C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI;AACtC,UAAM,WAAW,MAAM,gBAAgB,IAAI,OAAO,EAAE;AACpD,WAAO,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA,EACA,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,gBAAgB,MAAM,QAAQ;AAC7C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,IAAI,OAAO,GAAG,CAAC;AAC3D,QAAI,CAAC,IAAK,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,gBAAgB,CAAC;AACjE,sBAAkB,KAAK,IAAI,QAAQ;AACnC,4BAAwB,KAAK,IAAI,cAAc;AAE/C,QAAI,OAAO,SAAS,UAAa,OAAO,SAAS,IAAI,MAAM;AACzD,YAAM,YAAY,MAAM,GAAG,QAAQ,aAAa;AAAA,QAC9C,MAAM,OAAO;AAAA,QACb,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,QACd,IAAI,EAAE,KAAK,IAAI,GAAG;AAAA,MACpB,CAAC;AACD,UAAI,UAAW,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAChF,UAAI,OAAO,OAAO;AAAA,IACpB;AACA,QAAI,OAAO,UAAU,OAAW,KAAI,QAAQ,OAAO;AACnD,QAAI,OAAO,UAAU,OAAW,KAAI,QAAQ,OAAO,SAAS;AAC5D,QAAI,OAAO,gBAAgB,OAAW,KAAI,cAAc,OAAO,eAAe;AAE9E,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,IAAI;AAAA,QACR,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAED,WAAO,EAAE,OAAO,IAAI,GAAG;AAAA,EACzB;AAAA,EACA,UAAU,OAAO,EAAE,WAAW,IAAI,MAAM;AACtC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,gBAAgB,MAAM,gBAAgB,IAAI,OAAO,EAAE;AACzD,UAAM,UACJ,iBAAiB,SACb;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,QAAQ,SAAS,SAAS,aAAa;AAAA,IAC1C,IACA,CAAC;AACP,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,YAAY;AAAA,MAClE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,gBAAgB;AAAA,MAChB,eAAe,iBAAiB;AAAA,MAChC;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACA,OAAO,iBAAiB;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAmC,QAAQ;AAC3D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,IAAI,OAAO,GAAG,CAAC;AACzD,QAAI,CAAC,KAAK;AACR,YAAM,GAAG,OAAO,aAAa;AAAA,QAC3B,IAAI,OAAO;AAAA,QACX,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,QACd,aAAa,OAAO;AAAA,MACtB,CAAC;AACD,SAAG,QAAQ,GAAG;AAAA,IAChB,OAAO;AACL,UAAI,OAAO,OAAO;AAClB,UAAI,QAAQ,OAAO;AACnB,UAAI,QAAQ,OAAO;AACnB,UAAI,cAAc,OAAO;AAAA,IAC3B;AACA,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,wBAAwB;AAAA,MAC5B,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,IAAI;AAAA,QACR,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACF;AAEA,MAAM,mBAA2H;AAAA,EAC/H,IAAI;AAAA,EACJ,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,iBAAiB;AAC7C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI;AACtC,UAAM,WAAW,MAAM,gBAAgB,IAAI,EAAE;AAC7C,WAAO,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA,EACA,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,iBAAiB;AAC7C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,GAAG,CAAC;AAChD,QAAI,CAAC,IAAK,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,gBAAgB,CAAC;AACjE,sBAAkB,KAAK,IAAI,QAAQ;AACnC,4BAAwB,KAAK,IAAI,cAAc;AAC/C,UAAM,GAAG,aAAa,uBAAuB,EAAE,IAAI,CAAC;AACpD,OAAG,OAAO,GAAG;AACb,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,IAAI;AAAA,QACR,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,EAAE,OAAO,IAAI,GAAG;AAAA,EACzB;AAAA,EACA,UAAU,OAAO,EAAE,UAAU,MAAM;AACjC,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,YAAY;AAAA,MAClE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,gBAAgB;AAAA,MAChB,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAmC,QAAQ;AAC3D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,IAAI,OAAO,GAAG,CAAC;AACzD,QAAI,CAAC,KAAK;AACR,YAAM,GAAG,OAAO,aAAa;AAAA,QAC3B,IAAI,OAAO;AAAA,QACX,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,QACd,aAAa,OAAO;AAAA,MACtB,CAAC;AACD,SAAG,QAAQ,GAAG;AAAA,IAChB,OAAO;AACL,UAAI,OAAO,OAAO;AAClB,UAAI,QAAQ,OAAO;AACnB,UAAI,QAAQ,OAAO;AACnB,UAAI,cAAc,OAAO;AAAA,IAC3B;AACA,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,wBAAwB;AAAA,MAC5B,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,IAAI;AAAA,QACR,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACF;AAEA,MAAM,mBAAiF;AAAA,EACrF,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,oBAAoB,MAAM,QAAQ;AACjD,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAElD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AACjE,UAAM,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,IAAI,OAAO,OAAO,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe,CAAC;AAChI,QAAI,CAAC,IAAK,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,gBAAgB,CAAC;AACjE,UAAM,SAAS,MAAM,sBAAsB,IAAI,OAAO,UAAU,QAAW,oBAAoB;AAC/F,oBAAgB,QAAQ,OAAO,gBAAgB,OAAO,QAAQ;AAC9D,UAAM,SAAS,MAAM,iBAAiB,IAAI,MAAM;AAC9C,QAAI,OAAO,SAAS,OAAO,KAAK,GAAG;AACjC,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,uBAAuB,CAAC;AAAA,IAChE;AAEA,UAAM,aAAa,GAAG,OAAO,uBAAuB;AAAA,MAClD;AAAA,MACA;AAAA,MACA,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,IACnB,CAAC;AACD,OAAG,QAAQ,UAAU;AACrB,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,OAAO,WAAW,EAAE;AAAA,QACxB,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,MACnB;AAAA,IACF,CAAC;AAED,UAAM,mBAAmB,0BAA0B;AAAA,MACjD,IAAI,OAAO,WAAW,EAAE;AAAA,MACxB,OAAO,OAAO;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,IACnB,GAAG,EAAE,YAAY,KAAK,CAAC;AAEvB,WAAO,EAAE,cAAc,WAAW,GAAG;AAAA,EACvC;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,IAAI,MAAM;AACnC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,aAAa,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,MACA,EAAE,IAAI,OAAO,aAAa;AAAA,MAC1B,EAAE,UAAU,CAAC,OAAO,QAAQ,EAAE;AAAA,MAC9B,EAAE,UAAU,IAAI,MAAM,YAAY,MAAM,gBAAgB,IAAI,0BAA0B,IAAI,MAAM,SAAS,KAAK;AAAA,IAChH;AACA,QAAI,CAAC,WAAY,QAAO;AACxB,UAAM,QAAQ,OAAO,WAAW,QAAQ,WAAW,WAAW,MAAM,WAAW,IAAI;AACnF,UAAM,WAAW,OAAO,WAAW,WAAW,WAAW,WAAW,SAAS,WAAW,OAAO;AAC/F,WAAO;AAAA,MACL,aAAa,UAAU,+BAA+B,YAAY;AAAA,MAClE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,WAAW;AAAA,MACrB,gBAAgB,WAAW;AAAA,MAC3B,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,QAAQ;AAAA,YACN;AAAA,YACA;AAAA,YACA,UAAU,WAAW;AAAA,YACrB,gBAAgB,WAAW;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAA6C,QAAQ;AACrE,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,GAAG,aAAa,uBAAuB;AAAA,MAC3C,KAAK,OAAO;AAAA,MACZ,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,IACzB,CAAC;AAAA,EACH;AACF;AAEA,MAAM,qBAA0F;AAAA,EAC9F,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,SAAS,oBAAoB,MAAM,QAAQ;AACjD,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAElD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,WAAW,MAAM,GAAG,QAAQ,uBAAuB;AAAA,MACvD,KAAK,OAAO;AAAA,MACZ,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,IACzB,CAAC;AACD,QAAI,CAAC,SAAU,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,2BAA2B,CAAC;AACjF,UAAM,GAAG,OAAO,QAAQ,EAAE,MAAM;AAChC,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,OAAO,SAAS,EAAE;AAAA,QACtB,gBAAgB,SAAS;AAAA,QACzB,UAAU,SAAS;AAAA,MACrB;AAAA,IACF,CAAC;AAED,UAAM,mBAAmB,yBAAyB;AAAA,MAChD,IAAI,OAAO,SAAS,EAAE;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,IACnB,GAAG,EAAE,YAAY,KAAK,CAAC;AAEvB,WAAO,EAAE,cAAc,SAAS,MAAM,KAAK;AAAA,EAC7C;AAAA,EACA,UAAU,OAAO,EAAE,WAAW,MAAM,MAAM;AACxC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,SAAS,oBAAoB,MAAM,KAAK;AAC9C,WAAO;AAAA,MACL,aAAa,UAAU,iCAAiC,cAAc;AAAA,MACtE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,QAAQ;AAAA,YACN,OAAO,OAAO;AAAA,YACd,UAAU,OAAO;AAAA,YACjB,UAAU,OAAO;AAAA,YACjB,gBAAgB,OAAO;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAA6C,QAAQ;AACrE,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,IAAI,OAAO,MAAM,CAAC;AAC9D,UAAM,SAAS,MAAM,sBAAsB,IAAI,OAAO,UAAU,QAAW,oBAAoB;AAC/F,oBAAgB,QAAQ,OAAO,gBAAgB,OAAO,QAAQ;AAC9D,QAAI,CAAC,IAAK,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,gBAAgB,CAAC;AACjE,UAAM,WAAW,MAAM,GAAG,QAAQ,uBAAuB;AAAA,MACvD;AAAA,MACA;AAAA,MACA,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,IACzB,CAAC;AACD,QAAI,CAAC,UAAU;AACb,YAAM,aAAa,GAAG,OAAO,uBAAuB;AAAA,QAClD;AAAA,QACA;AAAA,QACA,UAAU,OAAO;AAAA,QACjB,gBAAgB,OAAO;AAAA,MACzB,CAAC;AACD,SAAG,QAAQ,UAAU;AACrB,YAAM,GAAG,MAAM;AAAA,IACjB;AAAA,EACF;AACF;AAEA,gBAAgB,gBAAgB;AAChC,gBAAgB,gBAAgB;AAChC,gBAAgB,gBAAgB;AAChC,gBAAgB,gBAAgB;AAChC,gBAAgB,kBAAkB;",
4
+ "sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerTag, CustomerTagAssignment } from '../data/entities'\nimport {\n tagCreateSchema,\n tagUpdateSchema,\n tagAssignmentSchema,\n type TagCreateInput,\n type TagUpdateInput,\n type TagAssignmentInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n requireCustomerEntity,\n ensureSameScope,\n loadEntityTagIds,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { emitCustomersEvent } from '../events'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\n\nconst tagCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'tag',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype TagSnapshot = {\n id: string\n organizationId: string\n tenantId: string\n slug: string\n label: string\n color: string | null\n description: string | null\n}\n\ntype TagUndoPayload = {\n before?: TagSnapshot | null\n after?: TagSnapshot | null\n}\n\ntype TagAssignmentSnapshot = {\n tagId: string\n entityId: string\n organizationId: string\n tenantId: string\n}\n\ntype TagAssignmentUndoPayload = {\n before?: TagAssignmentSnapshot | null\n}\n\nasync function loadTagSnapshot(em: EntityManager, id: string): Promise<TagSnapshot | null> {\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) return null\n return {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n slug: tag.slug,\n label: tag.label,\n color: tag.color ?? null,\n description: tag.description ?? null,\n }\n}\n\nconst createTagCommand: CommandHandler<TagCreateInput, { tagId: string }> = {\n id: 'customers.tags.create',\n async execute(rawInput, ctx) {\n const parsed = tagCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n\n const tag = em.create(CustomerTag, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n slug: parsed.slug,\n label: parsed.label,\n color: parsed.color ?? null,\n description: parsed.description ?? null,\n })\n em.persist(tag)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadTagSnapshot(em, result.tagId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTagSnapshot(em, result.tagId)\n return {\n actionLabel: translate('customers.audit.tags.create', 'Create tag'),\n resourceKind: 'customers.tag',\n resourceId: result.tagId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const tagId = logEntry?.resourceId ?? null\n if (!tagId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: tagId })\n if (tag) {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n await em.flush()\n }\n },\n}\n\nconst updateTagCommand: CommandHandler<TagUpdateInput, { tagId: string }> = {\n id: 'customers.tags.update',\n async prepare(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n\n if (parsed.slug !== undefined && parsed.slug !== tag.slug) {\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n id: { $ne: tag.id },\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n tag.slug = parsed.slug\n }\n if (parsed.label !== undefined) tag.label = parsed.label\n if (parsed.color !== undefined) tag.color = parsed.color ?? null\n if (parsed.description !== undefined) tag.description = parsed.description ?? null\n\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const afterSnapshot = await loadTagSnapshot(em, before.id)\n const changes =\n afterSnapshot && before\n ? buildChanges(\n before as unknown as Record<string, unknown>,\n afterSnapshot as unknown as Record<string, unknown>,\n ['slug', 'label', 'color', 'description']\n )\n : {}\n return {\n actionLabel: translate('customers.audit.tags.update', 'Update tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst deleteTagCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { tagId: string }> = {\n id: 'customers.tags.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n await withAtomicFlush(em, [\n async () => {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n },\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.tags.delete', 'Delete tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n const restoredTag = tag\n await withAtomicFlush(em, [\n () => {\n em.persist(restoredTag)\n },\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string }> = {\n id: 'customers.tags.assign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.tagId, tenantId: parsed.tenantId, organizationId: parsed.organizationId })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, parsed.organizationId, parsed.tenantId)\n const tagIds = await loadEntityTagIds(em, entity)\n if (tagIds.includes(parsed.tagId)) {\n throw new CrudHttpError(409, { error: 'Tag already assigned' })\n }\n\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n em.persist(assignment)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: assignment,\n identifiers: {\n id: String(assignment.id),\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.assigned', {\n id: String(assignment.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: assignment.id }\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const assignment = await findOneWithDecryption(\n em,\n CustomerTagAssignment,\n { id: result.assignmentId },\n { populate: ['tag', 'entity'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null },\n )\n if (!assignment) return null\n const tagId = typeof assignment.tag === 'string' ? assignment.tag : assignment.tag.id\n const entityId = typeof assignment.entity === 'string' ? assignment.entity : assignment.entity.id\n return {\n actionLabel: translate('customers.audit.tags.assign', 'Assign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: result.assignmentId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n payload: {\n undo: {\n before: {\n tagId,\n entityId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await em.nativeDelete(CustomerTagAssignment, {\n tag: before.tagId,\n entity: before.entityId,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n },\n}\n\nconst unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string | null }> = {\n id: 'customers.tags.unassign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await em.findOne(CustomerTagAssignment, {\n tag: parsed.tagId,\n entity: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n })\n if (!existing) throw new CrudHttpError(404, { error: 'Tag assignment not found' })\n await em.remove(existing).flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: existing,\n identifiers: {\n id: String(existing.id),\n organizationId: existing.organizationId,\n tenantId: existing.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.removed', {\n id: String(existing.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: existing.id ?? null }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const parsed = tagAssignmentSchema.parse(input)\n return {\n actionLabel: translate('customers.audit.tags.unassign', 'Unassign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: parsed.tagId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: {\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: before.tagId })\n const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, before.organizationId, before.tenantId)\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const existing = await em.findOne(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n if (!existing) {\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n em.persist(assignment)\n await em.flush()\n }\n },\n}\n\nregisterCommand(createTagCommand)\nregisterCommand(updateTagCommand)\nregisterCommand(deleteTagCommand)\nregisterCommand(assignTagCommand)\nregisterCommand(unassignTagCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -109,7 +109,6 @@ async function PUT(req) {
109
109
  if (parsed.data.mode === "inherit") {
110
110
  if (record) {
111
111
  await em.remove(record).flush();
112
- await em.flush();
113
112
  }
114
113
  return NextResponse.json({ ok: true, mode: "inherit", widgetIds: [] });
115
114
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/dashboards/api/users/widgets/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { DashboardUserWidgets } from '@open-mercato/core/modules/dashboards/data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { userWidgetSettingsSchema } from '@open-mercato/core/modules/dashboards/data/validators'\nimport { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'\nimport { resolveAllowedWidgetIds } from '@open-mercato/core/modules/dashboards/lib/access'\nimport { resolveWidgetAssignmentReadScope } from '@open-mercato/core/modules/dashboards/lib/widgetAssignmentScope'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n dashboardsTag,\n dashboardsErrorSchema,\n dashboardUserWidgetsResponseSchema,\n dashboardUserWidgetsUpdateResponseSchema,\n} from '../../openapi'\n\nconst FEATURE = 'dashboards.admin.assign-widgets'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: [FEATURE] },\n PUT: { requireAuth: true, requireFeatures: [FEATURE] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const url = new URL(req.url)\n const userId = url.searchParams.get('userId')\n if (!userId) return NextResponse.json({ error: 'userId is required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as any\n const rbac = container.resolve('rbacService') as any\n const acl = await rbac.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n if (!acl.isSuperAdmin && !hasFeature(acl.features, FEATURE)) {\n return NextResponse.json({ error: 'Forbidden' }, { status: 403 })\n }\n\n const { tenantId, organizationId } = resolveWidgetAssignmentReadScope({\n auth: { tenantId: auth.tenantId ?? null, orgId: auth.orgId ?? null },\n isSuperAdmin: !!acl.isSuperAdmin,\n queryTenantId: url.searchParams.get('tenantId'),\n queryOrganizationId: url.searchParams.get('organizationId'),\n })\n\n const targetUserForRead = await em.findOne(User, { id: userId, deletedAt: null })\n if (!targetUserForRead || (tenantId && (targetUserForRead.tenantId ?? null) !== tenantId)) {\n return NextResponse.json({ error: 'User not found' }, { status: 404 })\n }\n\n const widgets = await loadAllWidgets()\n const targetAcl = await rbac.loadAcl(userId, { tenantId, organizationId })\n const allowed = await resolveAllowedWidgetIds(\n em,\n {\n userId,\n tenantId,\n organizationId,\n features: targetAcl.features ?? [],\n isSuperAdmin: !!targetAcl.isSuperAdmin,\n },\n widgets,\n )\n\n const record = await em.findOne(DashboardUserWidgets, {\n userId,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n const response = {\n mode: record ? record.mode : 'inherit',\n widgetIds: record && record.mode === 'override' ? record.widgetIdsJson : [],\n hasCustom: !!record && record.mode === 'override',\n effectiveWidgetIds: allowed,\n scope: { tenantId, organizationId },\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\n let payload: unknown\n try {\n payload = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n const parsed = userWidgetSettingsSchema.safeParse(payload)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid payload', issues: parsed.error.issues }, { status: 400 })\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as any\n const acl = await rbac.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n if (!acl.isSuperAdmin && !hasFeature(acl.features, FEATURE)) {\n return NextResponse.json({ error: 'Forbidden' }, { status: 403 })\n }\n\n const widgets = await loadAllWidgets()\n const validWidgetIds = new Set(widgets.map((w) => w.metadata.id))\n const widgetIds = parsed.data.widgetIds.filter((id) => validWidgetIds.has(id))\n\n const tenantId = auth.tenantId ?? null\n const organizationId = auth.orgId ?? null\n\n const targetUser = await em.findOne(User, { id: parsed.data.userId, deletedAt: null })\n if (!targetUser || (tenantId && (targetUser.tenantId ?? null) !== tenantId)) {\n return NextResponse.json({ error: 'User not found' }, { status: 404 })\n }\n\n let record = await em.findOne(DashboardUserWidgets, {\n userId: parsed.data.userId,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n if (parsed.data.mode === 'inherit') {\n if (record) {\n await em.remove(record).flush()\n await em.flush()\n }\n return NextResponse.json({ ok: true, mode: 'inherit', widgetIds: [] })\n }\n\n if (!record) {\n record = em.create(DashboardUserWidgets, {\n userId: parsed.data.userId,\n tenantId,\n organizationId,\n mode: 'override',\n widgetIdsJson: widgetIds,\n })\n em.persist(record)\n } else {\n record.mode = 'override'\n record.widgetIdsJson = widgetIds\n }\n await em.flush()\n\n return NextResponse.json({ ok: true, mode: 'override', widgetIds })\n}\n\nconst userWidgetsQuerySchema = z.object({\n userId: z.string().uuid(),\n tenantId: z.string().uuid().optional(),\n organizationId: z.string().uuid().optional(),\n})\n\nconst userWidgetsGetDoc: OpenApiMethodDoc = {\n summary: 'Read widget overrides for a user',\n description: 'Returns the widgets inherited and explicitly configured for the requested user within the current scope.',\n tags: [dashboardsTag],\n query: userWidgetsQuerySchema,\n responses: [\n { status: 200, description: 'Widget settings for the user.', schema: dashboardUserWidgetsResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Missing user identifier', schema: dashboardsErrorSchema },\n { status: 401, description: 'Authentication required', schema: dashboardsErrorSchema },\n { status: 403, description: 'Insufficient permissions to manage user widgets', schema: dashboardsErrorSchema },\n ],\n}\n\nconst userWidgetsPutDoc: OpenApiMethodDoc = {\n summary: 'Update user-specific dashboard widgets',\n description: 'Sets the widget override mode and allowed widgets for a user. Passing `mode: inherit` clears overrides.',\n tags: [dashboardsTag],\n requestBody: {\n contentType: 'application/json',\n schema: userWidgetSettingsSchema,\n description: 'User identifier, override mode, and widget ids. Scope is derived from the authenticated session.',\n },\n responses: [\n { status: 200, description: 'Overrides saved.', schema: dashboardUserWidgetsUpdateResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid payload or unknown widgets', schema: dashboardsErrorSchema },\n { status: 401, description: 'Authentication required', schema: dashboardsErrorSchema },\n { status: 403, description: 'Insufficient permissions to manage user widgets', schema: dashboardsErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: dashboardsTag,\n summary: 'Manage user-level dashboard widgets',\n methods: {\n GET: userWidgetsGetDoc,\n PUT: userWidgetsPutDoc,\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { DashboardUserWidgets } from '@open-mercato/core/modules/dashboards/data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { userWidgetSettingsSchema } from '@open-mercato/core/modules/dashboards/data/validators'\nimport { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'\nimport { resolveAllowedWidgetIds } from '@open-mercato/core/modules/dashboards/lib/access'\nimport { resolveWidgetAssignmentReadScope } from '@open-mercato/core/modules/dashboards/lib/widgetAssignmentScope'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n dashboardsTag,\n dashboardsErrorSchema,\n dashboardUserWidgetsResponseSchema,\n dashboardUserWidgetsUpdateResponseSchema,\n} from '../../openapi'\n\nconst FEATURE = 'dashboards.admin.assign-widgets'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: [FEATURE] },\n PUT: { requireAuth: true, requireFeatures: [FEATURE] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const url = new URL(req.url)\n const userId = url.searchParams.get('userId')\n if (!userId) return NextResponse.json({ error: 'userId is required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as any\n const rbac = container.resolve('rbacService') as any\n const acl = await rbac.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n if (!acl.isSuperAdmin && !hasFeature(acl.features, FEATURE)) {\n return NextResponse.json({ error: 'Forbidden' }, { status: 403 })\n }\n\n const { tenantId, organizationId } = resolveWidgetAssignmentReadScope({\n auth: { tenantId: auth.tenantId ?? null, orgId: auth.orgId ?? null },\n isSuperAdmin: !!acl.isSuperAdmin,\n queryTenantId: url.searchParams.get('tenantId'),\n queryOrganizationId: url.searchParams.get('organizationId'),\n })\n\n const targetUserForRead = await em.findOne(User, { id: userId, deletedAt: null })\n if (!targetUserForRead || (tenantId && (targetUserForRead.tenantId ?? null) !== tenantId)) {\n return NextResponse.json({ error: 'User not found' }, { status: 404 })\n }\n\n const widgets = await loadAllWidgets()\n const targetAcl = await rbac.loadAcl(userId, { tenantId, organizationId })\n const allowed = await resolveAllowedWidgetIds(\n em,\n {\n userId,\n tenantId,\n organizationId,\n features: targetAcl.features ?? [],\n isSuperAdmin: !!targetAcl.isSuperAdmin,\n },\n widgets,\n )\n\n const record = await em.findOne(DashboardUserWidgets, {\n userId,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n const response = {\n mode: record ? record.mode : 'inherit',\n widgetIds: record && record.mode === 'override' ? record.widgetIdsJson : [],\n hasCustom: !!record && record.mode === 'override',\n effectiveWidgetIds: allowed,\n scope: { tenantId, organizationId },\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\n let payload: unknown\n try {\n payload = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n const parsed = userWidgetSettingsSchema.safeParse(payload)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid payload', issues: parsed.error.issues }, { status: 400 })\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as any\n const acl = await rbac.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n if (!acl.isSuperAdmin && !hasFeature(acl.features, FEATURE)) {\n return NextResponse.json({ error: 'Forbidden' }, { status: 403 })\n }\n\n const widgets = await loadAllWidgets()\n const validWidgetIds = new Set(widgets.map((w) => w.metadata.id))\n const widgetIds = parsed.data.widgetIds.filter((id) => validWidgetIds.has(id))\n\n const tenantId = auth.tenantId ?? null\n const organizationId = auth.orgId ?? null\n\n const targetUser = await em.findOne(User, { id: parsed.data.userId, deletedAt: null })\n if (!targetUser || (tenantId && (targetUser.tenantId ?? null) !== tenantId)) {\n return NextResponse.json({ error: 'User not found' }, { status: 404 })\n }\n\n let record = await em.findOne(DashboardUserWidgets, {\n userId: parsed.data.userId,\n tenantId,\n organizationId,\n deletedAt: null,\n })\n\n if (parsed.data.mode === 'inherit') {\n if (record) {\n await em.remove(record).flush()\n }\n return NextResponse.json({ ok: true, mode: 'inherit', widgetIds: [] })\n }\n\n if (!record) {\n record = em.create(DashboardUserWidgets, {\n userId: parsed.data.userId,\n tenantId,\n organizationId,\n mode: 'override',\n widgetIdsJson: widgetIds,\n })\n em.persist(record)\n } else {\n record.mode = 'override'\n record.widgetIdsJson = widgetIds\n }\n await em.flush()\n\n return NextResponse.json({ ok: true, mode: 'override', widgetIds })\n}\n\nconst userWidgetsQuerySchema = z.object({\n userId: z.string().uuid(),\n tenantId: z.string().uuid().optional(),\n organizationId: z.string().uuid().optional(),\n})\n\nconst userWidgetsGetDoc: OpenApiMethodDoc = {\n summary: 'Read widget overrides for a user',\n description: 'Returns the widgets inherited and explicitly configured for the requested user within the current scope.',\n tags: [dashboardsTag],\n query: userWidgetsQuerySchema,\n responses: [\n { status: 200, description: 'Widget settings for the user.', schema: dashboardUserWidgetsResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Missing user identifier', schema: dashboardsErrorSchema },\n { status: 401, description: 'Authentication required', schema: dashboardsErrorSchema },\n { status: 403, description: 'Insufficient permissions to manage user widgets', schema: dashboardsErrorSchema },\n ],\n}\n\nconst userWidgetsPutDoc: OpenApiMethodDoc = {\n summary: 'Update user-specific dashboard widgets',\n description: 'Sets the widget override mode and allowed widgets for a user. Passing `mode: inherit` clears overrides.',\n tags: [dashboardsTag],\n requestBody: {\n contentType: 'application/json',\n schema: userWidgetSettingsSchema,\n description: 'User identifier, override mode, and widget ids. Scope is derived from the authenticated session.',\n },\n responses: [\n { status: 200, description: 'Overrides saved.', schema: dashboardUserWidgetsUpdateResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid payload or unknown widgets', schema: dashboardsErrorSchema },\n { status: 401, description: 'Authentication required', schema: dashboardsErrorSchema },\n { status: 403, description: 'Insufficient permissions to manage user widgets', schema: dashboardsErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: dashboardsTag,\n summary: 'Manage user-level dashboard widgets',\n methods: {\n GET: userWidgetsGetDoc,\n PUT: userWidgetsPutDoc,\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -6,6 +6,7 @@ import {
6
6
  createWidgetDataService,
7
7
  WidgetDataValidationError
8
8
  } from "../../../services/widgetDataService.js";
9
+ import { runApiInterceptorsBefore } from "@open-mercato/shared/lib/crud/interceptor-runner";
9
10
  import { dashboardsTag, dashboardsErrorSchema } from "../../openapi.js";
10
11
  import { widgetDataRequestSchema, widgetDataResponseSchema } from "./schema.js";
11
12
  const metadata = {
@@ -59,10 +60,37 @@ async function POST(req) {
59
60
  if (auth.orgId) return [auth.orgId];
60
61
  return void 0;
61
62
  })();
63
+ const userFeatures = Array.isArray(auth.features) ? auth.features.filter((value) => typeof value === "string") : [];
64
+ const headers = {};
65
+ req.headers.forEach((value, key) => {
66
+ headers[key] = value;
67
+ });
68
+ const interceptorResult = await runApiInterceptorsBefore({
69
+ routePath: "dashboards/widgets/data",
70
+ method: "POST",
71
+ request: {
72
+ method: "POST",
73
+ url: req.url,
74
+ headers,
75
+ body: parsed.data
76
+ },
77
+ context: {
78
+ em,
79
+ container,
80
+ userId: auth.sub ?? "",
81
+ tenantId,
82
+ organizationId: organizationIds?.[0] ?? auth.orgId ?? "",
83
+ userFeatures
84
+ }
85
+ });
86
+ if (!interceptorResult.ok) {
87
+ return NextResponse.json(interceptorResult.body, { status: interceptorResult.statusCode });
88
+ }
89
+ const requestData = interceptorResult.request.body ?? parsed.data;
62
90
  try {
63
91
  const cache = container.resolve("cache");
64
92
  const service = createWidgetDataService(em, { tenantId, organizationIds }, analyticsRegistry, cache);
65
- const result = await service.fetchWidgetData(parsed.data);
93
+ const result = await service.fetchWidgetData(requestData);
66
94
  return NextResponse.json(result);
67
95
  } catch (err) {
68
96
  console.error("[widgets/data] Error:", err);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/dashboards/api/widgets/data/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n createWidgetDataService,\n type WidgetDataRequest,\n WidgetDataValidationError,\n} from '../../../services/widgetDataService'\nimport type { AnalyticsRegistry } from '../../../services/analyticsRegistry'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { dashboardsTag, dashboardsErrorSchema } from '../../openapi'\nimport { widgetDataRequestSchema, widgetDataResponseSchema } from './schema'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['analytics.view'] },\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n const parsed = widgetDataRequestSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n { error: 'Invalid request payload', issues: parsed.error.issues },\n { status: 400 },\n )\n }\n\n const container = await createRequestContainer()\n const analyticsRegistry = container.resolve<AnalyticsRegistry>('analyticsRegistry')\n\n const entityFeatures = analyticsRegistry.getRequiredFeatures(parsed.data.entityType)\n if (entityFeatures && entityFeatures.length > 0) {\n const rbacService = container.resolve<{\n userHasAllFeatures: (\n userId: string,\n features: string[],\n scope: { tenantId: string; organizationId?: string | null },\n ) => Promise<boolean>\n }>('rbacService')\n const hasAccess = await rbacService.userHasAllFeatures(auth.sub, entityFeatures, {\n tenantId: auth.tenantId!,\n organizationId: auth.orgId,\n })\n if (!hasAccess) {\n return NextResponse.json({ error: 'Forbidden' }, { status: 403 })\n }\n }\n\n const em = (container.resolve('em') as EntityManager).fork({\n clear: true,\n freshEventManager: true,\n useContext: true,\n })\n\n const tenantId = auth.tenantId ?? null\n if (!tenantId) {\n return NextResponse.json({ error: 'Tenant context is required' }, { status: 400 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n\n const organizationIds = (() => {\n if (scope?.selectedId) return [scope.selectedId]\n if (Array.isArray(scope?.filterIds) && scope.filterIds.length > 0) return scope.filterIds\n if (scope?.allowedIds === null) return undefined\n if (auth.orgId) return [auth.orgId]\n return undefined\n })()\n\n try {\n const cache = container.resolve<CacheStrategy>('cache')\n const service = createWidgetDataService(em, { tenantId, organizationIds }, analyticsRegistry, cache)\n const result = await service.fetchWidgetData(parsed.data as WidgetDataRequest)\n return NextResponse.json(result)\n } catch (err) {\n console.error('[widgets/data] Error:', err)\n if (err instanceof WidgetDataValidationError) {\n return NextResponse.json({ error: err.message }, { status: 400 })\n }\n return NextResponse.json(\n { error: 'An error occurred while processing your request' },\n { status: 500 },\n )\n }\n}\n\nconst widgetDataPostDoc: OpenApiMethodDoc = {\n summary: 'Fetch aggregated data for dashboard widgets',\n description:\n 'Executes an aggregation query against the specified entity type and returns the result. Supports date range filtering, grouping, and period-over-period comparison.',\n tags: [dashboardsTag],\n requestBody: {\n contentType: 'application/json',\n schema: widgetDataRequestSchema,\n description: 'Widget data request configuration specifying entity type, metric, filters, and grouping.',\n },\n responses: [\n {\n status: 200,\n description: 'Aggregated data for the widget.',\n schema: widgetDataResponseSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Invalid request payload', schema: dashboardsErrorSchema },\n { status: 401, description: 'Authentication required', schema: dashboardsErrorSchema },\n { status: 403, description: 'Missing analytics.view feature', schema: dashboardsErrorSchema },\n { status: 500, description: 'Internal server error', schema: dashboardsErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: dashboardsTag,\n summary: 'Widget data aggregation endpoint',\n methods: {\n POST: widgetDataPostDoc,\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n createWidgetDataService,\n type WidgetDataRequest,\n WidgetDataValidationError,\n} from '../../../services/widgetDataService'\nimport type { AnalyticsRegistry } from '../../../services/analyticsRegistry'\nimport { runApiInterceptorsBefore } from '@open-mercato/shared/lib/crud/interceptor-runner'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { dashboardsTag, dashboardsErrorSchema } from '../../openapi'\nimport { widgetDataRequestSchema, widgetDataResponseSchema } from './schema'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['analytics.view'] },\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n const parsed = widgetDataRequestSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n { error: 'Invalid request payload', issues: parsed.error.issues },\n { status: 400 },\n )\n }\n\n const container = await createRequestContainer()\n const analyticsRegistry = container.resolve<AnalyticsRegistry>('analyticsRegistry')\n\n const entityFeatures = analyticsRegistry.getRequiredFeatures(parsed.data.entityType)\n if (entityFeatures && entityFeatures.length > 0) {\n const rbacService = container.resolve<{\n userHasAllFeatures: (\n userId: string,\n features: string[],\n scope: { tenantId: string; organizationId?: string | null },\n ) => Promise<boolean>\n }>('rbacService')\n const hasAccess = await rbacService.userHasAllFeatures(auth.sub, entityFeatures, {\n tenantId: auth.tenantId!,\n organizationId: auth.orgId,\n })\n if (!hasAccess) {\n return NextResponse.json({ error: 'Forbidden' }, { status: 403 })\n }\n }\n\n const em = (container.resolve('em') as EntityManager).fork({\n clear: true,\n freshEventManager: true,\n useContext: true,\n })\n\n const tenantId = auth.tenantId ?? null\n if (!tenantId) {\n return NextResponse.json({ error: 'Tenant context is required' }, { status: 400 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n\n const organizationIds = (() => {\n if (scope?.selectedId) return [scope.selectedId]\n if (Array.isArray(scope?.filterIds) && scope.filterIds.length > 0) return scope.filterIds\n if (scope?.allowedIds === null) return undefined\n if (auth.orgId) return [auth.orgId]\n return undefined\n })()\n\n const userFeatures = Array.isArray(auth.features)\n ? auth.features.filter((value): value is string => typeof value === 'string')\n : []\n\n const headers: Record<string, string> = {}\n req.headers.forEach((value, key) => {\n headers[key] = value\n })\n\n const interceptorResult = await runApiInterceptorsBefore({\n routePath: 'dashboards/widgets/data',\n method: 'POST',\n request: {\n method: 'POST',\n url: req.url,\n headers,\n body: parsed.data as unknown as Record<string, unknown>,\n },\n context: {\n em,\n container,\n userId: auth.sub ?? '',\n tenantId,\n organizationId: organizationIds?.[0] ?? auth.orgId ?? '',\n userFeatures,\n },\n })\n\n if (!interceptorResult.ok) {\n return NextResponse.json(interceptorResult.body, { status: interceptorResult.statusCode })\n }\n\n const requestData = (interceptorResult.request.body ?? parsed.data) as WidgetDataRequest\n\n try {\n const cache = container.resolve<CacheStrategy>('cache')\n const service = createWidgetDataService(em, { tenantId, organizationIds }, analyticsRegistry, cache)\n const result = await service.fetchWidgetData(requestData)\n return NextResponse.json(result)\n } catch (err) {\n console.error('[widgets/data] Error:', err)\n if (err instanceof WidgetDataValidationError) {\n return NextResponse.json({ error: err.message }, { status: 400 })\n }\n return NextResponse.json(\n { error: 'An error occurred while processing your request' },\n { status: 500 },\n )\n }\n}\n\nconst widgetDataPostDoc: OpenApiMethodDoc = {\n summary: 'Fetch aggregated data for dashboard widgets',\n description:\n 'Executes an aggregation query against the specified entity type and returns the result. Supports date range filtering, grouping, and period-over-period comparison.',\n tags: [dashboardsTag],\n requestBody: {\n contentType: 'application/json',\n schema: widgetDataRequestSchema,\n description: 'Widget data request configuration specifying entity type, metric, filters, and grouping.',\n },\n responses: [\n {\n status: 200,\n description: 'Aggregated data for the widget.',\n schema: widgetDataResponseSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Invalid request payload', schema: dashboardsErrorSchema },\n { status: 401, description: 'Authentication required', schema: dashboardsErrorSchema },\n { status: 403, description: 'Missing analytics.view feature', schema: dashboardsErrorSchema },\n { status: 500, description: 'Internal server error', schema: dashboardsErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: dashboardsTag,\n summary: 'Widget data aggregation endpoint',\n methods: {\n POST: widgetDataPostDoc,\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -347,15 +347,15 @@ function createSyncEngine(deps) {
347
347
  const processedBatchCount = batch.processedCount ?? batch.items.length;
348
348
  processedCount += processedBatchCount;
349
349
  totalCount = batch.totalEstimate ?? totalCount;
350
- await syncRunService.updateCounts(
350
+ await syncRunService.commitBatchProgress(
351
351
  run.id,
352
352
  {
353
353
  ...delta,
354
354
  batchesCompleted: 1
355
355
  },
356
+ batch.cursor,
356
357
  scope
357
358
  );
358
- await syncRunService.updateCursor(run.id, batch.cursor, scope);
359
359
  await updateProgress(run.progressJobId, processedCount, totalCount, scope);
360
360
  await refreshCoverageSnapshots(batch.refreshCoverageEntityTypes, scope);
361
361
  await logImportItemFailures(run.id, run.integrationId, batch.items, scope);
@@ -475,7 +475,7 @@ function createSyncEngine(deps) {
475
475
  }
476
476
  const delta = applyExportCounters(batch);
477
477
  processedCount += delta.processedCount;
478
- await syncRunService.updateCounts(
478
+ await syncRunService.commitBatchProgress(
479
479
  run.id,
480
480
  {
481
481
  createdCount: 0,
@@ -484,9 +484,9 @@ function createSyncEngine(deps) {
484
484
  failedCount: delta.failedCount,
485
485
  batchesCompleted: 1
486
486
  },
487
+ batch.cursor,
487
488
  scope
488
489
  );
489
- await syncRunService.updateCursor(run.id, batch.cursor, scope);
490
490
  await updateProgress(run.progressJobId, processedCount, null, scope);
491
491
  await writeOperationalLog({
492
492
  integrationId: run.integrationId,