@open-mercato/core 0.4.2-canary-ed15f2e753 → 0.4.2-canary-e2aeb1a7bf

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 (711) hide show
  1. package/dist/generated/entities/notification/index.js +57 -0
  2. package/dist/generated/entities/notification/index.js.map +7 -0
  3. package/dist/generated/entities.ids.generated.js +5 -2
  4. package/dist/generated/entities.ids.generated.js.map +2 -2
  5. package/dist/generated/entity-fields-registry.js +2 -2
  6. package/dist/generated/entity-fields-registry.js.map +2 -2
  7. package/dist/modules/api_docs/frontend/docs/api/page.js +3 -2
  8. package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
  9. package/dist/modules/api_keys/backend/api-keys/page.js +1 -1
  10. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  11. package/dist/modules/api_keys/setup.js +11 -0
  12. package/dist/modules/api_keys/setup.js.map +7 -0
  13. package/dist/modules/attachments/components/AttachmentLibrary.js +5 -1
  14. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  15. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +2 -0
  16. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  17. package/dist/modules/attachments/lib/assignmentDetails.js +31 -17
  18. package/dist/modules/attachments/lib/assignmentDetails.js.map +2 -2
  19. package/dist/modules/attachments/lib/partitions.js +3 -3
  20. package/dist/modules/attachments/lib/partitions.js.map +2 -2
  21. package/dist/modules/attachments/setup.js +11 -0
  22. package/dist/modules/attachments/setup.js.map +7 -0
  23. package/dist/modules/audit_logs/setup.js +12 -0
  24. package/dist/modules/audit_logs/setup.js.map +7 -0
  25. package/dist/modules/auth/api/admin/nav.js +4 -3
  26. package/dist/modules/auth/api/admin/nav.js.map +2 -2
  27. package/dist/modules/auth/api/login.js +25 -6
  28. package/dist/modules/auth/api/login.js.map +2 -2
  29. package/dist/modules/auth/api/profile/route.js +157 -0
  30. package/dist/modules/auth/api/profile/route.js.map +7 -0
  31. package/dist/modules/auth/api/reset/confirm.js +25 -2
  32. package/dist/modules/auth/api/reset/confirm.js.map +2 -2
  33. package/dist/modules/auth/api/reset.js +23 -0
  34. package/dist/modules/auth/api/reset.js.map +2 -2
  35. package/dist/modules/auth/api/sidebar/preferences/route.js +14 -9
  36. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  37. package/dist/modules/auth/api/users/route.js +4 -2
  38. package/dist/modules/auth/api/users/route.js.map +2 -2
  39. package/dist/modules/auth/backend/auth/profile/page.js +141 -0
  40. package/dist/modules/auth/backend/auth/profile/page.js.map +7 -0
  41. package/dist/modules/auth/backend/auth/profile/page.meta.js +13 -0
  42. package/dist/modules/auth/backend/auth/profile/page.meta.js.map +7 -0
  43. package/dist/modules/auth/backend/roles/[id]/edit/page.js +4 -1
  44. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  45. package/dist/modules/auth/backend/roles/page.js +3 -3
  46. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  47. package/dist/modules/auth/backend/users/[id]/edit/page.js +18 -3
  48. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  49. package/dist/modules/auth/backend/users/create/page.js +15 -2
  50. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  51. package/dist/modules/auth/backend/users/page.js +3 -3
  52. package/dist/modules/auth/backend/users/page.js.map +2 -2
  53. package/dist/modules/auth/cli.js +25 -11
  54. package/dist/modules/auth/cli.js.map +2 -2
  55. package/dist/modules/auth/commands/users.js +59 -2
  56. package/dist/modules/auth/commands/users.js.map +2 -2
  57. package/dist/modules/auth/data/validators.js +6 -3
  58. package/dist/modules/auth/data/validators.js.map +2 -2
  59. package/dist/modules/auth/frontend/login.js +112 -3
  60. package/dist/modules/auth/frontend/login.js.map +2 -2
  61. package/dist/modules/auth/frontend/reset/[token]/page.js +20 -10
  62. package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
  63. package/dist/modules/auth/lib/setup-app.js +70 -167
  64. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  65. package/dist/modules/auth/notifications.js +112 -0
  66. package/dist/modules/auth/notifications.js.map +7 -0
  67. package/dist/modules/auth/services/authService.js +24 -3
  68. package/dist/modules/auth/services/authService.js.map +2 -2
  69. package/dist/modules/auth/setup.js +11 -0
  70. package/dist/modules/auth/setup.js.map +7 -0
  71. package/dist/modules/business_rules/api/execute/route.js +7 -1
  72. package/dist/modules/business_rules/api/execute/route.js.map +2 -2
  73. package/dist/modules/business_rules/backend/rules/page.js +4 -0
  74. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  75. package/dist/modules/business_rules/backend/sets/page.js +3 -0
  76. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  77. package/dist/modules/business_rules/cli.js +2 -1
  78. package/dist/modules/business_rules/cli.js.map +2 -2
  79. package/dist/modules/business_rules/data/validators.js +0 -34
  80. package/dist/modules/business_rules/data/validators.js.map +2 -2
  81. package/dist/modules/business_rules/index.js +1 -21
  82. package/dist/modules/business_rules/index.js.map +2 -2
  83. package/dist/modules/business_rules/lib/rule-engine.js +34 -185
  84. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  85. package/dist/modules/business_rules/notifications.js +28 -0
  86. package/dist/modules/business_rules/notifications.js.map +7 -0
  87. package/dist/modules/business_rules/setup.js +11 -0
  88. package/dist/modules/business_rules/setup.js.map +7 -0
  89. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +37 -0
  90. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +7 -0
  91. package/dist/modules/catalog/components/PriceKindSettings.js +2 -0
  92. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  93. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -2
  94. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  95. package/dist/modules/catalog/components/products/ProductsDataTable.js +2 -0
  96. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  97. package/dist/modules/catalog/notifications.js +28 -0
  98. package/dist/modules/catalog/notifications.js.map +7 -0
  99. package/dist/modules/catalog/setup.js +22 -0
  100. package/dist/modules/catalog/setup.js.map +7 -0
  101. package/dist/modules/catalog/subscribers/low-stock-notification.js +38 -0
  102. package/dist/modules/catalog/subscribers/low-stock-notification.js.map +7 -0
  103. package/dist/modules/configs/cli.js +6 -0
  104. package/dist/modules/configs/cli.js.map +2 -2
  105. package/dist/modules/configs/components/CachePanel.js +4 -4
  106. package/dist/modules/configs/components/CachePanel.js.map +2 -2
  107. package/dist/modules/configs/lib/system-status.js +48 -1
  108. package/dist/modules/configs/lib/system-status.js.map +2 -2
  109. package/dist/modules/configs/lib/upgrade-actions.js +1 -302
  110. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  111. package/dist/modules/configs/setup.js +16 -0
  112. package/dist/modules/configs/setup.js.map +7 -0
  113. package/dist/modules/currencies/backend/currencies/page.js +3 -0
  114. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  115. package/dist/modules/currencies/backend/exchange-rates/page.js +2 -0
  116. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  117. package/dist/modules/currencies/setup.js +16 -0
  118. package/dist/modules/currencies/setup.js.map +7 -0
  119. package/dist/modules/customers/backend/customers/companies/page.js +3 -0
  120. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  121. package/dist/modules/customers/backend/customers/deals/page.js +3 -0
  122. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  123. package/dist/modules/customers/backend/customers/people/page.js +3 -0
  124. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  125. package/dist/modules/customers/commands/deals.js +31 -0
  126. package/dist/modules/customers/commands/deals.js.map +2 -2
  127. package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
  128. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  129. package/dist/modules/customers/notifications.js +48 -0
  130. package/dist/modules/customers/notifications.js.map +7 -0
  131. package/dist/modules/customers/setup.js +36 -0
  132. package/dist/modules/customers/setup.js.map +7 -0
  133. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js +2 -1
  134. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js.map +2 -2
  135. package/dist/modules/customers/widgets/dashboard/new-customers/widget.js +2 -1
  136. package/dist/modules/customers/widgets/dashboard/new-customers/widget.js.map +2 -2
  137. package/dist/modules/customers/widgets/dashboard/new-deals/widget.js +2 -1
  138. package/dist/modules/customers/widgets/dashboard/new-deals/widget.js.map +2 -2
  139. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js +2 -1
  140. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js.map +2 -2
  141. package/dist/modules/dashboards/cli.js +44 -5
  142. package/dist/modules/dashboards/cli.js.map +2 -2
  143. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +16 -11
  144. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +3 -3
  145. package/dist/modules/dashboards/lib/role-widgets.js +58 -0
  146. package/dist/modules/dashboards/lib/role-widgets.js.map +7 -0
  147. package/dist/modules/dashboards/services/widgetDataService.js +139 -3
  148. package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
  149. package/dist/modules/dashboards/setup.js +27 -0
  150. package/dist/modules/dashboards/setup.js.map +7 -0
  151. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +2 -1
  152. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
  153. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +2 -1
  154. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js.map +2 -2
  155. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js +2 -1
  156. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
  157. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +2 -1
  158. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
  159. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +2 -1
  160. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
  161. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +2 -1
  162. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
  163. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +2 -1
  164. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
  165. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +2 -1
  166. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
  167. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +2 -1
  168. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
  169. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +2 -1
  170. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
  171. package/dist/modules/dictionaries/components/DictionaryTable.js +2 -0
  172. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  173. package/dist/modules/dictionaries/setup.js +12 -0
  174. package/dist/modules/dictionaries/setup.js.map +7 -0
  175. package/dist/modules/directory/api/get/tenants/lookup.js +70 -0
  176. package/dist/modules/directory/api/get/tenants/lookup.js.map +7 -0
  177. package/dist/modules/directory/backend/directory/organizations/page.js +2 -2
  178. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  179. package/dist/modules/directory/backend/directory/tenants/page.js +2 -2
  180. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  181. package/dist/modules/directory/setup.js +12 -0
  182. package/dist/modules/directory/setup.js.map +7 -0
  183. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +2 -2
  184. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  185. package/dist/modules/entities/components/SystemEntitiesTable.js +1 -1
  186. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  187. package/dist/modules/entities/components/UserEntitiesTable.js +2 -2
  188. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  189. package/dist/modules/entities/setup.js +11 -0
  190. package/dist/modules/entities/setup.js.map +7 -0
  191. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +3 -3
  192. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  193. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -1
  194. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  195. package/dist/modules/feature_toggles/setup.js +11 -0
  196. package/dist/modules/feature_toggles/setup.js.map +7 -0
  197. package/dist/modules/notifications/acl.js +11 -0
  198. package/dist/modules/notifications/acl.js.map +7 -0
  199. package/dist/modules/notifications/api/[id]/action/route.js +74 -0
  200. package/dist/modules/notifications/api/[id]/action/route.js.map +7 -0
  201. package/dist/modules/notifications/api/[id]/dismiss/route.js +15 -0
  202. package/dist/modules/notifications/api/[id]/dismiss/route.js.map +7 -0
  203. package/dist/modules/notifications/api/[id]/read/route.js +15 -0
  204. package/dist/modules/notifications/api/[id]/read/route.js.map +7 -0
  205. package/dist/modules/notifications/api/[id]/restore/route.js +53 -0
  206. package/dist/modules/notifications/api/[id]/restore/route.js.map +7 -0
  207. package/dist/modules/notifications/api/batch/route.js +17 -0
  208. package/dist/modules/notifications/api/batch/route.js.map +7 -0
  209. package/dist/modules/notifications/api/feature/route.js +17 -0
  210. package/dist/modules/notifications/api/feature/route.js.map +7 -0
  211. package/dist/modules/notifications/api/mark-all-read/route.js +35 -0
  212. package/dist/modules/notifications/api/mark-all-read/route.js.map +7 -0
  213. package/dist/modules/notifications/api/openapi.js +76 -0
  214. package/dist/modules/notifications/api/openapi.js.map +7 -0
  215. package/dist/modules/notifications/api/role/route.js +17 -0
  216. package/dist/modules/notifications/api/role/route.js.map +7 -0
  217. package/dist/modules/notifications/api/route.js +85 -0
  218. package/dist/modules/notifications/api/route.js.map +7 -0
  219. package/dist/modules/notifications/api/settings/route.js +155 -0
  220. package/dist/modules/notifications/api/settings/route.js.map +7 -0
  221. package/dist/modules/notifications/api/unread-count/route.js +38 -0
  222. package/dist/modules/notifications/api/unread-count/route.js.map +7 -0
  223. package/dist/modules/notifications/backend/config/notifications/page.js +10 -0
  224. package/dist/modules/notifications/backend/config/notifications/page.js.map +7 -0
  225. package/dist/modules/notifications/backend/config/notifications/page.meta.js +24 -0
  226. package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +7 -0
  227. package/dist/modules/notifications/cli.js +16 -0
  228. package/dist/modules/notifications/cli.js.map +7 -0
  229. package/dist/modules/notifications/data/entities.js +112 -0
  230. package/dist/modules/notifications/data/entities.js.map +7 -0
  231. package/dist/modules/notifications/data/validators.js +98 -0
  232. package/dist/modules/notifications/data/validators.js.map +7 -0
  233. package/dist/modules/notifications/di.js +13 -0
  234. package/dist/modules/notifications/di.js.map +7 -0
  235. package/dist/modules/notifications/emails/NotificationEmail.js +58 -0
  236. package/dist/modules/notifications/emails/NotificationEmail.js.map +7 -0
  237. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +44 -0
  238. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +7 -0
  239. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +220 -0
  240. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +7 -0
  241. package/dist/modules/notifications/index.js +14 -0
  242. package/dist/modules/notifications/index.js.map +7 -0
  243. package/dist/modules/notifications/lib/deliveryConfig.js +107 -0
  244. package/dist/modules/notifications/lib/deliveryConfig.js.map +7 -0
  245. package/dist/modules/notifications/lib/deliveryStrategies.js +14 -0
  246. package/dist/modules/notifications/lib/deliveryStrategies.js.map +7 -0
  247. package/dist/modules/notifications/lib/events.js +12 -0
  248. package/dist/modules/notifications/lib/events.js.map +7 -0
  249. package/dist/modules/notifications/lib/notificationBuilder.js +66 -0
  250. package/dist/modules/notifications/lib/notificationBuilder.js.map +7 -0
  251. package/dist/modules/notifications/lib/notificationFactory.js +54 -0
  252. package/dist/modules/notifications/lib/notificationFactory.js.map +7 -0
  253. package/dist/modules/notifications/lib/notificationMapper.js +34 -0
  254. package/dist/modules/notifications/lib/notificationMapper.js.map +7 -0
  255. package/dist/modules/notifications/lib/notificationRecipients.js +35 -0
  256. package/dist/modules/notifications/lib/notificationRecipients.js.map +7 -0
  257. package/dist/modules/notifications/lib/notificationService.js +279 -0
  258. package/dist/modules/notifications/lib/notificationService.js.map +7 -0
  259. package/dist/modules/notifications/lib/routeHelpers.js +101 -0
  260. package/dist/modules/notifications/lib/routeHelpers.js.map +7 -0
  261. package/dist/modules/notifications/lib/safeHref.js +24 -0
  262. package/dist/modules/notifications/lib/safeHref.js.map +7 -0
  263. package/dist/modules/notifications/migrations/Migration20260123000001.js +70 -0
  264. package/dist/modules/notifications/migrations/Migration20260123000001.js.map +7 -0
  265. package/dist/modules/notifications/migrations/Migration20260126150000.js +37 -0
  266. package/dist/modules/notifications/migrations/Migration20260126150000.js.map +7 -0
  267. package/dist/modules/notifications/migrations/Migration20260129082610.js +13 -0
  268. package/dist/modules/notifications/migrations/Migration20260129082610.js.map +7 -0
  269. package/dist/modules/notifications/subscribers/deliver-notification.js +165 -0
  270. package/dist/modules/notifications/subscribers/deliver-notification.js.map +7 -0
  271. package/dist/modules/notifications/workers/create-notification.worker.js +70 -0
  272. package/dist/modules/notifications/workers/create-notification.worker.js.map +7 -0
  273. package/dist/modules/perspectives/setup.js +12 -0
  274. package/dist/modules/perspectives/setup.js.map +7 -0
  275. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +2 -2
  276. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  277. package/dist/modules/planner/setup.js +21 -0
  278. package/dist/modules/planner/setup.js.map +7 -0
  279. package/dist/modules/query_index/cli.js +63 -7
  280. package/dist/modules/query_index/cli.js.map +2 -2
  281. package/dist/modules/query_index/components/QueryIndexesTable.js +7 -1
  282. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  283. package/dist/modules/query_index/setup.js +11 -0
  284. package/dist/modules/query_index/setup.js.map +7 -0
  285. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
  286. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  287. package/dist/modules/resources/backend/resources/resources/page.js +2 -2
  288. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  289. package/dist/modules/resources/setup.js +21 -0
  290. package/dist/modules/resources/setup.js.map +7 -0
  291. package/dist/modules/sales/acl.js +0 -1
  292. package/dist/modules/sales/acl.js.map +2 -2
  293. package/dist/modules/sales/backend/sales/channels/offers/page.js +2 -0
  294. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  295. package/dist/modules/sales/backend/sales/channels/page.js +2 -0
  296. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  297. package/dist/modules/sales/backend/sales/documents/[id]/page.js +0 -12
  298. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  299. package/dist/modules/sales/cli.js +2 -42
  300. package/dist/modules/sales/cli.js.map +2 -2
  301. package/dist/modules/sales/commands/documents.js +53 -62
  302. package/dist/modules/sales/commands/documents.js.map +2 -2
  303. package/dist/modules/sales/commands/payments.js +26 -0
  304. package/dist/modules/sales/commands/payments.js.map +2 -2
  305. package/dist/modules/sales/components/AdjustmentKindSettings.js +2 -2
  306. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  307. package/dist/modules/sales/components/PaymentMethodsSettings.js +2 -2
  308. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  309. package/dist/modules/sales/components/ShippingMethodsSettings.js +2 -2
  310. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  311. package/dist/modules/sales/components/TaxRatesSettings.js +2 -2
  312. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  313. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +2 -0
  314. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  315. package/dist/modules/sales/components/documents/AdjustmentsSection.js +2 -0
  316. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  317. package/dist/modules/sales/components/documents/PaymentsSection.js +2 -1
  318. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  319. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -0
  320. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  321. package/dist/modules/sales/lib/dictionaries.js +0 -3
  322. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  323. package/dist/modules/sales/lib/seeds.js +48 -0
  324. package/dist/modules/sales/lib/seeds.js.map +7 -0
  325. package/dist/modules/sales/notifications.client.js +51 -0
  326. package/dist/modules/sales/notifications.client.js.map +7 -0
  327. package/dist/modules/sales/notifications.js +88 -0
  328. package/dist/modules/sales/notifications.js.map +7 -0
  329. package/dist/modules/sales/setup.js +99 -0
  330. package/dist/modules/sales/setup.js.map +7 -0
  331. package/dist/modules/sales/subscribers/quote-expiring-notification.js +38 -0
  332. package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +7 -0
  333. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +137 -0
  334. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +7 -0
  335. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +137 -0
  336. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +7 -0
  337. package/dist/modules/sales/widgets/notifications/index.js +7 -0
  338. package/dist/modules/sales/widgets/notifications/index.js.map +7 -0
  339. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +60 -0
  340. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +7 -0
  341. package/dist/modules/staff/backend/staff/team-members/page.js +1 -1
  342. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  343. package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
  344. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  345. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +2 -2
  346. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  347. package/dist/modules/staff/backend/staff/teams/page.js +2 -2
  348. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  349. package/dist/modules/staff/commands/leave-requests.js +79 -0
  350. package/dist/modules/staff/commands/leave-requests.js.map +2 -2
  351. package/dist/modules/staff/notifications.js +75 -0
  352. package/dist/modules/staff/notifications.js.map +7 -0
  353. package/dist/modules/staff/setup.js +27 -0
  354. package/dist/modules/staff/setup.js.map +7 -0
  355. package/dist/modules/workflows/acl.js +0 -2
  356. package/dist/modules/workflows/acl.js.map +2 -2
  357. package/dist/modules/workflows/api/instances/route.js +6 -18
  358. package/dist/modules/workflows/api/instances/route.js.map +2 -2
  359. package/dist/modules/workflows/api/tasks/route.js +1 -6
  360. package/dist/modules/workflows/api/tasks/route.js.map +2 -2
  361. package/dist/modules/workflows/backend/definitions/[id]/page.js +1 -9
  362. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  363. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
  364. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
  365. package/dist/modules/workflows/backend/definitions/create/page.js +15 -24
  366. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  367. package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
  368. package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
  369. package/dist/modules/workflows/backend/definitions/page.js +5 -0
  370. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  371. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +132 -150
  372. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  373. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
  374. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
  375. package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
  376. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  377. package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
  378. package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
  379. package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
  380. package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
  381. package/dist/modules/workflows/backend/instances/page.js +3 -0
  382. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  383. package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
  384. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  385. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
  386. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
  387. package/dist/modules/workflows/backend/tasks/page.js +9 -5
  388. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  389. package/dist/modules/workflows/cli.js +15 -93
  390. package/dist/modules/workflows/cli.js.map +3 -3
  391. package/dist/modules/workflows/data/entities.js +1 -64
  392. package/dist/modules/workflows/data/entities.js.map +2 -2
  393. package/dist/modules/workflows/data/validators.js +0 -115
  394. package/dist/modules/workflows/data/validators.js.map +2 -2
  395. package/dist/modules/workflows/examples/checkout-demo-definition.json +5 -1
  396. package/dist/modules/workflows/lib/activity-executor.js +13 -75
  397. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  398. package/dist/modules/workflows/lib/graph-utils.js +2 -71
  399. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  400. package/dist/modules/workflows/lib/seeds.js +7 -36
  401. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  402. package/dist/modules/workflows/lib/start-validator.js +23 -33
  403. package/dist/modules/workflows/lib/start-validator.js.map +2 -2
  404. package/dist/modules/workflows/lib/transition-handler.js +57 -161
  405. package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
  406. package/dist/modules/workflows/migrations/Migration20251207131955.js +76 -72
  407. package/dist/modules/workflows/migrations/Migration20251207131955.js.map +2 -2
  408. package/dist/modules/workflows/notifications.js +28 -0
  409. package/dist/modules/workflows/notifications.js.map +7 -0
  410. package/dist/modules/workflows/setup.js +16 -0
  411. package/dist/modules/workflows/setup.js.map +7 -0
  412. package/dist/modules/workflows/subscribers/task-assigned-notification.js +38 -0
  413. package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +7 -0
  414. package/generated/entities/notification/index.ts +27 -0
  415. package/generated/entities.ids.generated.ts +5 -2
  416. package/generated/entity-fields-registry.ts +2 -2
  417. package/package.json +2 -2
  418. package/src/__tests__/module-decoupling.test.ts +356 -0
  419. package/src/modules/api_docs/frontend/docs/api/page.tsx +3 -2
  420. package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
  421. package/src/modules/api_keys/setup.ts +9 -0
  422. package/src/modules/attachments/components/AttachmentLibrary.tsx +6 -2
  423. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +2 -0
  424. package/src/modules/attachments/lib/assignmentDetails.ts +32 -16
  425. package/src/modules/attachments/lib/partitions.ts +3 -3
  426. package/src/modules/attachments/setup.ts +9 -0
  427. package/src/modules/audit_logs/setup.ts +10 -0
  428. package/src/modules/auth/README.md +1 -1
  429. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +31 -1
  430. package/src/modules/auth/api/__tests__/login.test.ts +2 -0
  431. package/src/modules/auth/api/admin/nav.ts +10 -6
  432. package/src/modules/auth/api/login.ts +26 -7
  433. package/src/modules/auth/api/profile/route.ts +163 -0
  434. package/src/modules/auth/api/reset/confirm.ts +25 -2
  435. package/src/modules/auth/api/reset.ts +23 -0
  436. package/src/modules/auth/api/sidebar/preferences/route.ts +21 -12
  437. package/src/modules/auth/api/users/route.ts +5 -2
  438. package/src/modules/auth/backend/auth/profile/page.meta.ts +9 -0
  439. package/src/modules/auth/backend/auth/profile/page.tsx +174 -0
  440. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +4 -1
  441. package/src/modules/auth/backend/roles/page.tsx +3 -3
  442. package/src/modules/auth/backend/users/[id]/edit/page.tsx +22 -3
  443. package/src/modules/auth/backend/users/create/page.tsx +19 -2
  444. package/src/modules/auth/backend/users/page.tsx +3 -3
  445. package/src/modules/auth/cli.ts +38 -11
  446. package/src/modules/auth/commands/users.ts +73 -2
  447. package/src/modules/auth/data/validators.ts +6 -2
  448. package/src/modules/auth/frontend/login.tsx +134 -5
  449. package/src/modules/auth/frontend/reset/[token]/page.tsx +24 -11
  450. package/src/modules/auth/i18n/de.json +48 -1
  451. package/src/modules/auth/i18n/en.json +48 -1
  452. package/src/modules/auth/i18n/es.json +48 -1
  453. package/src/modules/auth/i18n/pl.json +48 -1
  454. package/src/modules/auth/lib/setup-app.ts +97 -186
  455. package/src/modules/auth/notifications.ts +109 -0
  456. package/src/modules/auth/services/authService.ts +27 -4
  457. package/src/modules/auth/setup.ts +9 -0
  458. package/src/modules/business_rules/api/execute/route.ts +8 -1
  459. package/src/modules/business_rules/backend/rules/page.tsx +4 -0
  460. package/src/modules/business_rules/backend/sets/page.tsx +3 -0
  461. package/src/modules/business_rules/cli.ts +2 -1
  462. package/src/modules/business_rules/data/validators.ts +0 -40
  463. package/src/modules/business_rules/i18n/en.json +3 -1
  464. package/src/modules/business_rules/index.ts +0 -25
  465. package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +51 -0
  466. package/src/modules/business_rules/lib/rule-engine.ts +51 -277
  467. package/src/modules/business_rules/notifications.ts +25 -0
  468. package/src/modules/business_rules/setup.ts +9 -0
  469. package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +50 -0
  470. package/src/modules/catalog/components/PriceKindSettings.tsx +2 -0
  471. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
  472. package/src/modules/catalog/components/products/ProductsDataTable.tsx +2 -0
  473. package/src/modules/catalog/i18n/en.json +3 -1
  474. package/src/modules/catalog/notifications.ts +25 -0
  475. package/src/modules/catalog/setup.ts +22 -0
  476. package/src/modules/catalog/subscribers/low-stock-notification.ts +52 -0
  477. package/src/modules/configs/cli.ts +6 -0
  478. package/src/modules/configs/components/CachePanel.tsx +4 -4
  479. package/src/modules/configs/i18n/en.json +12 -2
  480. package/src/modules/configs/i18n/pl.json +12 -2
  481. package/src/modules/configs/lib/system-status.ts +48 -1
  482. package/src/modules/configs/lib/system-status.types.ts +1 -0
  483. package/src/modules/configs/lib/upgrade-actions.ts +5 -338
  484. package/src/modules/configs/setup.ts +14 -0
  485. package/src/modules/currencies/backend/currencies/page.tsx +3 -0
  486. package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -0
  487. package/src/modules/currencies/setup.ts +15 -0
  488. package/src/modules/customers/backend/customers/companies/page.tsx +3 -0
  489. package/src/modules/customers/backend/customers/deals/page.tsx +3 -0
  490. package/src/modules/customers/backend/customers/people/page.tsx +3 -0
  491. package/src/modules/customers/commands/deals.ts +39 -0
  492. package/src/modules/customers/components/CustomerTodosTable.tsx +1 -0
  493. package/src/modules/customers/i18n/en.json +5 -1
  494. package/src/modules/customers/notifications.ts +44 -0
  495. package/src/modules/customers/setup.ts +36 -0
  496. package/src/modules/customers/widgets/dashboard/customer-todos/widget.ts +2 -2
  497. package/src/modules/customers/widgets/dashboard/new-customers/widget.ts +2 -2
  498. package/src/modules/customers/widgets/dashboard/new-deals/widget.ts +2 -2
  499. package/src/modules/customers/widgets/dashboard/next-interactions/widget.ts +2 -2
  500. package/src/modules/dashboards/cli.ts +55 -5
  501. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +22 -11
  502. package/src/modules/dashboards/lib/role-widgets.ts +80 -0
  503. package/src/modules/dashboards/services/widgetDataService.ts +164 -4
  504. package/src/modules/dashboards/setup.ts +26 -0
  505. package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.ts +2 -2
  506. package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.ts +2 -2
  507. package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.ts +2 -2
  508. package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.ts +2 -2
  509. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
  510. package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.ts +2 -2
  511. package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.ts +2 -2
  512. package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.ts +2 -2
  513. package/src/modules/dashboards/widgets/dashboard/top-customers/widget.ts +2 -2
  514. package/src/modules/dashboards/widgets/dashboard/top-products/widget.ts +2 -2
  515. package/src/modules/dictionaries/components/DictionaryTable.tsx +2 -0
  516. package/src/modules/dictionaries/setup.ts +10 -0
  517. package/src/modules/directory/api/get/tenants/lookup.ts +75 -0
  518. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -2
  519. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -2
  520. package/src/modules/directory/setup.ts +10 -0
  521. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -2
  522. package/src/modules/entities/components/SystemEntitiesTable.tsx +1 -1
  523. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -2
  524. package/src/modules/entities/setup.ts +9 -0
  525. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +3 -4
  526. package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
  527. package/src/modules/feature_toggles/setup.ts +9 -0
  528. package/src/modules/notifications/__tests__/deliver-notification.test.ts +195 -0
  529. package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +19 -0
  530. package/src/modules/notifications/__tests__/notificationService.test.ts +208 -0
  531. package/src/modules/notifications/acl.ts +7 -0
  532. package/src/modules/notifications/api/[id]/action/route.ts +75 -0
  533. package/src/modules/notifications/api/[id]/dismiss/route.ts +12 -0
  534. package/src/modules/notifications/api/[id]/read/route.ts +12 -0
  535. package/src/modules/notifications/api/[id]/restore/route.ts +53 -0
  536. package/src/modules/notifications/api/batch/route.ts +14 -0
  537. package/src/modules/notifications/api/feature/route.ts +14 -0
  538. package/src/modules/notifications/api/mark-all-read/route.ts +34 -0
  539. package/src/modules/notifications/api/openapi.ts +76 -0
  540. package/src/modules/notifications/api/role/route.ts +14 -0
  541. package/src/modules/notifications/api/route.ts +92 -0
  542. package/src/modules/notifications/api/settings/route.ts +157 -0
  543. package/src/modules/notifications/api/unread-count/route.ts +38 -0
  544. package/src/modules/notifications/backend/config/notifications/page.meta.ts +22 -0
  545. package/src/modules/notifications/backend/config/notifications/page.tsx +12 -0
  546. package/src/modules/notifications/cli.ts +18 -0
  547. package/src/modules/notifications/data/entities.ts +99 -0
  548. package/src/modules/notifications/data/validators.ts +115 -0
  549. package/src/modules/notifications/di.ts +11 -0
  550. package/src/modules/notifications/emails/NotificationEmail.tsx +98 -0
  551. package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +42 -0
  552. package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +233 -0
  553. package/src/modules/notifications/i18n/de.json +50 -0
  554. package/src/modules/notifications/i18n/en.json +50 -0
  555. package/src/modules/notifications/i18n/es.json +50 -0
  556. package/src/modules/notifications/i18n/pl.json +50 -0
  557. package/src/modules/notifications/index.ts +12 -0
  558. package/src/modules/notifications/lib/deliveryConfig.ts +153 -0
  559. package/src/modules/notifications/lib/deliveryStrategies.ts +50 -0
  560. package/src/modules/notifications/lib/events.ts +48 -0
  561. package/src/modules/notifications/lib/notificationBuilder.ts +121 -0
  562. package/src/modules/notifications/lib/notificationFactory.ts +76 -0
  563. package/src/modules/notifications/lib/notificationMapper.ts +33 -0
  564. package/src/modules/notifications/lib/notificationRecipients.ts +83 -0
  565. package/src/modules/notifications/lib/notificationService.ts +414 -0
  566. package/src/modules/notifications/lib/routeHelpers.ts +151 -0
  567. package/src/modules/notifications/lib/safeHref.ts +29 -0
  568. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +336 -0
  569. package/src/modules/notifications/migrations/Migration20260123000001.ts +73 -0
  570. package/src/modules/notifications/migrations/Migration20260126150000.ts +39 -0
  571. package/src/modules/notifications/migrations/Migration20260129082610.ts +13 -0
  572. package/src/modules/notifications/subscribers/deliver-notification.ts +204 -0
  573. package/src/modules/notifications/workers/create-notification.worker.ts +122 -0
  574. package/src/modules/perspectives/setup.ts +10 -0
  575. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
  576. package/src/modules/planner/setup.ts +21 -0
  577. package/src/modules/query_index/cli.ts +82 -13
  578. package/src/modules/query_index/components/QueryIndexesTable.tsx +8 -2
  579. package/src/modules/query_index/setup.ts +9 -0
  580. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -2
  581. package/src/modules/resources/backend/resources/resources/page.tsx +2 -2
  582. package/src/modules/resources/setup.ts +21 -0
  583. package/src/modules/sales/acl.ts +0 -1
  584. package/src/modules/sales/backend/sales/channels/offers/page.tsx +2 -0
  585. package/src/modules/sales/backend/sales/channels/page.tsx +2 -0
  586. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +0 -16
  587. package/src/modules/sales/cli.ts +2 -43
  588. package/src/modules/sales/commands/documents.ts +62 -70
  589. package/src/modules/sales/commands/payments.ts +33 -0
  590. package/src/modules/sales/components/AdjustmentKindSettings.tsx +2 -2
  591. package/src/modules/sales/components/PaymentMethodsSettings.tsx +2 -2
  592. package/src/modules/sales/components/ShippingMethodsSettings.tsx +2 -2
  593. package/src/modules/sales/components/TaxRatesSettings.tsx +2 -2
  594. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +2 -0
  595. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +2 -0
  596. package/src/modules/sales/components/documents/PaymentsSection.tsx +2 -1
  597. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -0
  598. package/src/modules/sales/i18n/de.json +20 -0
  599. package/src/modules/sales/i18n/en.json +25 -1
  600. package/src/modules/sales/i18n/es.json +20 -0
  601. package/src/modules/sales/i18n/pl.json +20 -0
  602. package/src/modules/sales/lib/dictionaries.ts +0 -3
  603. package/src/modules/sales/lib/seeds.ts +53 -0
  604. package/src/modules/sales/notifications.client.ts +65 -0
  605. package/src/modules/sales/notifications.ts +82 -0
  606. package/src/modules/sales/setup.ts +108 -0
  607. package/src/modules/sales/subscribers/quote-expiring-notification.ts +53 -0
  608. package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +156 -0
  609. package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +156 -0
  610. package/src/modules/sales/widgets/notifications/index.ts +2 -0
  611. package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +81 -0
  612. package/src/modules/staff/backend/staff/team-members/page.tsx +1 -1
  613. package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
  614. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -2
  615. package/src/modules/staff/backend/staff/teams/page.tsx +2 -2
  616. package/src/modules/staff/commands/leave-requests.ts +94 -0
  617. package/src/modules/staff/i18n/de.json +4 -0
  618. package/src/modules/staff/i18n/en.json +9 -1
  619. package/src/modules/staff/i18n/es.json +4 -0
  620. package/src/modules/staff/i18n/pl.json +4 -0
  621. package/src/modules/staff/notifications.ts +71 -0
  622. package/src/modules/staff/setup.ts +27 -0
  623. package/src/modules/workflows/acl.ts +0 -2
  624. package/src/modules/workflows/api/__tests__/instances.route.test.ts +2 -5
  625. package/src/modules/workflows/api/instances/route.ts +7 -21
  626. package/src/modules/workflows/api/tasks/route.ts +1 -7
  627. package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
  628. package/src/modules/workflows/backend/definitions/[id]/page.tsx +0 -9
  629. package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
  630. package/src/modules/workflows/backend/definitions/create/page.tsx +0 -9
  631. package/src/modules/workflows/backend/definitions/page.tsx +5 -0
  632. package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
  633. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +3 -21
  634. package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
  635. package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
  636. package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
  637. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  638. package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
  639. package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
  640. package/src/modules/workflows/backend/tasks/page.tsx +10 -6
  641. package/src/modules/workflows/cli.ts +12 -123
  642. package/src/modules/workflows/data/entities.ts +0 -124
  643. package/src/modules/workflows/data/validators.ts +0 -138
  644. package/src/modules/workflows/examples/checkout-demo-definition.json +5 -1
  645. package/src/modules/workflows/i18n/en.json +3 -72
  646. package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +36 -43
  647. package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +90 -170
  648. package/src/modules/workflows/lib/activity-executor.ts +16 -129
  649. package/src/modules/workflows/lib/graph-utils.ts +2 -117
  650. package/src/modules/workflows/lib/seeds.ts +12 -50
  651. package/src/modules/workflows/lib/start-validator.ts +28 -38
  652. package/src/modules/workflows/lib/transition-handler.ts +71 -212
  653. package/src/modules/workflows/migrations/Migration20251207131955.ts +77 -143
  654. package/src/modules/workflows/notifications.ts +25 -0
  655. package/src/modules/workflows/setup.ts +15 -0
  656. package/src/modules/workflows/subscribers/task-assigned-notification.ts +53 -0
  657. package/dist/generated/entities/workflow_event_trigger/index.js +0 -33
  658. package/dist/generated/entities/workflow_event_trigger/index.js.map +0 -7
  659. package/dist/modules/auth/events.js +0 -30
  660. package/dist/modules/auth/events.js.map +0 -7
  661. package/dist/modules/business_rules/api/execute/[ruleId]/route.js +0 -145
  662. package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +0 -7
  663. package/dist/modules/catalog/events.js +0 -34
  664. package/dist/modules/catalog/events.js.map +0 -7
  665. package/dist/modules/customers/events.js +0 -49
  666. package/dist/modules/customers/events.js.map +0 -7
  667. package/dist/modules/directory/events.js +0 -23
  668. package/dist/modules/directory/events.js.map +0 -7
  669. package/dist/modules/sales/events.js +0 -63
  670. package/dist/modules/sales/events.js.map +0 -7
  671. package/dist/modules/sales/lib/frontend/documentDataEvents.js +0 -25
  672. package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +0 -7
  673. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +0 -481
  674. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +0 -7
  675. package/dist/modules/workflows/components/EventTriggersEditor.js +0 -553
  676. package/dist/modules/workflows/components/EventTriggersEditor.js.map +0 -7
  677. package/dist/modules/workflows/events.js +0 -38
  678. package/dist/modules/workflows/events.js.map +0 -7
  679. package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
  680. package/dist/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  681. package/dist/modules/workflows/lib/event-trigger-service.js +0 -308
  682. package/dist/modules/workflows/lib/event-trigger-service.js.map +0 -7
  683. package/dist/modules/workflows/migrations/Migration20260123143500.js +0 -36
  684. package/dist/modules/workflows/migrations/Migration20260123143500.js.map +0 -7
  685. package/dist/modules/workflows/subscribers/event-trigger.js +0 -78
  686. package/dist/modules/workflows/subscribers/event-trigger.js.map +0 -7
  687. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +0 -323
  688. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +0 -7
  689. package/dist/modules/workflows/widgets/injection/order-approval/widget.js +0 -17
  690. package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +0 -7
  691. package/dist/modules/workflows/widgets/injection-table.js +0 -19
  692. package/dist/modules/workflows/widgets/injection-table.js.map +0 -7
  693. package/generated/entities/workflow_event_trigger/index.ts +0 -15
  694. package/src/modules/auth/events.ts +0 -39
  695. package/src/modules/business_rules/api/execute/[ruleId]/route.ts +0 -163
  696. package/src/modules/catalog/events.ts +0 -45
  697. package/src/modules/customers/events.ts +0 -63
  698. package/src/modules/directory/events.ts +0 -31
  699. package/src/modules/sales/events.ts +0 -82
  700. package/src/modules/sales/lib/frontend/documentDataEvents.ts +0 -28
  701. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +0 -581
  702. package/src/modules/workflows/components/EventTriggersEditor.tsx +0 -664
  703. package/src/modules/workflows/events.ts +0 -49
  704. package/src/modules/workflows/examples/order-approval-definition.json +0 -257
  705. package/src/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  706. package/src/modules/workflows/lib/event-trigger-service.ts +0 -557
  707. package/src/modules/workflows/migrations/Migration20260123143500.ts +0 -38
  708. package/src/modules/workflows/subscribers/event-trigger.ts +0 -109
  709. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +0 -446
  710. package/src/modules/workflows/widgets/injection/order-approval/widget.ts +0 -16
  711. package/src/modules/workflows/widgets/injection-table.ts +0 -21
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/lib/assignmentDetails.ts"],
4
- "sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { AttachmentAssignment } from './metadata'\nimport type { CustomEntitySpec } from '@open-mercato/shared/modules/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\n\ntype AssignmentLinkSpec = {\n labelFields?: string[]\n extraFields?: string[]\n buildHref?: (record: Record<string, unknown>) => string | null | undefined\n}\n\nlet _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null\n\nfunction getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {\n if (_entityLinkSpecsCache) return _entityLinkSpecsCache\n const E = getEntityIds() as any\n _entityLinkSpecsCache = {\n [E.catalog.catalog_product]: {\n labelFields: ['title', 'sku', 'handle'],\n buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),\n },\n [E.catalog.catalog_product_variant]: {\n labelFields: ['name', 'sku'],\n extraFields: ['product_id'],\n buildHref: (record) => {\n const productId = readRecordValue(record, 'product_id')\n if (!productId) return null\n return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`\n },\n },\n [E.customers.customer_entity]: {\n labelFields: ['display_name'],\n extraFields: ['kind'],\n buildHref: (record) => {\n const kind = String(readRecordValue(record, 'kind') || '').toLowerCase()\n if (kind === 'company') return buildSimpleHref('/backend/customers/companies', record.id)\n if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)\n return null\n },\n },\n [E.customers.customer_person_profile]: {\n labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],\n extraFields: ['entity_id', 'first_name', 'last_name'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null\n },\n },\n [E.customers.customer_company_profile]: {\n labelFields: ['brand_name', 'display_name', 'legal_name'],\n extraFields: ['entity_id'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null\n },\n },\n [E.customers.customer_deal]: {\n labelFields: ['title'],\n buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),\n },\n [E.sales.sales_channel]: {\n labelFields: ['name', 'title'],\n buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),\n },\n }\n return _entityLinkSpecsCache\n}\n\nconst LIBRARY_ENTITY_ID = 'attachments:library'\nconst DEFAULT_LABEL_FIELDS = [\n 'label',\n 'title',\n 'name',\n 'display_name',\n 'displayName',\n 'subject',\n 'sku',\n 'handle',\n 'order_number',\n 'quote_number',\n 'invoice_number',\n 'email',\n 'company_name',\n 'legal_name',\n 'brand_name',\n]\n\nlet entitySpecsPromise: Promise<Map<string, CustomEntitySpec>> | null = null\n\nasync function loadEntitySpecs(): Promise<Map<string, CustomEntitySpec>> {\n if (!entitySpecsPromise) {\n entitySpecsPromise = Promise.resolve()\n .then(() => {\n const map = new Map<string, CustomEntitySpec>()\n const mods = getModules()\n for (const mod of mods) {\n const specs = ((mod as any).customEntities as CustomEntitySpec[] | undefined) ?? []\n for (const spec of specs) {\n if (spec?.id && !map.has(spec.id)) {\n map.set(spec.id, spec)\n }\n }\n }\n return map\n })\n .catch(() => new Map<string, CustomEntitySpec>())\n }\n return entitySpecsPromise\n}\n\nexport type AssignmentEnrichment = {\n label?: string\n href?: string\n}\n\nexport type AssignmentEnrichmentMap = Map<string, AssignmentEnrichment>\n\nfunction camelToSnake(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toLowerCase()\n}\n\nfunction snakeToCamel(value: string): string {\n return value.replace(/[_-](\\w)/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction normalizeValue(value: unknown): string | null {\n if (value === undefined || value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n return null\n}\n\nfunction readRecordValue(record: Record<string, unknown>, field: string): string | null {\n if (!field) return null\n if (record[field] !== undefined) return normalizeValue(record[field])\n const snake = camelToSnake(field)\n if (snake !== field && record[snake] !== undefined) return normalizeValue(record[snake])\n const camel = snakeToCamel(field)\n if (camel !== field && record[camel] !== undefined) return normalizeValue(record[camel])\n return null\n}\n\nfunction buildSimpleHref(base: string, idValue: unknown, suffix: string = ''): string | null {\n const id = normalizeValue(idValue)\n if (!id) return null\n return `${base}/${encodeURIComponent(id)}${suffix}`\n}\n\nfunction isUuid(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim())\n}\n\nfunction filterIdsForEntity(entityId: string, ids: string[]): string[] {\n const E = getEntityIds() as any\n if (entityId === E.catalog.catalog_product_variant || entityId === E.catalog.catalog_product) {\n return ids.filter((id) => isUuid(id))\n }\n return ids\n}\n\nfunction resolveLabelCandidates(entityId: string, linkSpec: AssignmentLinkSpec | undefined, entitySpecs: Map<string, CustomEntitySpec>): string[] {\n const candidates = new Set<string>()\n const spec = entitySpecs.get(entityId)\n if (spec?.labelField) {\n candidates.add(spec.labelField)\n candidates.add(camelToSnake(spec.labelField))\n }\n for (const field of linkSpec?.labelFields ?? []) {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n }\n DEFAULT_LABEL_FIELDS.forEach((field) => {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n })\n return Array.from(candidates).filter((field) => field.length > 0)\n}\n\nfunction buildLabel(\n record: Record<string, unknown>,\n entityId: string,\n linkSpec: AssignmentLinkSpec | undefined,\n entitySpecs: Map<string, CustomEntitySpec>\n): string | null {\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n for (const candidate of candidates) {\n const value = readRecordValue(record, candidate)\n if (value) return value\n }\n const fullName = [readRecordValue(record, 'first_name'), readRecordValue(record, 'last_name')]\n .filter((part): part is string => Boolean(part))\n .join(' ')\n .trim()\n if (fullName.length) return fullName\n return null\n}\n\nexport async function resolveAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n opts: { queryEngine?: QueryEngine | null; tenantId: string; organizationId: string },\n): Promise<AssignmentEnrichmentMap> {\n const map: AssignmentEnrichmentMap = new Map()\n if (!assignments.length || !opts.queryEngine) return map\n const entitySpecs = await loadEntitySpecs()\n const grouped = new Map<string, Set<string>>()\n for (const assignment of assignments) {\n if (!assignment || assignment.type === LIBRARY_ENTITY_ID) continue\n const type = assignment.type?.trim()\n const id = assignment.id?.trim()\n if (!type || !id) continue\n if (!grouped.has(type)) grouped.set(type, new Set())\n grouped.get(type)!.add(id)\n }\n if (!grouped.size) return map\n\n const entityLinkSpecs = getEntityLinkSpecs()\n for (const [entityId, idsSet] of grouped.entries()) {\n const ids = filterIdsForEntity(entityId, Array.from(idsSet.values()))\n if (!ids.length) continue\n const linkSpec = entityLinkSpecs[entityId]\n const fields = new Set<string>(['id'])\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n candidates.forEach((field) => fields.add(field))\n for (const extra of linkSpec?.extraFields ?? []) {\n fields.add(extra)\n fields.add(camelToSnake(extra))\n }\n try {\n const result = await opts.queryEngine.query(entityId as any, {\n fields: Array.from(fields),\n filters: { id: ids.length === 1 ? { $eq: ids[0] } : { $in: ids } },\n tenantId: opts.tenantId,\n organizationId: opts.organizationId,\n page: { pageSize: Math.max(ids.length, 20) },\n })\n for (const record of result.items ?? []) {\n const recordId = normalizeValue((record as Record<string, unknown>).id)\n if (!recordId) continue\n const label = buildLabel(record as Record<string, unknown>, entityId, linkSpec, entitySpecs)\n const href = linkSpec?.buildHref?.(record as Record<string, unknown>) ?? null\n if (label || href) {\n map.set(`${entityId}:${recordId}`, {\n label: label ?? undefined,\n href: href ?? undefined,\n })\n }\n }\n } catch (error) {\n console.warn('[attachments] Failed to resolve assignment details for', entityId, error)\n }\n }\n return map\n}\n\nexport function applyAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n enrichments: AssignmentEnrichmentMap,\n): AttachmentAssignment[] {\n if (!enrichments.size) return assignments\n return assignments.map((assignment) => {\n if (!assignment || !assignment.type || !assignment.id) return assignment\n const key = `${assignment.type}:${assignment.id}`\n const detail = enrichments.get(key)\n if (!detail) return assignment\n const next: AttachmentAssignment = { ...assignment }\n if (!next.label && detail.label) next.label = detail.label\n if (!next.href && detail.href) next.href = detail.href\n return next\n })\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { AttachmentAssignment } from './metadata'\nimport type { CustomEntitySpec } from '@open-mercato/shared/modules/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\n\ntype AssignmentLinkSpec = {\n labelFields?: string[]\n extraFields?: string[]\n buildHref?: (record: Record<string, unknown>) => string | null | undefined\n}\n\nlet _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null\n\nfunction getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {\n if (_entityLinkSpecsCache) return _entityLinkSpecsCache\n const E = getEntityIds() as any\n const specs: Record<string, AssignmentLinkSpec> = {}\n\n if (E.catalog?.catalog_product) {\n specs[E.catalog.catalog_product] = {\n labelFields: ['title', 'sku', 'handle'],\n buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),\n }\n }\n if (E.catalog?.catalog_product_variant) {\n specs[E.catalog.catalog_product_variant] = {\n labelFields: ['name', 'sku'],\n extraFields: ['product_id'],\n buildHref: (record) => {\n const productId = readRecordValue(record, 'product_id')\n if (!productId) return null\n return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`\n },\n }\n }\n if (E.customers?.customer_entity) {\n specs[E.customers.customer_entity] = {\n labelFields: ['display_name'],\n extraFields: ['kind'],\n buildHref: (record) => {\n const kind = String(readRecordValue(record, 'kind') || '').toLowerCase()\n if (kind === 'company') return buildSimpleHref('/backend/customers/companies', record.id)\n if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)\n return null\n },\n }\n }\n if (E.customers?.customer_person_profile) {\n specs[E.customers.customer_person_profile] = {\n labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],\n extraFields: ['entity_id', 'first_name', 'last_name'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null\n },\n }\n }\n if (E.customers?.customer_company_profile) {\n specs[E.customers.customer_company_profile] = {\n labelFields: ['brand_name', 'display_name', 'legal_name'],\n extraFields: ['entity_id'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null\n },\n }\n }\n if (E.customers?.customer_deal) {\n specs[E.customers.customer_deal] = {\n labelFields: ['title'],\n buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),\n }\n }\n if (E.sales?.sales_channel) {\n specs[E.sales.sales_channel] = {\n labelFields: ['name', 'title'],\n buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),\n }\n }\n\n _entityLinkSpecsCache = specs\n return _entityLinkSpecsCache\n}\n\nconst LIBRARY_ENTITY_ID = 'attachments:library'\nconst DEFAULT_LABEL_FIELDS = [\n 'label',\n 'title',\n 'name',\n 'display_name',\n 'displayName',\n 'subject',\n 'sku',\n 'handle',\n 'order_number',\n 'quote_number',\n 'invoice_number',\n 'email',\n 'company_name',\n 'legal_name',\n 'brand_name',\n]\n\nlet entitySpecsPromise: Promise<Map<string, CustomEntitySpec>> | null = null\n\nasync function loadEntitySpecs(): Promise<Map<string, CustomEntitySpec>> {\n if (!entitySpecsPromise) {\n entitySpecsPromise = Promise.resolve()\n .then(() => {\n const map = new Map<string, CustomEntitySpec>()\n const mods = getModules()\n for (const mod of mods) {\n const specs = ((mod as any).customEntities as CustomEntitySpec[] | undefined) ?? []\n for (const spec of specs) {\n if (spec?.id && !map.has(spec.id)) {\n map.set(spec.id, spec)\n }\n }\n }\n return map\n })\n .catch(() => new Map<string, CustomEntitySpec>())\n }\n return entitySpecsPromise\n}\n\nexport type AssignmentEnrichment = {\n label?: string\n href?: string\n}\n\nexport type AssignmentEnrichmentMap = Map<string, AssignmentEnrichment>\n\nfunction camelToSnake(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toLowerCase()\n}\n\nfunction snakeToCamel(value: string): string {\n return value.replace(/[_-](\\w)/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction normalizeValue(value: unknown): string | null {\n if (value === undefined || value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n return null\n}\n\nfunction readRecordValue(record: Record<string, unknown>, field: string): string | null {\n if (!field) return null\n if (record[field] !== undefined) return normalizeValue(record[field])\n const snake = camelToSnake(field)\n if (snake !== field && record[snake] !== undefined) return normalizeValue(record[snake])\n const camel = snakeToCamel(field)\n if (camel !== field && record[camel] !== undefined) return normalizeValue(record[camel])\n return null\n}\n\nfunction buildSimpleHref(base: string, idValue: unknown, suffix: string = ''): string | null {\n const id = normalizeValue(idValue)\n if (!id) return null\n return `${base}/${encodeURIComponent(id)}${suffix}`\n}\n\nfunction isUuid(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim())\n}\n\nfunction filterIdsForEntity(entityId: string, ids: string[]): string[] {\n const E = getEntityIds() as any\n if (entityId === E.catalog?.catalog_product_variant || entityId === E.catalog?.catalog_product) {\n return ids.filter((id) => isUuid(id))\n }\n return ids\n}\n\nfunction resolveLabelCandidates(entityId: string, linkSpec: AssignmentLinkSpec | undefined, entitySpecs: Map<string, CustomEntitySpec>): string[] {\n const candidates = new Set<string>()\n const spec = entitySpecs.get(entityId)\n if (spec?.labelField) {\n candidates.add(spec.labelField)\n candidates.add(camelToSnake(spec.labelField))\n }\n for (const field of linkSpec?.labelFields ?? []) {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n }\n DEFAULT_LABEL_FIELDS.forEach((field) => {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n })\n return Array.from(candidates).filter((field) => field.length > 0)\n}\n\nfunction buildLabel(\n record: Record<string, unknown>,\n entityId: string,\n linkSpec: AssignmentLinkSpec | undefined,\n entitySpecs: Map<string, CustomEntitySpec>\n): string | null {\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n for (const candidate of candidates) {\n const value = readRecordValue(record, candidate)\n if (value) return value\n }\n const fullName = [readRecordValue(record, 'first_name'), readRecordValue(record, 'last_name')]\n .filter((part): part is string => Boolean(part))\n .join(' ')\n .trim()\n if (fullName.length) return fullName\n return null\n}\n\nexport async function resolveAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n opts: { queryEngine?: QueryEngine | null; tenantId: string; organizationId: string },\n): Promise<AssignmentEnrichmentMap> {\n const map: AssignmentEnrichmentMap = new Map()\n if (!assignments.length || !opts.queryEngine) return map\n const entitySpecs = await loadEntitySpecs()\n const grouped = new Map<string, Set<string>>()\n for (const assignment of assignments) {\n if (!assignment || assignment.type === LIBRARY_ENTITY_ID) continue\n const type = assignment.type?.trim()\n const id = assignment.id?.trim()\n if (!type || !id) continue\n if (!grouped.has(type)) grouped.set(type, new Set())\n grouped.get(type)!.add(id)\n }\n if (!grouped.size) return map\n\n const entityLinkSpecs = getEntityLinkSpecs()\n for (const [entityId, idsSet] of grouped.entries()) {\n const ids = filterIdsForEntity(entityId, Array.from(idsSet.values()))\n if (!ids.length) continue\n const linkSpec = entityLinkSpecs[entityId]\n const fields = new Set<string>(['id'])\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n candidates.forEach((field) => fields.add(field))\n for (const extra of linkSpec?.extraFields ?? []) {\n fields.add(extra)\n fields.add(camelToSnake(extra))\n }\n try {\n const result = await opts.queryEngine.query(entityId as any, {\n fields: Array.from(fields),\n filters: { id: ids.length === 1 ? { $eq: ids[0] } : { $in: ids } },\n tenantId: opts.tenantId,\n organizationId: opts.organizationId,\n page: { pageSize: Math.max(ids.length, 20) },\n })\n for (const record of result.items ?? []) {\n const recordId = normalizeValue((record as Record<string, unknown>).id)\n if (!recordId) continue\n const label = buildLabel(record as Record<string, unknown>, entityId, linkSpec, entitySpecs)\n const href = linkSpec?.buildHref?.(record as Record<string, unknown>) ?? null\n if (label || href) {\n map.set(`${entityId}:${recordId}`, {\n label: label ?? undefined,\n href: href ?? undefined,\n })\n }\n }\n } catch (error) {\n console.warn('[attachments] Failed to resolve assignment details for', entityId, error)\n }\n }\n return map\n}\n\nexport function applyAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n enrichments: AssignmentEnrichmentMap,\n): AttachmentAssignment[] {\n if (!enrichments.size) return assignments\n return assignments.map((assignment) => {\n if (!assignment || !assignment.type || !assignment.id) return assignment\n const key = `${assignment.type}:${assignment.id}`\n const detail = enrichments.get(key)\n if (!detail) return assignment\n const next: AttachmentAssignment = { ...assignment }\n if (!next.label && detail.label) next.label = detail.label\n if (!next.href && detail.href) next.href = detail.href\n return next\n })\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -16,9 +16,9 @@ const DEFAULT_ATTACHMENT_PARTITIONS = [
16
16
  isPublic: false
17
17
  }
18
18
  ];
19
- const PRODUCT_MEDIA_ENTITY_IDS = /* @__PURE__ */ new Set([
20
- E.catalog.catalog_product
21
- ]);
19
+ const PRODUCT_MEDIA_ENTITY_IDS = new Set(
20
+ [E.catalog?.catalog_product].filter(Boolean)
21
+ );
22
22
  const FALLBACK_PARTITION = "privateAttachments";
23
23
  function resolveDefaultPartitionCode(entityId) {
24
24
  if (!entityId) return FALLBACK_PARTITION;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/lib/partitions.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { AttachmentPartition } from '../data/entities'\nimport { resolveDefaultAttachmentOcrEnabled } from './ocrConfig'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { E } from '#generated/entities.ids.generated'\n\nexport type AttachmentPartitionSeed = {\n code: string\n title: string\n description?: string | null\n isPublic?: boolean\n}\n\nexport const DEFAULT_ATTACHMENT_PARTITIONS: AttachmentPartitionSeed[] = [\n {\n code: 'productsMedia',\n title: 'Products media',\n description: 'Public media uploaded for catalog products.',\n isPublic: true,\n },\n {\n code: 'privateAttachments',\n title: 'Private attachments',\n description: 'Internal attachments scoped to tenants and organizations.',\n isPublic: false,\n },\n]\n\nconst PRODUCT_MEDIA_ENTITY_IDS = new Set<string>([\n E.catalog.catalog_product,\n])\n\nconst FALLBACK_PARTITION = 'privateAttachments'\n\nexport function resolveDefaultPartitionCode(entityId: string | null | undefined): string {\n if (!entityId) return FALLBACK_PARTITION\n if (PRODUCT_MEDIA_ENTITY_IDS.has(entityId)) return 'productsMedia'\n return FALLBACK_PARTITION\n}\n\nexport async function ensureDefaultPartitions(em: EntityManager): Promise<void> {\n const repo = em.getRepository(AttachmentPartition)\n const existing = await repo.findAll({ fields: ['code'] })\n const existingCodes = new Set(existing.map((entry) => entry.code))\n const pending = DEFAULT_ATTACHMENT_PARTITIONS.filter((seed) => !existingCodes.has(seed.code))\n if (!pending.length) return\n for (const seed of pending) {\n const record = repo.create({\n code: seed.code,\n title: seed.title,\n description: seed.description ?? null,\n storageDriver: 'local',\n isPublic: seed.isPublic ?? false,\n requiresOcr: resolveDefaultAttachmentOcrEnabled(),\n })\n em.persist(record)\n }\n await em.flush()\n}\n\nexport function sanitizePartitionCode(input: string): string {\n const trimmed = input.trim()\n const normalized = trimmed.replace(/[^a-zA-Z0-9_-]/g, '')\n return normalized\n}\n\nexport function isPartitionSettingsLocked(): boolean {\n const demoModeParsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n const demoModeEnabled = demoModeParsed === false ? false : true\n const onboardingEnabled = parseBooleanToken(process.env.SELF_SERVICE_ONBOARDING_ENABLED ?? '') === true\n return demoModeEnabled || onboardingEnabled\n}\n"],
5
- "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,0CAA0C;AACnD,SAAS,yBAAyB;AAClC,SAAS,SAAS;AASX,MAAM,gCAA2D;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AACF;AAEA,MAAM,2BAA2B,oBAAI,IAAY;AAAA,EAC/C,EAAE,QAAQ;AACZ,CAAC;AAED,MAAM,qBAAqB;AAEpB,SAAS,4BAA4B,UAA6C;AACvF,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,yBAAyB,IAAI,QAAQ,EAAG,QAAO;AACnD,SAAO;AACT;AAEA,eAAsB,wBAAwB,IAAkC;AAC9E,QAAM,OAAO,GAAG,cAAc,mBAAmB;AACjD,QAAM,WAAW,MAAM,KAAK,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AACxD,QAAM,gBAAgB,IAAI,IAAI,SAAS,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AACjE,QAAM,UAAU,8BAA8B,OAAO,CAAC,SAAS,CAAC,cAAc,IAAI,KAAK,IAAI,CAAC;AAC5F,MAAI,CAAC,QAAQ,OAAQ;AACrB,aAAW,QAAQ,SAAS;AAC1B,UAAM,SAAS,KAAK,OAAO;AAAA,MACzB,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe;AAAA,MACf,UAAU,KAAK,YAAY;AAAA,MAC3B,aAAa,mCAAmC;AAAA,IAClD,CAAC;AACD,OAAG,QAAQ,MAAM;AAAA,EACnB;AACA,QAAM,GAAG,MAAM;AACjB;AAEO,SAAS,sBAAsB,OAAuB;AAC3D,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,aAAa,QAAQ,QAAQ,mBAAmB,EAAE;AACxD,SAAO;AACT;AAEO,SAAS,4BAAqC;AACnD,QAAM,iBAAiB,kBAAkB,QAAQ,IAAI,aAAa,EAAE;AACpE,QAAM,kBAAkB,mBAAmB,QAAQ,QAAQ;AAC3D,QAAM,oBAAoB,kBAAkB,QAAQ,IAAI,mCAAmC,EAAE,MAAM;AACnG,SAAO,mBAAmB;AAC5B;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { AttachmentPartition } from '../data/entities'\nimport { resolveDefaultAttachmentOcrEnabled } from './ocrConfig'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { E } from '#generated/entities.ids.generated'\n\nexport type AttachmentPartitionSeed = {\n code: string\n title: string\n description?: string | null\n isPublic?: boolean\n}\n\nexport const DEFAULT_ATTACHMENT_PARTITIONS: AttachmentPartitionSeed[] = [\n {\n code: 'productsMedia',\n title: 'Products media',\n description: 'Public media uploaded for catalog products.',\n isPublic: true,\n },\n {\n code: 'privateAttachments',\n title: 'Private attachments',\n description: 'Internal attachments scoped to tenants and organizations.',\n isPublic: false,\n },\n]\n\nconst PRODUCT_MEDIA_ENTITY_IDS = new Set<string>(\n [(E as any).catalog?.catalog_product].filter(Boolean) as string[]\n)\n\nconst FALLBACK_PARTITION = 'privateAttachments'\n\nexport function resolveDefaultPartitionCode(entityId: string | null | undefined): string {\n if (!entityId) return FALLBACK_PARTITION\n if (PRODUCT_MEDIA_ENTITY_IDS.has(entityId)) return 'productsMedia'\n return FALLBACK_PARTITION\n}\n\nexport async function ensureDefaultPartitions(em: EntityManager): Promise<void> {\n const repo = em.getRepository(AttachmentPartition)\n const existing = await repo.findAll({ fields: ['code'] })\n const existingCodes = new Set(existing.map((entry) => entry.code))\n const pending = DEFAULT_ATTACHMENT_PARTITIONS.filter((seed) => !existingCodes.has(seed.code))\n if (!pending.length) return\n for (const seed of pending) {\n const record = repo.create({\n code: seed.code,\n title: seed.title,\n description: seed.description ?? null,\n storageDriver: 'local',\n isPublic: seed.isPublic ?? false,\n requiresOcr: resolveDefaultAttachmentOcrEnabled(),\n })\n em.persist(record)\n }\n await em.flush()\n}\n\nexport function sanitizePartitionCode(input: string): string {\n const trimmed = input.trim()\n const normalized = trimmed.replace(/[^a-zA-Z0-9_-]/g, '')\n return normalized\n}\n\nexport function isPartitionSettingsLocked(): boolean {\n const demoModeParsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n const demoModeEnabled = demoModeParsed === false ? false : true\n const onboardingEnabled = parseBooleanToken(process.env.SELF_SERVICE_ONBOARDING_ENABLED ?? '') === true\n return demoModeEnabled || onboardingEnabled\n}\n"],
5
+ "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,0CAA0C;AACnD,SAAS,yBAAyB;AAClC,SAAS,SAAS;AASX,MAAM,gCAA2D;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AACF;AAEA,MAAM,2BAA2B,IAAI;AAAA,EACnC,CAAE,EAAU,SAAS,eAAe,EAAE,OAAO,OAAO;AACtD;AAEA,MAAM,qBAAqB;AAEpB,SAAS,4BAA4B,UAA6C;AACvF,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,yBAAyB,IAAI,QAAQ,EAAG,QAAO;AACnD,SAAO;AACT;AAEA,eAAsB,wBAAwB,IAAkC;AAC9E,QAAM,OAAO,GAAG,cAAc,mBAAmB;AACjD,QAAM,WAAW,MAAM,KAAK,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AACxD,QAAM,gBAAgB,IAAI,IAAI,SAAS,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AACjE,QAAM,UAAU,8BAA8B,OAAO,CAAC,SAAS,CAAC,cAAc,IAAI,KAAK,IAAI,CAAC;AAC5F,MAAI,CAAC,QAAQ,OAAQ;AACrB,aAAW,QAAQ,SAAS;AAC1B,UAAM,SAAS,KAAK,OAAO;AAAA,MACzB,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe;AAAA,MACf,UAAU,KAAK,YAAY;AAAA,MAC3B,aAAa,mCAAmC;AAAA,IAClD,CAAC;AACD,OAAG,QAAQ,MAAM;AAAA,EACnB;AACA,QAAM,GAAG,MAAM;AACjB;AAEO,SAAS,sBAAsB,OAAuB;AAC3D,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,aAAa,QAAQ,QAAQ,mBAAmB,EAAE;AACxD,SAAO;AACT;AAEO,SAAS,4BAAqC;AACnD,QAAM,iBAAiB,kBAAkB,QAAQ,IAAI,aAAa,EAAE;AACpE,QAAM,kBAAkB,mBAAmB,QAAQ,QAAQ;AAC3D,QAAM,oBAAoB,kBAAkB,QAAQ,IAAI,mCAAmC,EAAE,MAAM;AACnG,SAAO,mBAAmB;AAC5B;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,11 @@
1
+ const setup = {
2
+ defaultRoleFeatures: {
3
+ admin: ["attachments.*", "attachments.view", "attachments.manage"]
4
+ }
5
+ };
6
+ var setup_default = setup;
7
+ export {
8
+ setup_default as default,
9
+ setup
10
+ };
11
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/attachments/setup.ts"],
4
+ "sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n admin: ['attachments.*', 'attachments.view', 'attachments.manage'],\n },\n}\n\nexport default setup\n"],
5
+ "mappings": "AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,OAAO,CAAC,iBAAiB,oBAAoB,oBAAoB;AAAA,EACnE;AACF;AAEA,IAAO,gBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,12 @@
1
+ const setup = {
2
+ defaultRoleFeatures: {
3
+ admin: ["audit_logs.*"],
4
+ employee: ["audit_logs.undo_self"]
5
+ }
6
+ };
7
+ var setup_default = setup;
8
+ export {
9
+ setup_default as default,
10
+ setup
11
+ };
12
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/audit_logs/setup.ts"],
4
+ "sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n admin: ['audit_logs.*'],\n employee: ['audit_logs.undo_self'],\n },\n}\n\nexport default setup\n"],
5
+ "mappings": "AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,OAAO,CAAC,cAAc;AAAA,IACtB,UAAU,CAAC,sBAAsB;AAAA,EACnC;AACF;AAEA,IAAO,gBAAQ;",
6
+ "names": []
7
+ }
@@ -232,12 +232,13 @@ async function GET(req) {
232
232
  }
233
233
  const groupsWithRole = rolePreference ? applySidebarPreference(groups, rolePreference) : groups;
234
234
  const baseForUser = adoptSidebarDefaults(groupsWithRole);
235
- const preference = await loadSidebarPreference(em, {
236
- userId: auth.sub,
235
+ const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub;
236
+ const preference = effectiveUserId ? await loadSidebarPreference(em, {
237
+ userId: effectiveUserId,
237
238
  tenantId: auth.tenantId ?? null,
238
239
  organizationId: auth.orgId ?? null,
239
240
  locale
240
- });
241
+ }) : null;
241
242
  const withPreference = applySidebarPreference(baseForUser, preference);
242
243
  const payload = {
243
244
  groups: withPreference.map((group) => ({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/auth/api/admin/nav.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { z } from 'zod'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { hasAllFeatures } from '@open-mercato/shared/security/features'\nimport { CustomEntity } from '@open-mercato/core/modules/entities/data/entities'\nimport { slugifySidebarId } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\nimport { applySidebarPreference, loadFirstRoleSidebarPreference, loadSidebarPreference } from '../../services/sidebarPreferencesService'\nimport { Role } from '../../data/entities'\n\nexport const metadata = {\n GET: { requireAuth: true },\n}\n\nconst sidebarNavItemSchema: z.ZodType<{ href: string; title: string; defaultTitle: string; enabled: boolean; hidden?: boolean; children?: any[] }> = z.lazy(() =>\n z.object({\n href: z.string(),\n title: z.string(),\n defaultTitle: z.string(),\n enabled: z.boolean(),\n hidden: z.boolean().optional(),\n children: z.array(sidebarNavItemSchema).optional(),\n })\n)\n\nconst adminNavResponseSchema = z.object({\n groups: z.array(\n z.object({\n id: z.string(),\n name: z.string(),\n defaultName: z.string(),\n items: z.array(sidebarNavItemSchema),\n })\n ),\n})\n\nconst adminNavErrorSchema = z.object({\n error: z.string(),\n})\n\ntype SidebarItemNode = {\n href: string\n title: string\n defaultTitle: string\n enabled: boolean\n hidden?: boolean\n children?: SidebarItemNode[]\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 { translate, locale } = await resolveTranslations()\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as any\n const cache = resolve('cache') as any\n\n // Cache key is user + tenant + organization scoped\n const cacheKey = `nav:sidebar:${locale}:${auth.sub}:${auth.tenantId || 'null'}:${auth.orgId || 'null'}`\n // try {\n // if (cache) {\n // const cached = await cache.get(cacheKey)\n // if (cached) return NextResponse.json(cached)\n // }\n // } catch {}\n\n // Load ACL once; we'll evaluate features locally without multiple calls\n const acl = await rbac.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n\n // Build nav entries from discovered backend routes\n type Entry = {\n groupId: string\n groupName: string\n groupKey?: string\n title: string\n titleKey?: string\n href: string\n enabled: boolean\n order?: number\n priority?: number\n children?: Entry[]\n }\n const entries: Entry[] = []\n\n function capitalize(s: string) { return s.charAt(0).toUpperCase() + s.slice(1) }\n function deriveTitleFromPath(p: string) {\n const seg = p.split('/').filter(Boolean).pop() || ''\n return seg ? seg.split('-').map(capitalize).join(' ') : 'Home'\n }\n\n const ctx = { auth: { roles: auth.roles || [], sub: auth.sub, tenantId: auth.tenantId, orgId: auth.orgId } }\n const modules = getModules()\n for (const m of (modules as any[])) {\n const groupDefault = capitalize(m.id)\n for (const r of (m.backendRoutes || [])) {\n const href = (r.pattern ?? r.path ?? '') as string\n if (!href || href.includes('[')) continue\n if ((r as any).navHidden) continue\n const title = (r.title as string) || deriveTitleFromPath(href)\n const titleKey = (r as any).pageTitleKey ?? (r as any).titleKey\n const groupName = (r.group as string) || groupDefault\n const groupKey = (r as any).pageGroupKey ?? (r as any).groupKey\n const groupId = typeof groupKey === 'string' && groupKey ? groupKey : slugifySidebarId(groupName)\n const visible = r.visible ? await Promise.resolve(r.visible(ctx)) : true\n if (!visible) continue\n const enabled = r.enabled ? await Promise.resolve(r.enabled(ctx)) : true\n const requiredRoles = (r.requireRoles as string[]) || []\n if (requiredRoles.length) {\n const roles = auth.roles || []\n const ok = requiredRoles.some((role) => roles.includes(role))\n if (!ok) continue\n }\n const features = (r as any).requireFeatures as string[] | undefined\n if (!acl.isSuperAdmin && !hasAllFeatures(acl.features, features)) continue\n const order = (r as any).order as number | undefined\n const priority = ((r as any).priority as number | undefined) ?? order\n entries.push({ groupId, groupName, groupKey, title, titleKey, href, enabled, order, priority })\n }\n }\n\n // Parent-child relationships within the same group by href prefix\n const roots: any[] = []\n for (const e of entries) {\n let parent: any | undefined\n for (const p of entries) {\n if (p === e) continue\n if (p.groupId !== e.groupId) continue\n if (!e.href.startsWith(p.href + '/')) continue\n if (!parent || p.href.length > parent.href.length) parent = p\n }\n if (parent) {\n ;(parent as any).children = (parent as any).children || []\n ;(parent as any).children.push(e)\n } else {\n roots.push(e)\n }\n }\n\n // Add dynamic user entities into Data designer > User Entities\n const where: any = { isActive: true, showInSidebar: true }\n where.$and = [\n { $or: [ { organizationId: auth.orgId ?? undefined as any }, { organizationId: null } ] },\n { $or: [ { tenantId: auth.tenantId ?? undefined as any }, { tenantId: null } ] },\n ]\n try {\n const entities = await em.find(CustomEntity as any, where as any, { orderBy: { label: 'asc' } as any })\n const items = (entities as any[]).map((e) => ({\n entityId: e.entityId,\n label: e.label,\n href: `/backend/entities/user/${encodeURIComponent(e.entityId)}/records`\n }))\n if (items.length) {\n const dd = roots.find((it: Entry) => it.groupKey === 'entities.nav.group' && it.titleKey === 'entities.nav.userEntities')\n if (dd) {\n const existing = dd.children || []\n const dynamic = items.map((it) => ({\n groupId: dd.groupId,\n groupName: dd.groupName,\n groupKey: dd.groupKey,\n title: it.label,\n href: it.href,\n enabled: true,\n order: 1000,\n priority: 1000,\n }))\n const byHref = new Map<string, Entry>()\n for (const c of existing) if (!byHref.has(c.href)) byHref.set(c.href, c)\n for (const c of dynamic) if (!byHref.has(c.href)) byHref.set(c.href, c)\n dd.children = Array.from(byHref.values())\n }\n }\n } catch (e) {\n console.error('Error loading user entities', e)\n }\n\n // Sort roots and children\n const sortItems = (arr: any[]) => {\n arr.sort((a, b) => {\n if (a.group !== b.group) return a.group.localeCompare(b.group)\n const ap = a.priority ?? a.order ?? 10000\n const bp = b.priority ?? b.order ?? 10000\n if (ap !== bp) return ap - bp\n return String(a.title).localeCompare(String(b.title))\n })\n for (const it of arr) if (it.children?.length) sortItems(it.children)\n }\n sortItems(roots)\n\n // Group into sidebar groups\n type GroupBucket = {\n id: string\n rawName: string\n key?: string\n weight: number\n entries: Entry[]\n }\n\n const groupBuckets = new Map<string, GroupBucket>()\n for (const entry of roots) {\n const weight = entry.priority ?? entry.order ?? 10_000\n if (!groupBuckets.has(entry.groupId)) {\n groupBuckets.set(entry.groupId, {\n id: entry.groupId,\n rawName: entry.groupName,\n key: entry.groupKey as string | undefined,\n weight,\n entries: [entry],\n })\n } else {\n const bucket = groupBuckets.get(entry.groupId)!\n bucket.entries.push(entry)\n if (weight < bucket.weight) bucket.weight = weight\n if (!bucket.key && entry.groupKey) bucket.key = entry.groupKey as string\n if (!bucket.rawName && entry.groupName) bucket.rawName = entry.groupName\n }\n }\n\n const toItem = (entry: Entry): SidebarItemNode => {\n const defaultTitle = entry.titleKey ? translate(entry.titleKey, entry.title) : entry.title\n return {\n href: entry.href,\n title: defaultTitle,\n defaultTitle,\n enabled: entry.enabled,\n children: entry.children?.map((child) => toItem(child)),\n }\n }\n\n const groups = Array.from(groupBuckets.values()).map((bucket) => {\n const defaultName = bucket.key ? translate(bucket.key, bucket.rawName) : bucket.rawName\n return {\n id: bucket.id,\n key: bucket.key,\n name: defaultName,\n defaultName,\n weight: bucket.weight,\n items: bucket.entries.map((entry) => toItem(entry)),\n }\n })\n const defaultGroupOrder = [\n 'customers.nav.group',\n 'catalog.nav.group',\n 'customers~sales.nav.group',\n 'resources.nav.group',\n 'staff.nav.group',\n 'entities.nav.group',\n 'directory.nav.group',\n 'customers.storage.nav.group',\n ]\n const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]))\n groups.sort((a, b) => {\n const aIndex = groupOrderIndex.get(a.id)\n const bIndex = groupOrderIndex.get(b.id)\n if (aIndex !== undefined || bIndex !== undefined) {\n if (aIndex === undefined) return 1\n if (bIndex === undefined) return -1\n if (aIndex !== bIndex) return aIndex - bIndex\n }\n if (a.weight !== b.weight) return a.weight - b.weight\n return a.name.localeCompare(b.name)\n })\n const defaultGroupCount = defaultGroupOrder.length\n groups.forEach((group, index) => {\n const rank = groupOrderIndex.get(group.id)\n const fallbackWeight = typeof group.weight === 'number' ? group.weight : 10_000\n const normalized =\n (rank !== undefined ? rank : defaultGroupCount + index) * 1_000_000 +\n Math.min(Math.max(fallbackWeight, 0), 999_999)\n group.weight = normalized\n })\n\n let rolePreference = null\n if (Array.isArray(auth.roles) && auth.roles.length) {\n const roleScope = auth.tenantId\n ? { $or: [{ tenantId: auth.tenantId }, { tenantId: null }] }\n : { tenantId: null }\n const roleRecords = await em.find(Role, {\n name: { $in: auth.roles },\n ...roleScope,\n } as any)\n const roleIds = roleRecords.map((role: Role) => role.id)\n if (roleIds.length) {\n rolePreference = await loadFirstRoleSidebarPreference(em, {\n roleIds,\n tenantId: auth.tenantId ?? null,\n locale,\n })\n }\n }\n\n const groupsWithRole = rolePreference ? applySidebarPreference(groups, rolePreference) : groups\n const baseForUser = adoptSidebarDefaults(groupsWithRole)\n\n const preference = await loadSidebarPreference(em, {\n userId: auth.sub,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n locale,\n })\n\n const withPreference = applySidebarPreference(baseForUser, preference)\n\n const payload = {\n groups: withPreference.map((group) => ({\n id: group.id,\n name: group.name,\n defaultName: group.defaultName,\n items: (group.items as SidebarItemNode[]).map((item) => ({\n href: item.href,\n title: item.title,\n defaultTitle: item.defaultTitle,\n enabled: item.enabled,\n hidden: item.hidden,\n children: item.children?.map((child) => ({\n href: child.href,\n title: child.title,\n defaultTitle: child.defaultTitle,\n enabled: child.enabled,\n hidden: child.hidden,\n })),\n })),\n })),\n }\n\n try {\n if (cache) {\n const tags = [\n `rbac:user:${auth.sub}`,\n auth.tenantId ? `rbac:tenant:${auth.tenantId}` : undefined,\n `nav:entities:${auth.tenantId || 'null'}`,\n `nav:locale:${locale}`,\n `nav:sidebar:user:${auth.sub}`,\n `nav:sidebar:scope:${auth.sub}:${auth.tenantId || 'null'}:${auth.orgId || 'null'}:${locale}`,\n ...(Array.isArray(auth.roles) ? auth.roles.map((role: string) => `nav:sidebar:role:${role}`) : []),\n ].filter(Boolean) as string[]\n await cache.set(cacheKey, payload, { tags })\n }\n } catch {}\n\n return NextResponse.json(payload)\n}\n\nfunction adoptSidebarDefaults(groups: ReturnType<typeof applySidebarPreference>) {\n const adoptItems = <T extends { title: string; defaultTitle?: string; children?: T[] }>(items: T[]): T[] =>\n items.map((item) => ({\n ...item,\n defaultTitle: item.title,\n children: item.children ? adoptItems(item.children) : undefined,\n }))\n\n return groups.map((group) => ({\n ...group,\n defaultName: group.name,\n items: adoptItems(group.items),\n }))\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Admin sidebar navigation',\n methods: {\n GET: {\n summary: 'Resolve sidebar entries',\n description:\n 'Returns the backend navigation tree available to the authenticated administrator after applying role and personal sidebar preferences.',\n responses: [\n { status: 200, description: 'Sidebar navigation structure', schema: adminNavResponseSchema },\n { status: 401, description: 'Unauthorized', schema: adminNavErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { z } from 'zod'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { hasAllFeatures } from '@open-mercato/shared/security/features'\nimport { CustomEntity } from '@open-mercato/core/modules/entities/data/entities'\nimport { slugifySidebarId } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\nimport { applySidebarPreference, loadFirstRoleSidebarPreference, loadSidebarPreference } from '../../services/sidebarPreferencesService'\nimport { Role } from '../../data/entities'\n\nexport const metadata = {\n GET: { requireAuth: true },\n}\n\nconst sidebarNavItemSchema: z.ZodType<{ href: string; title: string; defaultTitle: string; enabled: boolean; hidden?: boolean; children?: any[] }> = z.lazy(() =>\n z.object({\n href: z.string(),\n title: z.string(),\n defaultTitle: z.string(),\n enabled: z.boolean(),\n hidden: z.boolean().optional(),\n children: z.array(sidebarNavItemSchema).optional(),\n })\n)\n\nconst adminNavResponseSchema = z.object({\n groups: z.array(\n z.object({\n id: z.string(),\n name: z.string(),\n defaultName: z.string(),\n items: z.array(sidebarNavItemSchema),\n })\n ),\n})\n\nconst adminNavErrorSchema = z.object({\n error: z.string(),\n})\n\ntype SidebarItemNode = {\n href: string\n title: string\n defaultTitle: string\n enabled: boolean\n hidden?: boolean\n children?: SidebarItemNode[]\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 { translate, locale } = await resolveTranslations()\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as any\n const cache = resolve('cache') as any\n\n // Cache key is user + tenant + organization scoped\n const cacheKey = `nav:sidebar:${locale}:${auth.sub}:${auth.tenantId || 'null'}:${auth.orgId || 'null'}`\n // try {\n // if (cache) {\n // const cached = await cache.get(cacheKey)\n // if (cached) return NextResponse.json(cached)\n // }\n // } catch {}\n\n // Load ACL once; we'll evaluate features locally without multiple calls\n const acl = await rbac.loadAcl(auth.sub, { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null })\n\n // Build nav entries from discovered backend routes\n type Entry = {\n groupId: string\n groupName: string\n groupKey?: string\n title: string\n titleKey?: string\n href: string\n enabled: boolean\n order?: number\n priority?: number\n children?: Entry[]\n }\n const entries: Entry[] = []\n\n function capitalize(s: string) { return s.charAt(0).toUpperCase() + s.slice(1) }\n function deriveTitleFromPath(p: string) {\n const seg = p.split('/').filter(Boolean).pop() || ''\n return seg ? seg.split('-').map(capitalize).join(' ') : 'Home'\n }\n\n const ctx = { auth: { roles: auth.roles || [], sub: auth.sub, tenantId: auth.tenantId, orgId: auth.orgId } }\n const modules = getModules()\n for (const m of (modules as any[])) {\n const groupDefault = capitalize(m.id)\n for (const r of (m.backendRoutes || [])) {\n const href = (r.pattern ?? r.path ?? '') as string\n if (!href || href.includes('[')) continue\n if ((r as any).navHidden) continue\n const title = (r.title as string) || deriveTitleFromPath(href)\n const titleKey = (r as any).pageTitleKey ?? (r as any).titleKey\n const groupName = (r.group as string) || groupDefault\n const groupKey = (r as any).pageGroupKey ?? (r as any).groupKey\n const groupId = typeof groupKey === 'string' && groupKey ? groupKey : slugifySidebarId(groupName)\n const visible = r.visible ? await Promise.resolve(r.visible(ctx)) : true\n if (!visible) continue\n const enabled = r.enabled ? await Promise.resolve(r.enabled(ctx)) : true\n const requiredRoles = (r.requireRoles as string[]) || []\n if (requiredRoles.length) {\n const roles = auth.roles || []\n const ok = requiredRoles.some((role) => roles.includes(role))\n if (!ok) continue\n }\n const features = (r as any).requireFeatures as string[] | undefined\n if (!acl.isSuperAdmin && !hasAllFeatures(acl.features, features)) continue\n const order = (r as any).order as number | undefined\n const priority = ((r as any).priority as number | undefined) ?? order\n entries.push({ groupId, groupName, groupKey, title, titleKey, href, enabled, order, priority })\n }\n }\n\n // Parent-child relationships within the same group by href prefix\n const roots: any[] = []\n for (const e of entries) {\n let parent: any | undefined\n for (const p of entries) {\n if (p === e) continue\n if (p.groupId !== e.groupId) continue\n if (!e.href.startsWith(p.href + '/')) continue\n if (!parent || p.href.length > parent.href.length) parent = p\n }\n if (parent) {\n ;(parent as any).children = (parent as any).children || []\n ;(parent as any).children.push(e)\n } else {\n roots.push(e)\n }\n }\n\n // Add dynamic user entities into Data designer > User Entities\n const where: any = { isActive: true, showInSidebar: true }\n where.$and = [\n { $or: [ { organizationId: auth.orgId ?? undefined as any }, { organizationId: null } ] },\n { $or: [ { tenantId: auth.tenantId ?? undefined as any }, { tenantId: null } ] },\n ]\n try {\n const entities = await em.find(CustomEntity as any, where as any, { orderBy: { label: 'asc' } as any })\n const items = (entities as any[]).map((e) => ({\n entityId: e.entityId,\n label: e.label,\n href: `/backend/entities/user/${encodeURIComponent(e.entityId)}/records`\n }))\n if (items.length) {\n const dd = roots.find((it: Entry) => it.groupKey === 'entities.nav.group' && it.titleKey === 'entities.nav.userEntities')\n if (dd) {\n const existing = dd.children || []\n const dynamic = items.map((it) => ({\n groupId: dd.groupId,\n groupName: dd.groupName,\n groupKey: dd.groupKey,\n title: it.label,\n href: it.href,\n enabled: true,\n order: 1000,\n priority: 1000,\n }))\n const byHref = new Map<string, Entry>()\n for (const c of existing) if (!byHref.has(c.href)) byHref.set(c.href, c)\n for (const c of dynamic) if (!byHref.has(c.href)) byHref.set(c.href, c)\n dd.children = Array.from(byHref.values())\n }\n }\n } catch (e) {\n console.error('Error loading user entities', e)\n }\n\n // Sort roots and children\n const sortItems = (arr: any[]) => {\n arr.sort((a, b) => {\n if (a.group !== b.group) return a.group.localeCompare(b.group)\n const ap = a.priority ?? a.order ?? 10000\n const bp = b.priority ?? b.order ?? 10000\n if (ap !== bp) return ap - bp\n return String(a.title).localeCompare(String(b.title))\n })\n for (const it of arr) if (it.children?.length) sortItems(it.children)\n }\n sortItems(roots)\n\n // Group into sidebar groups\n type GroupBucket = {\n id: string\n rawName: string\n key?: string\n weight: number\n entries: Entry[]\n }\n\n const groupBuckets = new Map<string, GroupBucket>()\n for (const entry of roots) {\n const weight = entry.priority ?? entry.order ?? 10_000\n if (!groupBuckets.has(entry.groupId)) {\n groupBuckets.set(entry.groupId, {\n id: entry.groupId,\n rawName: entry.groupName,\n key: entry.groupKey as string | undefined,\n weight,\n entries: [entry],\n })\n } else {\n const bucket = groupBuckets.get(entry.groupId)!\n bucket.entries.push(entry)\n if (weight < bucket.weight) bucket.weight = weight\n if (!bucket.key && entry.groupKey) bucket.key = entry.groupKey as string\n if (!bucket.rawName && entry.groupName) bucket.rawName = entry.groupName\n }\n }\n\n const toItem = (entry: Entry): SidebarItemNode => {\n const defaultTitle = entry.titleKey ? translate(entry.titleKey, entry.title) : entry.title\n return {\n href: entry.href,\n title: defaultTitle,\n defaultTitle,\n enabled: entry.enabled,\n children: entry.children?.map((child) => toItem(child)),\n }\n }\n\n const groups = Array.from(groupBuckets.values()).map((bucket) => {\n const defaultName = bucket.key ? translate(bucket.key, bucket.rawName) : bucket.rawName\n return {\n id: bucket.id,\n key: bucket.key,\n name: defaultName,\n defaultName,\n weight: bucket.weight,\n items: bucket.entries.map((entry) => toItem(entry)),\n }\n })\n const defaultGroupOrder = [\n 'customers.nav.group',\n 'catalog.nav.group',\n 'customers~sales.nav.group',\n 'resources.nav.group',\n 'staff.nav.group',\n 'entities.nav.group',\n 'directory.nav.group',\n 'customers.storage.nav.group',\n ]\n const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]))\n groups.sort((a, b) => {\n const aIndex = groupOrderIndex.get(a.id)\n const bIndex = groupOrderIndex.get(b.id)\n if (aIndex !== undefined || bIndex !== undefined) {\n if (aIndex === undefined) return 1\n if (bIndex === undefined) return -1\n if (aIndex !== bIndex) return aIndex - bIndex\n }\n if (a.weight !== b.weight) return a.weight - b.weight\n return a.name.localeCompare(b.name)\n })\n const defaultGroupCount = defaultGroupOrder.length\n groups.forEach((group, index) => {\n const rank = groupOrderIndex.get(group.id)\n const fallbackWeight = typeof group.weight === 'number' ? group.weight : 10_000\n const normalized =\n (rank !== undefined ? rank : defaultGroupCount + index) * 1_000_000 +\n Math.min(Math.max(fallbackWeight, 0), 999_999)\n group.weight = normalized\n })\n\n let rolePreference = null\n if (Array.isArray(auth.roles) && auth.roles.length) {\n const roleScope = auth.tenantId\n ? { $or: [{ tenantId: auth.tenantId }, { tenantId: null }] }\n : { tenantId: null }\n const roleRecords = await em.find(Role, {\n name: { $in: auth.roles },\n ...roleScope,\n } as any)\n const roleIds = roleRecords.map((role: Role) => role.id)\n if (roleIds.length) {\n rolePreference = await loadFirstRoleSidebarPreference(em, {\n roleIds,\n tenantId: auth.tenantId ?? null,\n locale,\n })\n }\n }\n\n const groupsWithRole = rolePreference ? applySidebarPreference(groups, rolePreference) : groups\n const baseForUser = adoptSidebarDefaults(groupsWithRole)\n\n // For API key auth, use userId (the actual user) if available; otherwise skip user preferences\n const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub\n const preference = effectiveUserId\n ? await loadSidebarPreference(em, {\n userId: effectiveUserId,\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n locale,\n })\n : null\n\n const withPreference = applySidebarPreference(baseForUser, preference)\n\n const payload = {\n groups: withPreference.map((group) => ({\n id: group.id,\n name: group.name,\n defaultName: group.defaultName,\n items: (group.items as SidebarItemNode[]).map((item) => ({\n href: item.href,\n title: item.title,\n defaultTitle: item.defaultTitle,\n enabled: item.enabled,\n hidden: item.hidden,\n children: item.children?.map((child) => ({\n href: child.href,\n title: child.title,\n defaultTitle: child.defaultTitle,\n enabled: child.enabled,\n hidden: child.hidden,\n })),\n })),\n })),\n }\n\n try {\n if (cache) {\n const tags = [\n `rbac:user:${auth.sub}`,\n auth.tenantId ? `rbac:tenant:${auth.tenantId}` : undefined,\n `nav:entities:${auth.tenantId || 'null'}`,\n `nav:locale:${locale}`,\n `nav:sidebar:user:${auth.sub}`,\n `nav:sidebar:scope:${auth.sub}:${auth.tenantId || 'null'}:${auth.orgId || 'null'}:${locale}`,\n ...(Array.isArray(auth.roles) ? auth.roles.map((role: string) => `nav:sidebar:role:${role}`) : []),\n ].filter(Boolean) as string[]\n await cache.set(cacheKey, payload, { tags })\n }\n } catch {}\n\n return NextResponse.json(payload)\n}\n\nfunction adoptSidebarDefaults(groups: ReturnType<typeof applySidebarPreference>) {\n const adoptItems = <T extends { title: string; defaultTitle?: string; children?: T[] }>(items: T[]): T[] =>\n items.map((item) => ({\n ...item,\n defaultTitle: item.title,\n children: item.children ? adoptItems(item.children) : undefined,\n }))\n\n return groups.map((group) => ({\n ...group,\n defaultName: group.name,\n items: adoptItems(group.items),\n }))\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Admin sidebar navigation',\n methods: {\n GET: {\n summary: 'Resolve sidebar entries',\n description:\n 'Returns the backend navigation tree available to the authenticated administrator after applying role and personal sidebar preferences.',\n responses: [\n { status: 200, description: 'Sidebar navigation structure', schema: adminNavResponseSchema },\n { status: 401, description: 'Unauthorized', schema: adminNavErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -11,15 +11,33 @@ async function POST(req) {
11
11
  const email = String(form.get("email") ?? "");
12
12
  const password = String(form.get("password") ?? "");
13
13
  const remember = parseBooleanToken(form.get("remember")?.toString()) === true;
14
+ const tenantIdRaw = String(form.get("tenantId") ?? form.get("tenant") ?? "").trim();
14
15
  const requireRoleRaw = String(form.get("requireRole") ?? form.get("role") ?? "").trim();
15
16
  const requiredRoles = requireRoleRaw ? requireRoleRaw.split(",").map((s) => s.trim()).filter(Boolean) : [];
16
- const parsed = userLoginSchema.pick({ email: true, password: true }).safeParse({ email, password });
17
+ const parsed = userLoginSchema.pick({ email: true, password: true, tenantId: true }).safeParse({
18
+ email,
19
+ password,
20
+ tenantId: tenantIdRaw || void 0
21
+ });
17
22
  if (!parsed.success) {
18
23
  return NextResponse.json({ ok: false, error: translate("auth.login.errors.invalidCredentials", "Invalid credentials") }, { status: 400 });
19
24
  }
20
25
  const container = await createRequestContainer();
21
26
  const auth = container.resolve("authService");
22
- const user = await auth.findUserByEmail(parsed.data.email);
27
+ const tenantId = parsed.data.tenantId ?? null;
28
+ let user = null;
29
+ if (tenantId) {
30
+ user = await auth.findUserByEmailAndTenant(parsed.data.email, tenantId);
31
+ } else {
32
+ const users = await auth.findUsersByEmail(parsed.data.email);
33
+ if (users.length > 1) {
34
+ return NextResponse.json({
35
+ ok: false,
36
+ error: translate("auth.login.errors.tenantRequired", "Use the login link provided with your tenant activation to continue.")
37
+ }, { status: 400 });
38
+ }
39
+ user = users[0] ?? null;
40
+ }
23
41
  if (!user || !user.passwordHash) {
24
42
  return NextResponse.json({ ok: false, error: translate("auth.login.errors.invalidCredentials", "Invalid email or password") }, { status: 401 });
25
43
  }
@@ -28,24 +46,25 @@ async function POST(req) {
28
46
  return NextResponse.json({ ok: false, error: translate("auth.login.errors.invalidCredentials", "Invalid email or password") }, { status: 401 });
29
47
  }
30
48
  if (requiredRoles.length) {
31
- const userRoleNames2 = await auth.getUserRoles(user, user.tenantId ? String(user.tenantId) : null);
49
+ const userRoleNames2 = await auth.getUserRoles(user, tenantId ?? (user.tenantId ? String(user.tenantId) : null));
32
50
  const authorized = requiredRoles.some((r) => userRoleNames2.includes(r));
33
51
  if (!authorized) {
34
52
  return NextResponse.json({ ok: false, error: translate("auth.login.errors.permissionDenied", "Not authorized for this area") }, { status: 403 });
35
53
  }
36
54
  }
37
55
  await auth.updateLastLoginAt(user);
38
- const userRoleNames = await auth.getUserRoles(user, user.tenantId ? String(user.tenantId) : null);
56
+ const resolvedTenantId = tenantId ?? (user.tenantId ? String(user.tenantId) : null);
57
+ const userRoleNames = await auth.getUserRoles(user, resolvedTenantId);
39
58
  try {
40
59
  const eventBus = container.resolve("eventBus");
41
60
  void eventBus.emitEvent("query_index.coverage.warmup", {
42
- tenantId: user.tenantId ? String(user.tenantId) : null
61
+ tenantId: resolvedTenantId
43
62
  }).catch(() => void 0);
44
63
  } catch {
45
64
  }
46
65
  const token = signJwt({
47
66
  sub: String(user.id),
48
- tenantId: user.tenantId ? String(user.tenantId) : null,
67
+ tenantId: resolvedTenantId,
49
68
  orgId: user.organizationId ? String(user.organizationId) : null,
50
69
  email: user.email,
51
70
  roles: userRoleNames
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/api/login.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { userLoginSchema } from '@open-mercato/core/modules/auth/data/validators'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { signJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { EventBus } from '@open-mercato/events/types'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\n// validation comes from userLoginSchema\n\nexport async function POST(req: Request) {\n const { translate } = await resolveTranslations()\n const form = await req.formData()\n const email = String(form.get('email') ?? '')\n const password = String(form.get('password') ?? '')\n const remember = parseBooleanToken(form.get('remember')?.toString()) === true\n const requireRoleRaw = (String(form.get('requireRole') ?? form.get('role') ?? '')).trim()\n const requiredRoles = requireRoleRaw ? requireRoleRaw.split(',').map((s) => s.trim()).filter(Boolean) : []\n const parsed = userLoginSchema.pick({ email: true, password: true }).safeParse({ email, password })\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid credentials') }, { status: 400 })\n }\n const container = await createRequestContainer()\n const auth = (container.resolve('authService') as AuthService)\n const user = await auth.findUserByEmail(parsed.data.email)\n if (!user || !user.passwordHash) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid email or password') }, { status: 401 })\n }\n const ok = await auth.verifyPassword(user, parsed.data.password)\n if (!ok) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid email or password') }, { status: 401 })\n }\n // Optional role requirement\n if (requiredRoles.length) {\n const userRoleNames = await auth.getUserRoles(user, user.tenantId ? String(user.tenantId) : null)\n const authorized = requiredRoles.some(r => userRoleNames.includes(r))\n if (!authorized) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.permissionDenied', 'Not authorized for this area') }, { status: 403 })\n }\n }\n await auth.updateLastLoginAt(user)\n const userRoleNames = await auth.getUserRoles(user, user.tenantId ? String(user.tenantId) : null)\n try {\n const eventBus = (container.resolve('eventBus') as EventBus)\n void eventBus.emitEvent('query_index.coverage.warmup', {\n tenantId: user.tenantId ? String(user.tenantId) : null,\n }).catch(() => undefined)\n } catch {\n // optional warmup\n }\n const token = signJwt({ \n sub: String(user.id), \n tenantId: user.tenantId ? String(user.tenantId) : null, \n orgId: user.organizationId ? String(user.organizationId) : null, \n email: user.email, \n roles: userRoleNames \n })\n const res = NextResponse.json({ ok: true, token, redirect: '/backend' })\n res.cookies.set('auth_token', token, { httpOnly: true, path: '/', sameSite: 'lax', secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60 * 8 })\n if (remember) {\n const days = Number(process.env.REMEMBER_ME_DAYS || '30')\n const expiresAt = new Date(Date.now() + days * 24 * 60 * 60 * 1000)\n const sess = await auth.createSession(user, expiresAt)\n res.cookies.set('session_token', sess.token, { httpOnly: true, path: '/', sameSite: 'lax', secure: process.env.NODE_ENV === 'production', expires: expiresAt })\n }\n return res\n}\n\nconst loginRequestSchema = userLoginSchema.extend({\n password: z.string().min(6).describe('User password'),\n remember: z.enum(['on', '1', 'true']).optional().describe('Persist the session (submit `on`, `1`, or `true`).'),\n}).describe('Login form payload')\n\nconst loginSuccessSchema = z.object({\n ok: z.literal(true),\n token: z.string().describe('JWT token issued for subsequent API calls'),\n redirect: z.string().nullable().describe('Next location the client should navigate to'),\n})\n\nconst loginErrorSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n})\n\nconst loginMethodDoc: OpenApiMethodDoc = {\n summary: 'Authenticate user credentials',\n description: 'Validates the submitted credentials and issues a bearer token cookie for subsequent API calls.',\n tags: ['Authentication & Accounts'],\n requestBody: {\n contentType: 'application/x-www-form-urlencoded',\n schema: loginRequestSchema,\n description: 'Form-encoded payload captured from the login form.',\n },\n responses: [\n {\n status: 200,\n description: 'Authentication succeeded',\n schema: loginSuccessSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: loginErrorSchema },\n { status: 401, description: 'Invalid credentials', schema: loginErrorSchema },\n { status: 403, description: 'User lacks required role', schema: loginErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Authenticate user credentials',\n description: 'Accepts login form submissions and manages cookie/session issuance.',\n methods: {\n POST: loginMethodDoc,\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { userLoginSchema } from '@open-mercato/core/modules/auth/data/validators'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { signJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { EventBus } from '@open-mercato/events/types'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\n// validation comes from userLoginSchema\n\nexport async function POST(req: Request) {\n const { translate } = await resolveTranslations()\n const form = await req.formData()\n const email = String(form.get('email') ?? '')\n const password = String(form.get('password') ?? '')\n const remember = parseBooleanToken(form.get('remember')?.toString()) === true\n const tenantIdRaw = String(form.get('tenantId') ?? form.get('tenant') ?? '').trim()\n const requireRoleRaw = (String(form.get('requireRole') ?? form.get('role') ?? '')).trim()\n const requiredRoles = requireRoleRaw ? requireRoleRaw.split(',').map((s) => s.trim()).filter(Boolean) : []\n const parsed = userLoginSchema.pick({ email: true, password: true, tenantId: true }).safeParse({\n email,\n password,\n tenantId: tenantIdRaw || undefined,\n })\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid credentials') }, { status: 400 })\n }\n const container = await createRequestContainer()\n const auth = (container.resolve('authService') as AuthService)\n const tenantId = parsed.data.tenantId ?? null\n let user = null\n if (tenantId) {\n user = await auth.findUserByEmailAndTenant(parsed.data.email, tenantId)\n } else {\n const users = await auth.findUsersByEmail(parsed.data.email)\n if (users.length > 1) {\n return NextResponse.json({\n ok: false,\n error: translate('auth.login.errors.tenantRequired', 'Use the login link provided with your tenant activation to continue.'),\n }, { status: 400 })\n }\n user = users[0] ?? null\n }\n if (!user || !user.passwordHash) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid email or password') }, { status: 401 })\n }\n const ok = await auth.verifyPassword(user, parsed.data.password)\n if (!ok) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.invalidCredentials', 'Invalid email or password') }, { status: 401 })\n }\n // Optional role requirement\n if (requiredRoles.length) {\n const userRoleNames = await auth.getUserRoles(user, tenantId ?? (user.tenantId ? String(user.tenantId) : null))\n const authorized = requiredRoles.some(r => userRoleNames.includes(r))\n if (!authorized) {\n return NextResponse.json({ ok: false, error: translate('auth.login.errors.permissionDenied', 'Not authorized for this area') }, { status: 403 })\n }\n }\n await auth.updateLastLoginAt(user)\n const resolvedTenantId = tenantId ?? (user.tenantId ? String(user.tenantId) : null)\n const userRoleNames = await auth.getUserRoles(user, resolvedTenantId)\n try {\n const eventBus = (container.resolve('eventBus') as EventBus)\n void eventBus.emitEvent('query_index.coverage.warmup', {\n tenantId: resolvedTenantId,\n }).catch(() => undefined)\n } catch {\n // optional warmup\n }\n const token = signJwt({ \n sub: String(user.id), \n tenantId: resolvedTenantId, \n orgId: user.organizationId ? String(user.organizationId) : null,\n email: user.email, \n roles: userRoleNames \n })\n const res = NextResponse.json({ ok: true, token, redirect: '/backend' })\n res.cookies.set('auth_token', token, { httpOnly: true, path: '/', sameSite: 'lax', secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60 * 8 })\n if (remember) {\n const days = Number(process.env.REMEMBER_ME_DAYS || '30')\n const expiresAt = new Date(Date.now() + days * 24 * 60 * 60 * 1000)\n const sess = await auth.createSession(user, expiresAt)\n res.cookies.set('session_token', sess.token, { httpOnly: true, path: '/', sameSite: 'lax', secure: process.env.NODE_ENV === 'production', expires: expiresAt })\n }\n return res\n}\n\nconst loginRequestSchema = userLoginSchema.extend({\n password: z.string().min(6).describe('User password'),\n remember: z.enum(['on', '1', 'true']).optional().describe('Persist the session (submit `on`, `1`, or `true`).'),\n}).describe('Login form payload')\n\nconst loginSuccessSchema = z.object({\n ok: z.literal(true),\n token: z.string().describe('JWT token issued for subsequent API calls'),\n redirect: z.string().nullable().describe('Next location the client should navigate to'),\n})\n\nconst loginErrorSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n})\n\nconst loginMethodDoc: OpenApiMethodDoc = {\n summary: 'Authenticate user credentials',\n description: 'Validates the submitted credentials and issues a bearer token cookie for subsequent API calls.',\n tags: ['Authentication & Accounts'],\n requestBody: {\n contentType: 'application/x-www-form-urlencoded',\n schema: loginRequestSchema,\n description: 'Form-encoded payload captured from the login form.',\n },\n responses: [\n {\n status: 200,\n description: 'Authentication succeeded',\n schema: loginSuccessSchema,\n },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: loginErrorSchema },\n { status: 401, description: 'Invalid credentials', schema: loginErrorSchema },\n { status: 403, description: 'User lacks required role', schema: loginErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Authenticate user credentials',\n description: 'Accepts login form submissions and manages cookie/session issuance.',\n methods: {\n POST: loginMethodDoc,\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["userRoleNames"]
7
7
  }
@@ -0,0 +1,157 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
+ import { signJwt } from "@open-mercato/shared/lib/auth/jwt";
6
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
7
+ import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
8
+ import { User } from "@open-mercato/core/modules/auth/data/entities";
9
+ import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
10
+ import { buildPasswordSchema } from "@open-mercato/shared/lib/auth/passwordPolicy";
11
+ const profileResponseSchema = z.object({
12
+ email: z.string().email()
13
+ });
14
+ const passwordSchema = buildPasswordSchema();
15
+ const updateSchema = z.object({
16
+ email: z.string().email().optional(),
17
+ password: passwordSchema.optional()
18
+ }).refine((data) => Boolean(data.email || data.password), {
19
+ message: "Provide an email or password.",
20
+ path: ["email"]
21
+ });
22
+ const profileUpdateResponseSchema = z.object({
23
+ ok: z.literal(true),
24
+ email: z.string().email()
25
+ });
26
+ const metadata = {
27
+ GET: { requireAuth: true },
28
+ PUT: { requireAuth: true }
29
+ };
30
+ function buildCommandContext(container, auth, req) {
31
+ return {
32
+ container,
33
+ auth,
34
+ organizationScope: null,
35
+ selectedOrganizationId: auth.orgId ?? null,
36
+ organizationIds: auth.orgId ? [auth.orgId] : null,
37
+ request: req
38
+ };
39
+ }
40
+ async function GET(req) {
41
+ const { translate } = await resolveTranslations();
42
+ const auth = await getAuthFromRequest(req);
43
+ if (!auth?.sub) {
44
+ return NextResponse.json({ error: translate("api.errors.unauthorized", "Unauthorized") }, { status: 401 });
45
+ }
46
+ try {
47
+ const container = await createRequestContainer();
48
+ const em = container.resolve("em");
49
+ const user = await findOneWithDecryption(
50
+ em,
51
+ User,
52
+ { id: auth.sub, deletedAt: null },
53
+ void 0,
54
+ { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null }
55
+ );
56
+ if (!user) {
57
+ return NextResponse.json({ error: translate("auth.users.form.errors.notFound", "User not found") }, { status: 404 });
58
+ }
59
+ return NextResponse.json({ email: String(user.email) });
60
+ } catch (err) {
61
+ console.error("auth.profile.load failed", err);
62
+ return NextResponse.json({ error: translate("auth.profile.form.errors.load", "Failed to load profile.") }, { status: 400 });
63
+ }
64
+ }
65
+ async function PUT(req) {
66
+ const { translate } = await resolveTranslations();
67
+ const auth = await getAuthFromRequest(req);
68
+ if (!auth?.sub) {
69
+ return NextResponse.json({ error: translate("api.errors.unauthorized", "Unauthorized") }, { status: 401 });
70
+ }
71
+ try {
72
+ const body = await req.json().catch(() => ({}));
73
+ const parsed = updateSchema.safeParse(body);
74
+ if (!parsed.success) {
75
+ return NextResponse.json(
76
+ {
77
+ error: translate("auth.profile.form.errors.invalid", "Invalid profile update."),
78
+ issues: parsed.error.issues
79
+ },
80
+ { status: 400 }
81
+ );
82
+ }
83
+ const container = await createRequestContainer();
84
+ const commandBus = container.resolve("commandBus");
85
+ const ctx = buildCommandContext(container, auth, req);
86
+ const { result } = await commandBus.execute(
87
+ "auth.users.update",
88
+ {
89
+ input: {
90
+ id: auth.sub,
91
+ email: parsed.data.email,
92
+ password: parsed.data.password
93
+ },
94
+ ctx
95
+ }
96
+ );
97
+ const authService = container.resolve("authService");
98
+ const roles = await authService.getUserRoles(result, result.tenantId ? String(result.tenantId) : null);
99
+ const jwt = signJwt({
100
+ sub: String(result.id),
101
+ tenantId: result.tenantId ? String(result.tenantId) : null,
102
+ orgId: result.organizationId ? String(result.organizationId) : null,
103
+ email: result.email,
104
+ roles
105
+ });
106
+ const res = NextResponse.json({ ok: true, email: String(result.email) });
107
+ res.cookies.set("auth_token", jwt, {
108
+ httpOnly: true,
109
+ path: "/",
110
+ sameSite: "lax",
111
+ secure: process.env.NODE_ENV === "production",
112
+ maxAge: 60 * 60 * 8
113
+ });
114
+ return res;
115
+ } catch (err) {
116
+ if (err instanceof CrudHttpError) {
117
+ return NextResponse.json(err.body, { status: err.status });
118
+ }
119
+ console.error("auth.profile.update failed", err);
120
+ return NextResponse.json({ error: translate("auth.profile.form.errors.save", "Failed to update profile.") }, { status: 400 });
121
+ }
122
+ }
123
+ const openApi = {
124
+ tag: "Authentication & Accounts",
125
+ summary: "Profile settings",
126
+ methods: {
127
+ GET: {
128
+ summary: "Get current profile",
129
+ description: "Returns the email address for the signed-in user.",
130
+ responses: [
131
+ { status: 200, description: "Profile payload", schema: profileResponseSchema },
132
+ { status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) },
133
+ { status: 404, description: "User not found", schema: z.object({ error: z.string() }) }
134
+ ]
135
+ },
136
+ PUT: {
137
+ summary: "Update current profile",
138
+ description: "Updates the email address or password for the signed-in user.",
139
+ requestBody: {
140
+ contentType: "application/json",
141
+ schema: updateSchema
142
+ },
143
+ responses: [
144
+ { status: 200, description: "Profile updated", schema: profileUpdateResponseSchema },
145
+ { status: 400, description: "Invalid payload", schema: z.object({ error: z.string() }) },
146
+ { status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) }
147
+ ]
148
+ }
149
+ }
150
+ };
151
+ export {
152
+ GET,
153
+ PUT,
154
+ metadata,
155
+ openApi
156
+ };
157
+ //# sourceMappingURL=route.js.map