@open-mercato/core 0.6.7 → 0.6.8-develop.6874.1.982d6097d8

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 (1508) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/AGENTS.md +3 -3
  3. package/agentic/standalone-guide.md +13 -0
  4. package/dist/bootstrap.js +16 -1
  5. package/dist/bootstrap.js.map +2 -2
  6. package/dist/generated/entities/attachment_quota_reservation/index.js +33 -0
  7. package/dist/generated/entities/attachment_quota_reservation/index.js.map +7 -0
  8. package/dist/generated/entities/customer_deal_person_link/index.js +2 -0
  9. package/dist/generated/entities/customer_deal_person_link/index.js.map +2 -2
  10. package/dist/generated/entities/customer_user_invitation/index.js +2 -0
  11. package/dist/generated/entities/customer_user_invitation/index.js.map +2 -2
  12. package/dist/generated/entities/gateway_payment_operation/index.js +2 -0
  13. package/dist/generated/entities/gateway_payment_operation/index.js.map +2 -2
  14. package/dist/generated/entities/gateway_transaction/index.js +2 -0
  15. package/dist/generated/entities/gateway_transaction/index.js.map +2 -2
  16. package/dist/generated/entities/organization/index.js +2 -0
  17. package/dist/generated/entities/organization/index.js.map +2 -2
  18. package/dist/generated/entities/resources_resource/index.js +2 -0
  19. package/dist/generated/entities/resources_resource/index.js.map +2 -2
  20. package/dist/generated/entities.ids.generated.js +3 -1
  21. package/dist/generated/entities.ids.generated.js.map +2 -2
  22. package/dist/generated/entity-fields-registry.js +23 -0
  23. package/dist/generated/entity-fields-registry.js.map +2 -2
  24. package/dist/helpers/integration/salesFixtures.js +31 -2
  25. package/dist/helpers/integration/salesFixtures.js.map +2 -2
  26. package/dist/helpers/integration/salesUi.js +5 -0
  27. package/dist/helpers/integration/salesUi.js.map +2 -2
  28. package/dist/modules/api_keys/backend/api-keys/page.js +2 -1
  29. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  30. package/dist/modules/api_keys/extension-points.js +16 -0
  31. package/dist/modules/api_keys/extension-points.js.map +7 -0
  32. package/dist/modules/attachments/api/route.js +120 -10
  33. package/dist/modules/attachments/api/route.js.map +2 -2
  34. package/dist/modules/attachments/backend/config/attachments/page.js +1 -1
  35. package/dist/modules/attachments/backend/config/attachments/page.js.map +2 -2
  36. package/dist/modules/attachments/data/entities.js +67 -1
  37. package/dist/modules/attachments/data/entities.js.map +2 -2
  38. package/dist/modules/attachments/di.js +7 -1
  39. package/dist/modules/attachments/di.js.map +2 -2
  40. package/dist/modules/attachments/fields/attachment.js +1 -1
  41. package/dist/modules/attachments/fields/attachment.js.map +2 -2
  42. package/dist/modules/attachments/lib/drivers/index.js.map +1 -1
  43. package/dist/modules/attachments/lib/drivers/localDriver.js +19 -6
  44. package/dist/modules/attachments/lib/drivers/localDriver.js.map +2 -2
  45. package/dist/modules/attachments/lib/quota-recovery-queue.js +9 -0
  46. package/dist/modules/attachments/lib/quota-recovery-queue.js.map +7 -0
  47. package/dist/modules/attachments/lib/quota-service.js +224 -0
  48. package/dist/modules/attachments/lib/quota-service.js.map +7 -0
  49. package/dist/modules/attachments/lib/upload-limits.js +33 -0
  50. package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
  51. package/dist/modules/attachments/migrations/Migration20260709234741_attachments.js +13 -0
  52. package/dist/modules/attachments/migrations/Migration20260709234741_attachments.js.map +7 -0
  53. package/dist/modules/attachments/workers/quota-recovery.js +45 -0
  54. package/dist/modules/attachments/workers/quota-recovery.js.map +7 -0
  55. package/dist/modules/audit_logs/api/audit-logs/access/route.js +5 -1
  56. package/dist/modules/audit_logs/api/audit-logs/access/route.js.map +2 -2
  57. package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js +5 -1
  58. package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +2 -2
  59. package/dist/modules/audit_logs/api/audit-logs/actions/route.js +5 -1
  60. package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
  61. package/dist/modules/audit_logs/api/audit-logs/readScope.js +12 -0
  62. package/dist/modules/audit_logs/api/audit-logs/readScope.js.map +7 -0
  63. package/dist/modules/audit_logs/components/AccessLogsTable.js +2 -1
  64. package/dist/modules/audit_logs/components/AccessLogsTable.js.map +2 -2
  65. package/dist/modules/audit_logs/components/AuditLogsActions.js +3 -2
  66. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  67. package/dist/modules/audit_logs/extension-points.js +14 -0
  68. package/dist/modules/audit_logs/extension-points.js.map +7 -0
  69. package/dist/modules/auth/api/admin/nav.js +17 -4
  70. package/dist/modules/auth/api/admin/nav.js.map +2 -2
  71. package/dist/modules/auth/api/profile/route.js +8 -2
  72. package/dist/modules/auth/api/profile/route.js.map +2 -2
  73. package/dist/modules/auth/api/users/route.js +8 -19
  74. package/dist/modules/auth/api/users/route.js.map +2 -2
  75. package/dist/modules/auth/backend/auth/profile/page.js.map +2 -2
  76. package/dist/modules/auth/backend/profile/change-password/page.js.map +2 -2
  77. package/dist/modules/auth/backend/roles/page.js +2 -1
  78. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  79. package/dist/modules/auth/backend/settings/page.js +14 -9
  80. package/dist/modules/auth/backend/settings/page.js.map +2 -2
  81. package/dist/modules/auth/backend/users/page.js +2 -1
  82. package/dist/modules/auth/backend/users/page.js.map +2 -2
  83. package/dist/modules/auth/cli.js +1 -1
  84. package/dist/modules/auth/cli.js.map +2 -2
  85. package/dist/modules/auth/components/UserConsentsPanel.js +9 -9
  86. package/dist/modules/auth/components/UserConsentsPanel.js.map +2 -2
  87. package/dist/modules/auth/extension-points.js +21 -0
  88. package/dist/modules/auth/extension-points.js.map +7 -0
  89. package/dist/modules/auth/frontend/login.js +7 -3
  90. package/dist/modules/auth/frontend/login.js.map +2 -2
  91. package/dist/modules/auth/frontend/reset.js +2 -2
  92. package/dist/modules/auth/frontend/reset.js.map +2 -2
  93. package/dist/modules/auth/lib/backendChrome.js +45 -29
  94. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  95. package/dist/modules/auth/lib/setup-app.js +17 -2
  96. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  97. package/dist/modules/auth/lib/tenantAccess.js +7 -0
  98. package/dist/modules/auth/lib/tenantAccess.js.map +2 -2
  99. package/dist/modules/auth/services/rbacService.js +29 -44
  100. package/dist/modules/auth/services/rbacService.js.map +2 -2
  101. package/dist/modules/business_rules/api/openmercato-call-options/route.js +85 -0
  102. package/dist/modules/business_rules/api/openmercato-call-options/route.js.map +7 -0
  103. package/dist/modules/business_rules/api/rules/route.js +71 -4
  104. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  105. package/dist/modules/business_rules/backend/rules/page.js +2 -1
  106. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  107. package/dist/modules/business_rules/components/ActionBuilder.js +47 -4
  108. package/dist/modules/business_rules/components/ActionBuilder.js.map +3 -3
  109. package/dist/modules/business_rules/components/ActionRow.js +106 -16
  110. package/dist/modules/business_rules/components/ActionRow.js.map +2 -2
  111. package/dist/modules/business_rules/components/ConditionRow.js +8 -4
  112. package/dist/modules/business_rules/components/ConditionRow.js.map +2 -2
  113. package/dist/modules/business_rules/components/utils/actionValidation.js +6 -0
  114. package/dist/modules/business_rules/components/utils/actionValidation.js.map +2 -2
  115. package/dist/modules/business_rules/events.js +13 -0
  116. package/dist/modules/business_rules/events.js.map +7 -0
  117. package/dist/modules/business_rules/extension-points.js +13 -0
  118. package/dist/modules/business_rules/extension-points.js.map +7 -0
  119. package/dist/modules/business_rules/lib/action-executor.js +148 -0
  120. package/dist/modules/business_rules/lib/action-executor.js.map +2 -2
  121. package/dist/modules/business_rules/lib/openmercato-call-options-types.js +5 -0
  122. package/dist/modules/business_rules/lib/openmercato-call-options-types.js.map +7 -0
  123. package/dist/modules/business_rules/lib/openmercato-call-options.js +231 -0
  124. package/dist/modules/business_rules/lib/openmercato-call-options.js.map +7 -0
  125. package/dist/modules/business_rules/lib/rule-engine.js +5 -1
  126. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  127. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +6 -5
  128. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  129. package/dist/modules/catalog/backend/catalog/products/create/page.js +7 -6
  130. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  131. package/dist/modules/catalog/components/PriceKindSettings.js +3 -3
  132. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  133. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -1
  134. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  135. package/dist/modules/catalog/components/products/ProductCategorizeSection.js +3 -3
  136. package/dist/modules/catalog/components/products/ProductCategorizeSection.js.map +2 -2
  137. package/dist/modules/catalog/components/products/ProductMediaManager.js +1 -1
  138. package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
  139. package/dist/modules/catalog/components/products/ProductsDataTable.js +3 -2
  140. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  141. package/dist/modules/catalog/components/products/VariantBuilder.js +5 -5
  142. package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
  143. package/dist/modules/catalog/events.js +1 -0
  144. package/dist/modules/catalog/events.js.map +2 -2
  145. package/dist/modules/catalog/extension-points.js +27 -0
  146. package/dist/modules/catalog/extension-points.js.map +7 -0
  147. package/dist/modules/catalog/widgets/injection/product-bulk-delete/widget.js +10 -5
  148. package/dist/modules/catalog/widgets/injection/product-bulk-delete/widget.js.map +2 -2
  149. package/dist/modules/catalog/widgets/injection/product-seo/widget.js +1 -1
  150. package/dist/modules/catalog/widgets/injection/product-seo/widget.js.map +2 -2
  151. package/dist/modules/communication_channels/api/post/test-seed/route.js +52 -2
  152. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  153. package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js +11 -1
  154. package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js.map +2 -2
  155. package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js +11 -6
  156. package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js.map +2 -2
  157. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +2 -1
  158. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  159. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +8 -7
  160. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
  161. package/dist/modules/communication_channels/data/enrichers.js +4 -4
  162. package/dist/modules/communication_channels/data/enrichers.js.map +2 -2
  163. package/dist/modules/communication_channels/extension-points.js +20 -0
  164. package/dist/modules/communication_channels/extension-points.js.map +7 -0
  165. package/dist/modules/communication_channels/lib/access-control.js +2 -2
  166. package/dist/modules/communication_channels/lib/access-control.js.map +2 -2
  167. package/dist/modules/configs/backend/config/system-status/page.js +2 -1
  168. package/dist/modules/configs/backend/config/system-status/page.js.map +2 -2
  169. package/dist/modules/configs/extension-points.js +18 -0
  170. package/dist/modules/configs/extension-points.js.map +7 -0
  171. package/dist/modules/configs/lib/upgrade-actions.js +12 -0
  172. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  173. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  174. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  175. package/dist/modules/currencies/backend/exchange-rates/page.js +2 -1
  176. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  177. package/dist/modules/currencies/di.js +4 -0
  178. package/dist/modules/currencies/di.js.map +2 -2
  179. package/dist/modules/currencies/extension-points.js +14 -0
  180. package/dist/modules/currencies/extension-points.js.map +7 -0
  181. package/dist/modules/currencies/services/baseCurrencyService.js +42 -0
  182. package/dist/modules/currencies/services/baseCurrencyService.js.map +7 -0
  183. package/dist/modules/customer_accounts/api/admin/users/[id].js +10 -1
  184. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  185. package/dist/modules/customer_accounts/api/admin/users-invite.js +63 -4
  186. package/dist/modules/customer_accounts/api/admin/users-invite.js.map +2 -2
  187. package/dist/modules/customer_accounts/api/invitations/accept.js +1 -2
  188. package/dist/modules/customer_accounts/api/invitations/accept.js.map +2 -2
  189. package/dist/modules/customer_accounts/api/login.js +4 -2
  190. package/dist/modules/customer_accounts/api/login.js.map +2 -2
  191. package/dist/modules/customer_accounts/api/magic-link/verify.js +4 -2
  192. package/dist/modules/customer_accounts/api/magic-link/verify.js.map +2 -2
  193. package/dist/modules/customer_accounts/api/portal/feature-check.js +5 -4
  194. package/dist/modules/customer_accounts/api/portal/feature-check.js.map +2 -2
  195. package/dist/modules/customer_accounts/api/portal/nav.js +6 -4
  196. package/dist/modules/customer_accounts/api/portal/nav.js.map +2 -2
  197. package/dist/modules/customer_accounts/api/portal/profile.js +5 -1
  198. package/dist/modules/customer_accounts/api/portal/profile.js.map +2 -2
  199. package/dist/modules/customer_accounts/api/portal/sessions-refresh.js +3 -3
  200. package/dist/modules/customer_accounts/api/portal/sessions-refresh.js.map +2 -2
  201. package/dist/modules/customer_accounts/api/portal/users-invite.js +22 -2
  202. package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
  203. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +2 -1
  204. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  205. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js +2 -2
  206. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js.map +2 -2
  207. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +2 -1
  208. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  209. package/dist/modules/customer_accounts/data/entities.js +3 -0
  210. package/dist/modules/customer_accounts/data/entities.js.map +2 -2
  211. package/dist/modules/customer_accounts/data/validators.js +1 -0
  212. package/dist/modules/customer_accounts/data/validators.js.map +2 -2
  213. package/dist/modules/customer_accounts/emails/CustomerInvitationEmail.js +26 -0
  214. package/dist/modules/customer_accounts/emails/CustomerInvitationEmail.js.map +7 -0
  215. package/dist/modules/customer_accounts/extension-points.js +14 -0
  216. package/dist/modules/customer_accounts/extension-points.js.map +7 -0
  217. package/dist/modules/customer_accounts/lib/customerAuth.js +7 -2
  218. package/dist/modules/customer_accounts/lib/customerAuth.js.map +2 -2
  219. package/dist/modules/customer_accounts/lib/customerAuthServer.js +2 -1
  220. package/dist/modules/customer_accounts/lib/customerAuthServer.js.map +2 -2
  221. package/dist/modules/customer_accounts/lib/customerEntityOwnership.js +29 -3
  222. package/dist/modules/customer_accounts/lib/customerEntityOwnership.js.map +2 -2
  223. package/dist/modules/customer_accounts/lib/customerUrl.js +19 -10
  224. package/dist/modules/customer_accounts/lib/customerUrl.js.map +2 -2
  225. package/dist/modules/customer_accounts/lib/invitationEmail.js +35 -0
  226. package/dist/modules/customer_accounts/lib/invitationEmail.js.map +7 -0
  227. package/dist/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.js +13 -0
  228. package/dist/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.js.map +7 -0
  229. package/dist/modules/customer_accounts/services/customerInvitationService.js +32 -2
  230. package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
  231. package/dist/modules/customer_accounts/services/customerRbacService.js +12 -3
  232. package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
  233. package/dist/modules/customer_accounts/setup.js +6 -0
  234. package/dist/modules/customer_accounts/setup.js.map +2 -2
  235. package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js +47 -7
  236. package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js.map +2 -2
  237. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -2
  238. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  239. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +1 -1
  240. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +2 -2
  241. package/dist/modules/customer_accounts/widgets/injection-table.js +1 -1
  242. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  243. package/dist/modules/customers/analytics.js +4 -1
  244. package/dist/modules/customers/analytics.js.map +2 -2
  245. package/dist/modules/customers/api/companies/[id]/route.js +3 -4
  246. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  247. package/dist/modules/customers/api/deals/[id]/people/route.js +4 -2
  248. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  249. package/dist/modules/customers/api/deals/[id]/route.js +7 -3
  250. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  251. package/dist/modules/customers/api/deals/aggregate/route.js +5 -4
  252. package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
  253. package/dist/modules/customers/api/deals/summary/route.js +14 -119
  254. package/dist/modules/customers/api/deals/summary/route.js.map +2 -2
  255. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +3 -2
  256. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  257. package/dist/modules/customers/api/utils.js +21 -24
  258. package/dist/modules/customers/api/utils.js.map +2 -2
  259. package/dist/modules/customers/backend/customers/companies/[id]/page.js +2 -1
  260. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  261. package/dist/modules/customers/backend/customers/companies/page.js +2 -1
  262. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  263. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +16 -5
  264. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  265. package/dist/modules/customers/backend/customers/deals/[id]/page.js +18 -11
  266. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  267. package/dist/modules/customers/backend/customers/deals/page.js +2 -1
  268. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  269. package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js +17 -3
  270. package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js.map +2 -2
  271. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +8 -2
  272. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  273. package/dist/modules/customers/backend/customers/people/[id]/page.js +2 -1
  274. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  275. package/dist/modules/customers/backend/customers/people/page.js +2 -1
  276. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  277. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +26 -10
  278. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  279. package/dist/modules/customers/cli.js +28 -11
  280. package/dist/modules/customers/cli.js.map +2 -2
  281. package/dist/modules/customers/commands/deals.js +48 -10
  282. package/dist/modules/customers/commands/deals.js.map +2 -2
  283. package/dist/modules/customers/commands/people.js +2 -0
  284. package/dist/modules/customers/commands/people.js.map +2 -2
  285. package/dist/modules/customers/components/CustomerTodosTable.js +2 -1
  286. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  287. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
  288. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
  289. package/dist/modules/customers/components/detail/ActiveDealCard.js +2 -1
  290. package/dist/modules/customers/components/detail/ActiveDealCard.js.map +2 -2
  291. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +2 -3
  292. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +2 -2
  293. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +26 -6
  294. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
  295. package/dist/modules/customers/components/detail/CompanyKpiBar.js +6 -5
  296. package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
  297. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +2 -2
  298. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +2 -2
  299. package/dist/modules/customers/components/detail/DealDetailTabs.js +30 -8
  300. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
  301. package/dist/modules/customers/components/detail/DealForm.js +2 -1
  302. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  303. package/dist/modules/customers/components/detail/DealsSection.js +1 -1
  304. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  305. package/dist/modules/customers/components/detail/MiniWeekCalendar.js +7 -52
  306. package/dist/modules/customers/components/detail/MiniWeekCalendar.js.map +2 -2
  307. package/dist/modules/customers/components/detail/PersonDetailTabs.js +30 -8
  308. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  309. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +231 -216
  310. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  311. package/dist/modules/customers/components/detail/dashboard/helpers.js +4 -3
  312. package/dist/modules/customers/components/detail/dashboard/helpers.js.map +2 -2
  313. package/dist/modules/customers/components/detail/legacyActivities.js +69 -0
  314. package/dist/modules/customers/components/detail/legacyActivities.js.map +7 -0
  315. package/dist/modules/customers/components/formConfig.js +14 -10
  316. package/dist/modules/customers/components/formConfig.js.map +2 -2
  317. package/dist/modules/customers/data/entities.js +8 -0
  318. package/dist/modules/customers/data/entities.js.map +2 -2
  319. package/dist/modules/customers/data/validators.js +5 -2
  320. package/dist/modules/customers/data/validators.js.map +2 -2
  321. package/dist/modules/customers/extension-points.js +42 -0
  322. package/dist/modules/customers/extension-points.js.map +7 -0
  323. package/dist/modules/customers/lib/calendar/format.js +8 -4
  324. package/dist/modules/customers/lib/calendar/format.js.map +2 -2
  325. package/dist/modules/customers/lib/dealStatus.js +38 -0
  326. package/dist/modules/customers/lib/dealStatus.js.map +7 -0
  327. package/dist/modules/customers/lib/dealsSummaryQueries.js +144 -0
  328. package/dist/modules/customers/lib/dealsSummaryQueries.js.map +7 -0
  329. package/dist/modules/customers/lib/optionalBaseCurrency.js +19 -0
  330. package/dist/modules/customers/lib/optionalBaseCurrency.js.map +7 -0
  331. package/dist/modules/customers/lib/visibilityFilter.js +6 -4
  332. package/dist/modules/customers/lib/visibilityFilter.js.map +2 -2
  333. package/dist/modules/customers/migrations/Migration20260723210000_customers.js +15 -0
  334. package/dist/modules/customers/migrations/Migration20260723210000_customers.js.map +7 -0
  335. package/dist/modules/customers/search.js +50 -29
  336. package/dist/modules/customers/search.js.map +2 -2
  337. package/dist/modules/customers/utils/phoneDuplicates.js +1 -2
  338. package/dist/modules/customers/utils/phoneDuplicates.js.map +2 -2
  339. package/dist/modules/dashboards/api/layout/[itemId]/route.js +6 -3
  340. package/dist/modules/dashboards/api/layout/[itemId]/route.js.map +2 -2
  341. package/dist/modules/dashboards/api/layout/route.js +22 -9
  342. package/dist/modules/dashboards/api/layout/route.js.map +2 -2
  343. package/dist/modules/dashboards/api/roles/widgets/route.js +9 -3
  344. package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
  345. package/dist/modules/dashboards/api/users/widgets/route.js +9 -3
  346. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  347. package/dist/modules/dashboards/api/widgets/catalog.js +6 -3
  348. package/dist/modules/dashboards/api/widgets/catalog.js.map +2 -2
  349. package/dist/modules/dashboards/api/widgets/data/batch/route.js +12 -3
  350. package/dist/modules/dashboards/api/widgets/data/batch/route.js.map +2 -2
  351. package/dist/modules/dashboards/api/widgets/data/route.js +28 -3
  352. package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
  353. package/dist/modules/dashboards/api/widgets/data/schema.js +28 -18
  354. package/dist/modules/dashboards/api/widgets/data/schema.js.map +2 -2
  355. package/dist/modules/dashboards/components/UnlabelledAmountNotice.js +33 -0
  356. package/dist/modules/dashboards/components/UnlabelledAmountNotice.js.map +7 -0
  357. package/dist/modules/dashboards/lib/access.js +5 -3
  358. package/dist/modules/dashboards/lib/access.js.map +2 -2
  359. package/dist/modules/dashboards/lib/aggregations.js +113 -46
  360. package/dist/modules/dashboards/lib/aggregations.js.map +2 -2
  361. package/dist/modules/dashboards/lib/exactDecimal.js +69 -0
  362. package/dist/modules/dashboards/lib/exactDecimal.js.map +7 -0
  363. package/dist/modules/dashboards/lib/formatters.js +84 -11
  364. package/dist/modules/dashboards/lib/formatters.js.map +2 -2
  365. package/dist/modules/dashboards/lib/optionalBaseCurrency.js +11 -0
  366. package/dist/modules/dashboards/lib/optionalBaseCurrency.js.map +7 -0
  367. package/dist/modules/dashboards/services/widgetDataService.js +316 -14
  368. package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
  369. package/dist/modules/dashboards/subscribers/invalidateWidgetDataCache.js +26 -0
  370. package/dist/modules/dashboards/subscribers/invalidateWidgetDataCache.js.map +7 -0
  371. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js +9 -3
  372. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js.map +2 -2
  373. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/config.js +52 -2
  374. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/config.js.map +2 -2
  375. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.js +52 -30
  376. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.js.map +2 -2
  377. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +2 -2
  378. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
  379. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js +9 -3
  380. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js.map +2 -2
  381. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js +8 -3
  382. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js.map +2 -2
  383. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js +26 -18
  384. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js.map +2 -2
  385. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js +22 -14
  386. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js.map +2 -2
  387. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js +10 -4
  388. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js.map +2 -2
  389. package/dist/modules/data_sync/api/mappings/[id]/route.js +22 -9
  390. package/dist/modules/data_sync/api/mappings/[id]/route.js.map +2 -2
  391. package/dist/modules/data_sync/api/mappings/route.js +13 -4
  392. package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
  393. package/dist/modules/data_sync/api/options.js +7 -2
  394. package/dist/modules/data_sync/api/options.js.map +2 -2
  395. package/dist/modules/data_sync/api/run.js +7 -2
  396. package/dist/modules/data_sync/api/run.js.map +2 -2
  397. package/dist/modules/data_sync/api/runs/[id]/cancel.js +8 -3
  398. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  399. package/dist/modules/data_sync/api/runs/[id]/retry.js +7 -2
  400. package/dist/modules/data_sync/api/runs/[id]/retry.js.map +2 -2
  401. package/dist/modules/data_sync/api/runs/[id]/route.js +8 -3
  402. package/dist/modules/data_sync/api/runs/[id]/route.js.map +2 -2
  403. package/dist/modules/data_sync/api/runs.js +7 -2
  404. package/dist/modules/data_sync/api/runs.js.map +2 -2
  405. package/dist/modules/data_sync/api/schedules/[id]/route.js +19 -6
  406. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  407. package/dist/modules/data_sync/api/schedules/route.js +13 -4
  408. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  409. package/dist/modules/data_sync/api/validate.js +9 -4
  410. package/dist/modules/data_sync/api/validate.js.map +2 -2
  411. package/dist/modules/data_sync/backend/data-sync/page.js +5 -4
  412. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  413. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +5 -5
  414. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  415. package/dist/modules/data_sync/extension-points.js +13 -0
  416. package/dist/modules/data_sync/extension-points.js.map +7 -0
  417. package/dist/modules/data_sync/lib/queue-policy.js +15 -0
  418. package/dist/modules/data_sync/lib/queue-policy.js.map +7 -0
  419. package/dist/modules/data_sync/lib/queue.js +16 -1
  420. package/dist/modules/data_sync/lib/queue.js.map +2 -2
  421. package/dist/modules/data_sync/lib/start-run.js +2 -1
  422. package/dist/modules/data_sync/lib/start-run.js.map +2 -2
  423. package/dist/modules/data_sync/lib/sync-engine.js +35 -2
  424. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  425. package/dist/modules/data_sync/lib/sync-run-service.js +70 -2
  426. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  427. package/dist/modules/data_sync/workers/sync-export.js +9 -2
  428. package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
  429. package/dist/modules/data_sync/workers/sync-import.js +9 -2
  430. package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
  431. package/dist/modules/design_system/acl.js +9 -0
  432. package/dist/modules/design_system/acl.js.map +7 -0
  433. package/dist/modules/design_system/backend/design-system/page.js +11 -0
  434. package/dist/modules/design_system/backend/design-system/page.js.map +7 -0
  435. package/dist/modules/design_system/backend/design-system/page.meta.js +15 -0
  436. package/dist/modules/design_system/backend/design-system/page.meta.js.map +7 -0
  437. package/dist/modules/design_system/gallery/components/CodeSnippet.js +52 -0
  438. package/dist/modules/design_system/gallery/components/CodeSnippet.js.map +7 -0
  439. package/dist/modules/design_system/gallery/components/EntryCard.js +63 -0
  440. package/dist/modules/design_system/gallery/components/EntryCard.js.map +7 -0
  441. package/dist/modules/design_system/gallery/components/GalleryShell.js +163 -0
  442. package/dist/modules/design_system/gallery/components/GalleryShell.js.map +7 -0
  443. package/dist/modules/design_system/gallery/components/VariantPreview.js +9 -0
  444. package/dist/modules/design_system/gallery/components/VariantPreview.js.map +7 -0
  445. package/dist/modules/design_system/gallery/entries/banners.js +186 -0
  446. package/dist/modules/design_system/gallery/entries/banners.js.map +7 -0
  447. package/dist/modules/design_system/gallery/entries/buttons.js +361 -0
  448. package/dist/modules/design_system/gallery/entries/buttons.js.map +7 -0
  449. package/dist/modules/design_system/gallery/entries/charts.js +457 -0
  450. package/dist/modules/design_system/gallery/entries/charts.js.map +7 -0
  451. package/dist/modules/design_system/gallery/entries/dates.js +306 -0
  452. package/dist/modules/design_system/gallery/entries/dates.js.map +7 -0
  453. package/dist/modules/design_system/gallery/entries/detail.js +358 -0
  454. package/dist/modules/design_system/gallery/entries/detail.js.map +7 -0
  455. package/dist/modules/design_system/gallery/entries/display.js +785 -0
  456. package/dist/modules/design_system/gallery/entries/display.js.map +7 -0
  457. package/dist/modules/design_system/gallery/entries/feedback.js +658 -0
  458. package/dist/modules/design_system/gallery/entries/feedback.js.map +7 -0
  459. package/dist/modules/design_system/gallery/entries/filters.js +505 -0
  460. package/dist/modules/design_system/gallery/entries/filters.js.map +7 -0
  461. package/dist/modules/design_system/gallery/entries/foundations.js +453 -0
  462. package/dist/modules/design_system/gallery/entries/foundations.js.map +7 -0
  463. package/dist/modules/design_system/gallery/entries/icons.js +140 -0
  464. package/dist/modules/design_system/gallery/entries/icons.js.map +7 -0
  465. package/dist/modules/design_system/gallery/entries/inputs.js +1217 -0
  466. package/dist/modules/design_system/gallery/entries/inputs.js.map +7 -0
  467. package/dist/modules/design_system/gallery/entries/messages.js +334 -0
  468. package/dist/modules/design_system/gallery/entries/messages.js.map +7 -0
  469. package/dist/modules/design_system/gallery/entries/navigation.js +475 -0
  470. package/dist/modules/design_system/gallery/entries/navigation.js.map +7 -0
  471. package/dist/modules/design_system/gallery/entries/notifications.js +257 -0
  472. package/dist/modules/design_system/gallery/entries/notifications.js.map +7 -0
  473. package/dist/modules/design_system/gallery/entries/overlays.js +576 -0
  474. package/dist/modules/design_system/gallery/entries/overlays.js.map +7 -0
  475. package/dist/modules/design_system/gallery/entries/scaffolding.js +378 -0
  476. package/dist/modules/design_system/gallery/entries/scaffolding.js.map +7 -0
  477. package/dist/modules/design_system/gallery/entries/schedule.js +297 -0
  478. package/dist/modules/design_system/gallery/entries/schedule.js.map +7 -0
  479. package/dist/modules/design_system/gallery/registry.js +139 -0
  480. package/dist/modules/design_system/gallery/registry.js.map +7 -0
  481. package/dist/modules/design_system/gallery/types.js +1 -0
  482. package/dist/modules/design_system/gallery/types.js.map +7 -0
  483. package/dist/modules/design_system/index.js +9 -0
  484. package/dist/modules/design_system/index.js.map +7 -0
  485. package/dist/modules/design_system/setup.js +14 -0
  486. package/dist/modules/design_system/setup.js.map +7 -0
  487. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +34 -12
  488. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  489. package/dist/modules/dictionaries/api/openapi.js +15 -2
  490. package/dist/modules/dictionaries/api/openapi.js.map +2 -2
  491. package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +1 -1
  492. package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
  493. package/dist/modules/dictionaries/components/hooks/useDictionaryEntries.js +30 -29
  494. package/dist/modules/dictionaries/components/hooks/useDictionaryEntries.js.map +2 -2
  495. package/dist/modules/dictionaries/data/validators.js +7 -0
  496. package/dist/modules/dictionaries/data/validators.js.map +2 -2
  497. package/dist/modules/dictionaries/lib/clientEntries.js +4 -3
  498. package/dist/modules/dictionaries/lib/clientEntries.js.map +2 -2
  499. package/dist/modules/dictionaries/lib/fetchAllEntries.js +43 -0
  500. package/dist/modules/dictionaries/lib/fetchAllEntries.js.map +7 -0
  501. package/dist/modules/directory/api/organization-branding/route.js +10 -3
  502. package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
  503. package/dist/modules/directory/api/organization-switcher/route.js +84 -20
  504. package/dist/modules/directory/api/organization-switcher/route.js.map +2 -2
  505. package/dist/modules/directory/api/organizations/route.js +7 -0
  506. package/dist/modules/directory/api/organizations/route.js.map +3 -3
  507. package/dist/modules/directory/api/tenants/route.js +8 -2
  508. package/dist/modules/directory/api/tenants/route.js.map +2 -2
  509. package/dist/modules/directory/backend/directory/branding/page.js +31 -8
  510. package/dist/modules/directory/backend/directory/branding/page.js.map +2 -2
  511. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +7 -16
  512. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  513. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  514. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  515. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  516. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  517. package/dist/modules/directory/commands/organizations.js +8 -1
  518. package/dist/modules/directory/commands/organizations.js.map +2 -2
  519. package/dist/modules/directory/commands/tenants.js +6 -0
  520. package/dist/modules/directory/commands/tenants.js.map +2 -2
  521. package/dist/modules/directory/data/entities.js +4 -0
  522. package/dist/modules/directory/data/entities.js.map +2 -2
  523. package/dist/modules/directory/data/validators.js +2 -0
  524. package/dist/modules/directory/data/validators.js.map +2 -2
  525. package/dist/modules/directory/extension-points.js +14 -0
  526. package/dist/modules/directory/extension-points.js.map +7 -0
  527. package/dist/modules/directory/migrations/Migration20260626145500_directory_logo_preserve_aspect_ratio.js +13 -0
  528. package/dist/modules/directory/migrations/Migration20260626145500_directory_logo_preserve_aspect_ratio.js.map +7 -0
  529. package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js +5 -1
  530. package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js.map +2 -2
  531. package/dist/modules/directory/utils/organizationScope.js +11 -3
  532. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  533. package/dist/modules/entities/api/definitions.js +53 -3
  534. package/dist/modules/entities/api/definitions.js.map +2 -2
  535. package/dist/modules/entities/api/entities.js +21 -2
  536. package/dist/modules/entities/api/entities.js.map +2 -2
  537. package/dist/modules/entities/api/entity-settings.js +59 -9
  538. package/dist/modules/entities/api/entity-settings.js.map +2 -2
  539. package/dist/modules/entities/api/records.js +11 -28
  540. package/dist/modules/entities/api/records.js.map +2 -2
  541. package/dist/modules/entities/api/sidebar-entities.js +34 -12
  542. package/dist/modules/entities/api/sidebar-entities.js.map +2 -2
  543. package/dist/modules/entities/backend/config/settings/page.js +10 -0
  544. package/dist/modules/entities/backend/config/settings/page.js.map +7 -0
  545. package/dist/modules/entities/backend/config/settings/page.meta.js +36 -0
  546. package/dist/modules/entities/backend/config/settings/page.meta.js.map +7 -0
  547. package/dist/modules/entities/backend/entities/user/[entityId]/page.js +1 -1
  548. package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
  549. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +23 -4
  550. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  551. package/dist/modules/entities/backend/entities/user/create/page.js +16 -7
  552. package/dist/modules/entities/backend/entities/user/create/page.js.map +2 -2
  553. package/dist/modules/entities/cli.js +193 -19
  554. package/dist/modules/entities/cli.js.map +2 -2
  555. package/dist/modules/entities/components/EntitySettingsManager.js +136 -0
  556. package/dist/modules/entities/components/EntitySettingsManager.js.map +7 -0
  557. package/dist/modules/entities/components/RecordListRelationCell.js +63 -0
  558. package/dist/modules/entities/components/RecordListRelationCell.js.map +7 -0
  559. package/dist/modules/entities/components/SystemEntitiesTable.js +2 -1
  560. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  561. package/dist/modules/entities/components/UserEntitiesTable.js +2 -1
  562. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  563. package/dist/modules/entities/components/recordListRelationDisplays.js +80 -0
  564. package/dist/modules/entities/components/recordListRelationDisplays.js.map +7 -0
  565. package/dist/modules/entities/extension-points.js +21 -0
  566. package/dist/modules/entities/extension-points.js.map +7 -0
  567. package/dist/modules/entities/lib/entityAcl.js +87 -9
  568. package/dist/modules/entities/lib/entityAcl.js.map +3 -3
  569. package/dist/modules/feature_toggles/components/FeatureGuard.js +3 -2
  570. package/dist/modules/feature_toggles/components/FeatureGuard.js.map +2 -2
  571. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +1 -1
  572. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
  573. package/dist/modules/feature_toggles/components/hooks/staleTime.js +5 -0
  574. package/dist/modules/feature_toggles/components/hooks/staleTime.js.map +7 -0
  575. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagBoolean.js +5 -2
  576. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagBoolean.js.map +2 -2
  577. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagJson.js +5 -2
  578. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagJson.js.map +2 -2
  579. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagNumber.js +5 -2
  580. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagNumber.js.map +2 -2
  581. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagString.js +5 -2
  582. package/dist/modules/feature_toggles/components/hooks/useFeatureFlagString.js.map +2 -2
  583. package/dist/modules/inbox_ops/ai-tools.js +5 -2
  584. package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
  585. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js +14 -1
  586. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js.map +2 -2
  587. package/dist/modules/inbox_ops/api/proposals/route.js +16 -1
  588. package/dist/modules/inbox_ops/api/proposals/route.js.map +2 -2
  589. package/dist/modules/inbox_ops/api/webhook/inbound.js +14 -10
  590. package/dist/modules/inbox_ops/api/webhook/inbound.js.map +2 -2
  591. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +6 -6
  592. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  593. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +25 -20
  594. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  595. package/dist/modules/inbox_ops/search.js +15 -4
  596. package/dist/modules/inbox_ops/search.js.map +2 -2
  597. package/dist/modules/inbox_ops/subscribers/search-reindex-proposal-created.js +32 -0
  598. package/dist/modules/inbox_ops/subscribers/search-reindex-proposal-created.js.map +7 -0
  599. package/dist/modules/integrations/api/[id]/credentials/route.js +11 -5
  600. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  601. package/dist/modules/integrations/api/[id]/health/route.js +6 -3
  602. package/dist/modules/integrations/api/[id]/health/route.js.map +2 -2
  603. package/dist/modules/integrations/api/[id]/route.js +6 -3
  604. package/dist/modules/integrations/api/[id]/route.js.map +2 -2
  605. package/dist/modules/integrations/api/[id]/state/route.js +6 -3
  606. package/dist/modules/integrations/api/[id]/state/route.js.map +2 -2
  607. package/dist/modules/integrations/api/[id]/version/route.js +6 -3
  608. package/dist/modules/integrations/api/[id]/version/route.js.map +2 -2
  609. package/dist/modules/integrations/api/logs/route.js +6 -3
  610. package/dist/modules/integrations/api/logs/route.js.map +2 -2
  611. package/dist/modules/integrations/api/route.js +6 -3
  612. package/dist/modules/integrations/api/route.js.map +2 -2
  613. package/dist/modules/integrations/api/umes-read.js +2 -2
  614. package/dist/modules/integrations/api/umes-read.js.map +2 -2
  615. package/dist/modules/integrations/backend/integrations/[id]/page.js +2 -4
  616. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  617. package/dist/modules/integrations/extension-points.js +30 -0
  618. package/dist/modules/integrations/extension-points.js.map +7 -0
  619. package/dist/modules/integrations/lib/organization-scope.js +2 -9
  620. package/dist/modules/integrations/lib/organization-scope.js.map +2 -2
  621. package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +0 -5
  622. package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +2 -2
  623. package/dist/modules/integrations/widgets/injection/external-ids/widget.js +14 -0
  624. package/dist/modules/integrations/widgets/injection/external-ids/widget.js.map +7 -0
  625. package/dist/modules/messages/api/[id]/route.js +15 -0
  626. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  627. package/dist/modules/messages/api/route.js +77 -8
  628. package/dist/modules/messages/api/route.js.map +2 -2
  629. package/dist/modules/messages/components/ComposeMessagePageClient.js +2 -1
  630. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +2 -2
  631. package/dist/modules/messages/components/MessageDetailPageClient.js +3 -2
  632. package/dist/modules/messages/components/MessageDetailPageClient.js.map +2 -2
  633. package/dist/modules/messages/components/MessagesInboxPageClient.js +2 -1
  634. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  635. package/dist/modules/messages/components/message-detail/panels/dialogs.js +1 -1
  636. package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +1 -1
  637. package/dist/modules/messages/extension-points.js +16 -0
  638. package/dist/modules/messages/extension-points.js.map +7 -0
  639. package/dist/modules/messages/lib/participantScope.js +15 -0
  640. package/dist/modules/messages/lib/participantScope.js.map +7 -0
  641. package/dist/modules/messages/lib/routeHelpers.js +1 -3
  642. package/dist/modules/messages/lib/routeHelpers.js.map +2 -2
  643. package/dist/modules/messages/lib/searchLookup.js +8 -16
  644. package/dist/modules/messages/lib/searchLookup.js.map +2 -2
  645. package/dist/modules/messages/search.js +10 -5
  646. package/dist/modules/messages/search.js.map +2 -2
  647. package/dist/modules/notifications/api/route.js +83 -4
  648. package/dist/modules/notifications/api/route.js.map +2 -2
  649. package/dist/modules/notifications/api/unread-count/route.js +25 -6
  650. package/dist/modules/notifications/api/unread-count/route.js.map +2 -2
  651. package/dist/modules/notifications/di.js +1 -1
  652. package/dist/modules/notifications/di.js.map +2 -2
  653. package/dist/modules/notifications/events.js +4 -2
  654. package/dist/modules/notifications/events.js.map +2 -2
  655. package/dist/modules/notifications/lib/notificationRecipients.js +6 -7
  656. package/dist/modules/notifications/lib/notificationRecipients.js.map +2 -2
  657. package/dist/modules/notifications/lib/notificationScope.js +26 -0
  658. package/dist/modules/notifications/lib/notificationScope.js.map +7 -0
  659. package/dist/modules/notifications/lib/notificationService.js +48 -4
  660. package/dist/modules/notifications/lib/notificationService.js.map +2 -2
  661. package/dist/modules/notifications/lib/routeHelpers.js +16 -2
  662. package/dist/modules/notifications/lib/routeHelpers.js.map +2 -2
  663. package/dist/modules/payment_gateways/api/capture/route.js +1 -1
  664. package/dist/modules/payment_gateways/api/capture/route.js.map +2 -2
  665. package/dist/modules/payment_gateways/api/sessions/route.js +6 -3
  666. package/dist/modules/payment_gateways/api/sessions/route.js.map +2 -2
  667. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +11 -1
  668. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  669. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -2
  670. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  671. package/dist/modules/payment_gateways/data/entities.js +11 -0
  672. package/dist/modules/payment_gateways/data/entities.js.map +2 -2
  673. package/dist/modules/payment_gateways/di.js +17 -1
  674. package/dist/modules/payment_gateways/di.js.map +2 -2
  675. package/dist/modules/payment_gateways/extension-points.js +19 -0
  676. package/dist/modules/payment_gateways/extension-points.js.map +7 -0
  677. package/dist/modules/payment_gateways/lib/capture-ledger.js +183 -0
  678. package/dist/modules/payment_gateways/lib/capture-ledger.js.map +7 -0
  679. package/dist/modules/payment_gateways/lib/gateway-service.js +93 -14
  680. package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
  681. package/dist/modules/payment_gateways/lib/order-amount-reconciliation.js +58 -0
  682. package/dist/modules/payment_gateways/lib/order-amount-reconciliation.js.map +7 -0
  683. package/dist/modules/payment_gateways/lib/payment-operation-idempotency.js +1 -0
  684. package/dist/modules/payment_gateways/lib/payment-operation-idempotency.js.map +2 -2
  685. package/dist/modules/payment_gateways/lib/session-idempotency.js +33 -0
  686. package/dist/modules/payment_gateways/lib/session-idempotency.js.map +2 -2
  687. package/dist/modules/payment_gateways/migrations/Migration20260725101500_payment_gateways.js +16 -0
  688. package/dist/modules/payment_gateways/migrations/Migration20260725101500_payment_gateways.js.map +7 -0
  689. package/dist/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.js +18 -0
  690. package/dist/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.js.map +7 -0
  691. package/dist/modules/payment_gateways/setup.js +47 -0
  692. package/dist/modules/payment_gateways/setup.js.map +2 -2
  693. package/dist/modules/payment_gateways/workers/session-initialization-prune.js +50 -0
  694. package/dist/modules/payment_gateways/workers/session-initialization-prune.js.map +7 -0
  695. package/dist/modules/planner/components/AvailabilityRulesEditor.js +4 -4
  696. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  697. package/dist/modules/planner/components/unavailabilityReasons.js +3 -3
  698. package/dist/modules/planner/components/unavailabilityReasons.js.map +2 -2
  699. package/dist/modules/portal/extension-points.js +32 -0
  700. package/dist/modules/portal/extension-points.js.map +7 -0
  701. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +3 -3
  702. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
  703. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js +134 -0
  704. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js.map +7 -0
  705. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.js +11 -0
  706. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.js.map +7 -0
  707. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +4 -4
  708. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
  709. package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -3
  710. package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
  711. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +3 -3
  712. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
  713. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +4 -4
  714. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +2 -2
  715. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +4 -4
  716. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
  717. package/dist/modules/portal/frontend/[orgSlug]/portal/verify/page.js +1 -1
  718. package/dist/modules/portal/frontend/[orgSlug]/portal/verify/page.js.map +2 -2
  719. package/dist/modules/portal/lib/navigation.js +7 -0
  720. package/dist/modules/portal/lib/navigation.js.map +7 -0
  721. package/dist/modules/progress/lib/progressService.js +2 -0
  722. package/dist/modules/progress/lib/progressService.js.map +2 -2
  723. package/dist/modules/progress/lib/progressServiceImpl.js +322 -104
  724. package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
  725. package/dist/modules/query_index/api/openapi.js +13 -1
  726. package/dist/modules/query_index/api/openapi.js.map +2 -2
  727. package/dist/modules/query_index/api/reindex.js +10 -0
  728. package/dist/modules/query_index/api/reindex.js.map +2 -2
  729. package/dist/modules/query_index/api/status.js +165 -105
  730. package/dist/modules/query_index/api/status.js.map +2 -2
  731. package/dist/modules/query_index/cli.js +125 -1
  732. package/dist/modules/query_index/cli.js.map +2 -2
  733. package/dist/modules/query_index/components/QueryIndexesTable.js +130 -42
  734. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  735. package/dist/modules/query_index/data/entities.js +2 -1
  736. package/dist/modules/query_index/data/entities.js.map +2 -2
  737. package/dist/modules/query_index/di.js +3 -0
  738. package/dist/modules/query_index/di.js.map +2 -2
  739. package/dist/modules/query_index/events.js +20 -0
  740. package/dist/modules/query_index/events.js.map +7 -0
  741. package/dist/modules/query_index/extension-points.js +13 -0
  742. package/dist/modules/query_index/extension-points.js.map +7 -0
  743. package/dist/modules/query_index/lib/batch.js +11 -4
  744. package/dist/modules/query_index/lib/batch.js.map +2 -2
  745. package/dist/modules/query_index/lib/coverage.js +21 -9
  746. package/dist/modules/query_index/lib/coverage.js.map +2 -2
  747. package/dist/modules/query_index/lib/document.js +12 -5
  748. package/dist/modules/query_index/lib/document.js.map +2 -2
  749. package/dist/modules/query_index/lib/engine.js +105 -48
  750. package/dist/modules/query_index/lib/engine.js.map +2 -2
  751. package/dist/modules/query_index/lib/indexer.js +95 -19
  752. package/dist/modules/query_index/lib/indexer.js.map +2 -2
  753. package/dist/modules/query_index/lib/reindexer.js +43 -37
  754. package/dist/modules/query_index/lib/reindexer.js.map +2 -2
  755. package/dist/modules/query_index/lib/search-tokens.js +34 -15
  756. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  757. package/dist/modules/query_index/lib/subscriber-scope.js +2 -3
  758. package/dist/modules/query_index/lib/subscriber-scope.js.map +2 -2
  759. package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js +17 -0
  760. package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js.map +7 -0
  761. package/dist/modules/query_index/subscribers/coverage_refresh.js +4 -0
  762. package/dist/modules/query_index/subscribers/coverage_refresh.js.map +2 -2
  763. package/dist/modules/query_index/subscribers/delete_one.js +53 -1
  764. package/dist/modules/query_index/subscribers/delete_one.js.map +3 -3
  765. package/dist/modules/query_index/subscribers/upsert_one.js +60 -0
  766. package/dist/modules/query_index/subscribers/upsert_one.js.map +3 -3
  767. package/dist/modules/resources/api/resources.js +2 -0
  768. package/dist/modules/resources/api/resources.js.map +2 -2
  769. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -1
  770. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  771. package/dist/modules/resources/backend/resources/resources/[id]/page.js +3 -2
  772. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  773. package/dist/modules/resources/backend/resources/resources/page.js +2 -1
  774. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  775. package/dist/modules/resources/commands/resources.js +9 -0
  776. package/dist/modules/resources/commands/resources.js.map +2 -2
  777. package/dist/modules/resources/components/detail/dictionaries.js +3 -3
  778. package/dist/modules/resources/components/detail/dictionaries.js.map +2 -2
  779. package/dist/modules/resources/data/entities.js +3 -0
  780. package/dist/modules/resources/data/entities.js.map +2 -2
  781. package/dist/modules/resources/data/validators.js +6 -2
  782. package/dist/modules/resources/data/validators.js.map +2 -2
  783. package/dist/modules/resources/extension-points.js +14 -0
  784. package/dist/modules/resources/extension-points.js.map +7 -0
  785. package/dist/modules/resources/lib/seeds.js +16 -9
  786. package/dist/modules/resources/lib/seeds.js.map +2 -2
  787. package/dist/modules/resources/migrations/Migration20260608231000.js +13 -0
  788. package/dist/modules/resources/migrations/Migration20260608231000.js.map +7 -0
  789. package/dist/modules/sales/analytics.js +7 -3
  790. package/dist/modules/sales/analytics.js.map +2 -2
  791. package/dist/modules/sales/api/document-history/route.js +2 -1
  792. package/dist/modules/sales/api/document-history/route.js.map +2 -2
  793. package/dist/modules/sales/api/documents/factory.js +14 -3
  794. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  795. package/dist/modules/sales/backend/sales/documents/[id]/page.js +11 -3
  796. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  797. package/dist/modules/sales/backend/sales/documents/create/page.js +11 -14
  798. package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
  799. package/dist/modules/sales/commands/documents.js +184 -23
  800. package/dist/modules/sales/commands/documents.js.map +2 -2
  801. package/dist/modules/sales/components/documents/ItemsSection.js +31 -11
  802. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  803. package/dist/modules/sales/components/documents/LineItemDialog.js +12 -5
  804. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  805. package/dist/modules/sales/components/documents/SalesDocumentForm.js +48 -2
  806. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  807. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -1
  808. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  809. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +167 -0
  810. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +7 -0
  811. package/dist/modules/sales/components/useSalesChannelsEnabled.js +2 -35
  812. package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +2 -2
  813. package/dist/modules/sales/data/validators.js +32 -5
  814. package/dist/modules/sales/data/validators.js.map +2 -2
  815. package/dist/modules/sales/di.js +7 -0
  816. package/dist/modules/sales/di.js.map +2 -2
  817. package/dist/modules/sales/events.js +1 -0
  818. package/dist/modules/sales/events.js.map +2 -2
  819. package/dist/modules/sales/extension-points.js +36 -0
  820. package/dist/modules/sales/extension-points.js.map +7 -0
  821. package/dist/modules/sales/lib/historyHelpers.js +69 -1
  822. package/dist/modules/sales/lib/historyHelpers.js.map +2 -2
  823. package/dist/modules/sales/services/paymentOrderTotalResolver.js +52 -0
  824. package/dist/modules/sales/services/paymentOrderTotalResolver.js.map +7 -0
  825. package/dist/modules/sales/widgets/injection/document-history/widget.client.js +51 -2
  826. package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
  827. package/dist/modules/sales/workflows.js +10 -7
  828. package/dist/modules/sales/workflows.js.map +2 -2
  829. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +11 -1
  830. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +2 -2
  831. package/dist/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.js +1 -1
  832. package/dist/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.js.map +1 -1
  833. package/dist/modules/staff/api/interceptors.js +5 -3
  834. package/dist/modules/staff/api/interceptors.js.map +2 -2
  835. package/dist/modules/staff/api/leave-requests.js +45 -42
  836. package/dist/modules/staff/api/leave-requests.js.map +2 -2
  837. package/dist/modules/staff/components/detail/dictionaries.js +3 -3
  838. package/dist/modules/staff/components/detail/dictionaries.js.map +2 -2
  839. package/dist/modules/sync_excel/api/upload/route.js +15 -2
  840. package/dist/modules/sync_excel/api/upload/route.js.map +2 -2
  841. package/dist/modules/sync_excel/widgets/injection/upload-config/widget.client.js +1 -1
  842. package/dist/modules/sync_excel/widgets/injection/upload-config/widget.client.js.map +2 -2
  843. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js +1 -1
  844. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js.map +1 -1
  845. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +5 -4
  846. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
  847. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +4 -3
  848. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  849. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +3 -2
  850. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
  851. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +3 -2
  852. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
  853. package/dist/modules/wms/components/backend/WmsLotsListPage.js +2 -1
  854. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  855. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +3 -2
  856. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
  857. package/dist/modules/wms/extension-points.js +26 -0
  858. package/dist/modules/wms/extension-points.js.map +7 -0
  859. package/dist/modules/workflows/backend/definitions/[id]/page.js +2 -2
  860. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  861. package/dist/modules/workflows/backend/definitions/create/page.js +1 -1
  862. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  863. package/dist/modules/workflows/backend/definitions/page.js +3 -2
  864. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  865. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +9 -6
  866. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  867. package/dist/modules/workflows/backend/instances/page.js +10 -9
  868. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  869. package/dist/modules/workflows/backend/tasks/page.js +8 -7
  870. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  871. package/dist/modules/workflows/components/ActivitiesEditor.js +69 -13
  872. package/dist/modules/workflows/components/ActivitiesEditor.js.map +2 -2
  873. package/dist/modules/workflows/components/BusinessRulesSelector.js +1 -1
  874. package/dist/modules/workflows/components/BusinessRulesSelector.js.map +2 -2
  875. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +3 -3
  876. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
  877. package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js +1 -2
  878. package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js.map +2 -2
  879. package/dist/modules/workflows/components/NodeEditDialog.js +3 -3
  880. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  881. package/dist/modules/workflows/components/NodeEditDialogCrudForm.js +4 -5
  882. package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +2 -2
  883. package/dist/modules/workflows/components/StepsEditor.js +2 -2
  884. package/dist/modules/workflows/components/StepsEditor.js.map +2 -2
  885. package/dist/modules/workflows/components/TransitionsEditor.js +207 -165
  886. package/dist/modules/workflows/components/TransitionsEditor.js.map +2 -2
  887. package/dist/modules/workflows/components/WorkflowGraphImpl.js +1 -1
  888. package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
  889. package/dist/modules/workflows/components/WorkflowLegend.js +1 -1
  890. package/dist/modules/workflows/components/WorkflowLegend.js.map +2 -2
  891. package/dist/modules/workflows/components/WorkflowSelector.js +1 -1
  892. package/dist/modules/workflows/components/WorkflowSelector.js.map +2 -2
  893. package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +1 -1
  894. package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
  895. package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +2 -2
  896. package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +2 -2
  897. package/dist/modules/workflows/components/fields/MappingArrayEditor.js +1 -1
  898. package/dist/modules/workflows/components/fields/MappingArrayEditor.js.map +2 -2
  899. package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +1 -1
  900. package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
  901. package/dist/modules/workflows/components/fields/WorkflowSelectorField.js +4 -4
  902. package/dist/modules/workflows/components/fields/WorkflowSelectorField.js.map +2 -2
  903. package/dist/modules/workflows/data/validators.js +34 -1
  904. package/dist/modules/workflows/data/validators.js.map +3 -3
  905. package/dist/modules/workflows/events.js +1 -0
  906. package/dist/modules/workflows/events.js.map +2 -2
  907. package/dist/modules/workflows/extension-points.js +15 -0
  908. package/dist/modules/workflows/extension-points.js.map +7 -0
  909. package/dist/modules/workflows/lib/activity-executor.js +59 -14
  910. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  911. package/dist/modules/workflows/lib/format-validation-error.js +46 -1
  912. package/dist/modules/workflows/lib/format-validation-error.js.map +2 -2
  913. package/dist/modules/workflows/widgets/injection/order-approval/context-keys.js +10 -0
  914. package/dist/modules/workflows/widgets/injection/order-approval/context-keys.js.map +7 -0
  915. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +21 -10
  916. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +2 -2
  917. package/generated/entities/attachment_quota_reservation/index.ts +15 -0
  918. package/generated/entities/customer_deal_person_link/index.ts +1 -0
  919. package/generated/entities/customer_user_invitation/index.ts +1 -0
  920. package/generated/entities/gateway_payment_operation/index.ts +1 -0
  921. package/generated/entities/gateway_transaction/index.ts +1 -0
  922. package/generated/entities/organization/index.ts +1 -0
  923. package/generated/entities/resources_resource/index.ts +1 -0
  924. package/generated/entities.ids.generated.ts +3 -1
  925. package/generated/entity-fields-registry.ts +23 -0
  926. package/package.json +19 -18
  927. package/src/bootstrap.ts +17 -2
  928. package/src/helpers/integration/salesFixtures.ts +34 -2
  929. package/src/helpers/integration/salesUi.ts +8 -0
  930. package/src/modules/api_keys/backend/api-keys/page.tsx +2 -1
  931. package/src/modules/api_keys/extension-points.ts +13 -0
  932. package/src/modules/api_keys/i18n/ko.json +42 -0
  933. package/src/modules/attachments/api/route.ts +130 -9
  934. package/src/modules/attachments/backend/config/attachments/page.tsx +1 -1
  935. package/src/modules/attachments/data/entities.ts +59 -0
  936. package/src/modules/attachments/di.ts +9 -1
  937. package/src/modules/attachments/fields/attachment.tsx +1 -1
  938. package/src/modules/attachments/i18n/de.json +15 -0
  939. package/src/modules/attachments/i18n/en.json +15 -0
  940. package/src/modules/attachments/i18n/es.json +15 -0
  941. package/src/modules/attachments/i18n/ko.json +175 -0
  942. package/src/modules/attachments/i18n/pl.json +15 -0
  943. package/src/modules/attachments/lib/drivers/index.ts +1 -1
  944. package/src/modules/attachments/lib/drivers/localDriver.ts +23 -8
  945. package/src/modules/attachments/lib/drivers/types.ts +5 -0
  946. package/src/modules/attachments/lib/quota-recovery-queue.ts +16 -0
  947. package/src/modules/attachments/lib/quota-service.ts +442 -0
  948. package/src/modules/attachments/lib/upload-limits.ts +35 -0
  949. package/src/modules/attachments/migrations/.snapshot-open-mercato.json +648 -120
  950. package/src/modules/attachments/migrations/Migration20260709234741_attachments.ts +12 -0
  951. package/src/modules/attachments/workers/quota-recovery.ts +68 -0
  952. package/src/modules/audit_logs/api/audit-logs/access/route.ts +5 -0
  953. package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +5 -0
  954. package/src/modules/audit_logs/api/audit-logs/actions/route.ts +5 -0
  955. package/src/modules/audit_logs/api/audit-logs/readScope.ts +28 -0
  956. package/src/modules/audit_logs/components/AccessLogsTable.tsx +2 -1
  957. package/src/modules/audit_logs/components/AuditLogsActions.tsx +3 -2
  958. package/src/modules/audit_logs/extension-points.ts +11 -0
  959. package/src/modules/audit_logs/i18n/ko.json +66 -0
  960. package/src/modules/auth/AGENTS.md +12 -8
  961. package/src/modules/auth/api/admin/nav.ts +28 -4
  962. package/src/modules/auth/api/profile/route.ts +8 -2
  963. package/src/modules/auth/api/users/route.ts +8 -28
  964. package/src/modules/auth/backend/auth/profile/page.tsx +1 -0
  965. package/src/modules/auth/backend/profile/change-password/page.tsx +1 -0
  966. package/src/modules/auth/backend/roles/page.tsx +2 -1
  967. package/src/modules/auth/backend/settings/page.tsx +17 -8
  968. package/src/modules/auth/backend/users/page.tsx +2 -1
  969. package/src/modules/auth/cli.ts +1 -1
  970. package/src/modules/auth/components/UserConsentsPanel.tsx +9 -9
  971. package/src/modules/auth/extension-points.ts +18 -0
  972. package/src/modules/auth/frontend/login.tsx +7 -3
  973. package/src/modules/auth/frontend/reset.tsx +2 -2
  974. package/src/modules/auth/i18n/de.json +1 -0
  975. package/src/modules/auth/i18n/en.json +1 -0
  976. package/src/modules/auth/i18n/es.json +1 -0
  977. package/src/modules/auth/i18n/ko.json +255 -0
  978. package/src/modules/auth/i18n/pl.json +1 -0
  979. package/src/modules/auth/lib/backendChrome.tsx +71 -33
  980. package/src/modules/auth/lib/setup-app.ts +21 -2
  981. package/src/modules/auth/lib/tenantAccess.ts +8 -0
  982. package/src/modules/auth/services/rbacService.ts +41 -46
  983. package/src/modules/business_rules/api/openmercato-call-options/route.ts +94 -0
  984. package/src/modules/business_rules/api/rules/route.ts +92 -4
  985. package/src/modules/business_rules/backend/rules/page.tsx +2 -1
  986. package/src/modules/business_rules/components/ActionBuilder.tsx +54 -5
  987. package/src/modules/business_rules/components/ActionRow.tsx +156 -18
  988. package/src/modules/business_rules/components/ConditionRow.tsx +9 -6
  989. package/src/modules/business_rules/components/utils/actionValidation.ts +6 -0
  990. package/src/modules/business_rules/events.ts +10 -0
  991. package/src/modules/business_rules/extension-points.ts +10 -0
  992. package/src/modules/business_rules/i18n/de.json +12 -0
  993. package/src/modules/business_rules/i18n/en.json +12 -0
  994. package/src/modules/business_rules/i18n/es.json +12 -0
  995. package/src/modules/business_rules/i18n/ko.json +396 -0
  996. package/src/modules/business_rules/i18n/pl.json +12 -0
  997. package/src/modules/business_rules/lib/action-executor.ts +198 -0
  998. package/src/modules/business_rules/lib/openmercato-call-options-types.ts +31 -0
  999. package/src/modules/business_rules/lib/openmercato-call-options.ts +297 -0
  1000. package/src/modules/business_rules/lib/rule-engine.ts +4 -0
  1001. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +6 -5
  1002. package/src/modules/catalog/backend/catalog/products/create/page.tsx +7 -6
  1003. package/src/modules/catalog/components/PriceKindSettings.tsx +3 -3
  1004. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -1
  1005. package/src/modules/catalog/components/products/ProductCategorizeSection.tsx +3 -3
  1006. package/src/modules/catalog/components/products/ProductMediaManager.tsx +1 -1
  1007. package/src/modules/catalog/components/products/ProductsDataTable.tsx +3 -2
  1008. package/src/modules/catalog/components/products/VariantBuilder.tsx +5 -5
  1009. package/src/modules/catalog/events.ts +1 -0
  1010. package/src/modules/catalog/extension-points.ts +24 -0
  1011. package/src/modules/catalog/i18n/de.json +18 -0
  1012. package/src/modules/catalog/i18n/en.json +18 -0
  1013. package/src/modules/catalog/i18n/es.json +18 -0
  1014. package/src/modules/catalog/i18n/ko.json +723 -0
  1015. package/src/modules/catalog/i18n/pl.json +18 -0
  1016. package/src/modules/catalog/widgets/injection/product-bulk-delete/widget.ts +15 -5
  1017. package/src/modules/catalog/widgets/injection/product-seo/widget.ts +1 -1
  1018. package/src/modules/communication_channels/api/post/test-seed/route.ts +69 -2
  1019. package/src/modules/communication_channels/api/post/webhook/[provider]/route.ts +11 -1
  1020. package/src/modules/communication_channels/api/post/webhooks/gmail/route.ts +17 -11
  1021. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +2 -1
  1022. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +8 -7
  1023. package/src/modules/communication_channels/data/enrichers.ts +6 -26
  1024. package/src/modules/communication_channels/extension-points.ts +17 -0
  1025. package/src/modules/communication_channels/i18n/de.json +2 -2
  1026. package/src/modules/communication_channels/i18n/en.json +2 -2
  1027. package/src/modules/communication_channels/i18n/es.json +2 -2
  1028. package/src/modules/communication_channels/i18n/ko.json +138 -0
  1029. package/src/modules/communication_channels/i18n/pl.json +2 -2
  1030. package/src/modules/communication_channels/lib/access-control.ts +3 -3
  1031. package/src/modules/configs/backend/config/system-status/page.tsx +2 -1
  1032. package/src/modules/configs/extension-points.ts +15 -0
  1033. package/src/modules/configs/i18n/ko.json +197 -0
  1034. package/src/modules/configs/lib/upgrade-actions.ts +14 -0
  1035. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  1036. package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -1
  1037. package/src/modules/currencies/di.ts +4 -1
  1038. package/src/modules/currencies/extension-points.ts +11 -0
  1039. package/src/modules/currencies/i18n/de.json +1 -0
  1040. package/src/modules/currencies/i18n/en.json +1 -0
  1041. package/src/modules/currencies/i18n/es.json +1 -0
  1042. package/src/modules/currencies/i18n/ko.json +160 -0
  1043. package/src/modules/currencies/i18n/pl.json +1 -0
  1044. package/src/modules/currencies/services/baseCurrencyService.ts +59 -0
  1045. package/src/modules/customer_accounts/AGENTS.md +3 -3
  1046. package/src/modules/customer_accounts/api/admin/users/[id].ts +16 -1
  1047. package/src/modules/customer_accounts/api/admin/users-invite.ts +81 -3
  1048. package/src/modules/customer_accounts/api/invitations/accept.ts +1 -2
  1049. package/src/modules/customer_accounts/api/login.ts +4 -2
  1050. package/src/modules/customer_accounts/api/magic-link/verify.ts +4 -2
  1051. package/src/modules/customer_accounts/api/portal/feature-check.ts +5 -7
  1052. package/src/modules/customer_accounts/api/portal/nav.ts +5 -3
  1053. package/src/modules/customer_accounts/api/portal/profile.ts +5 -1
  1054. package/src/modules/customer_accounts/api/portal/sessions-refresh.ts +3 -3
  1055. package/src/modules/customer_accounts/api/portal/users-invite.ts +25 -1
  1056. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +2 -1
  1057. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.tsx +2 -2
  1058. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +2 -1
  1059. package/src/modules/customer_accounts/data/entities.ts +3 -0
  1060. package/src/modules/customer_accounts/data/validators.ts +1 -0
  1061. package/src/modules/customer_accounts/emails/CustomerInvitationEmail.tsx +45 -0
  1062. package/src/modules/customer_accounts/extension-points.ts +11 -0
  1063. package/src/modules/customer_accounts/i18n/de.json +6 -0
  1064. package/src/modules/customer_accounts/i18n/en.json +6 -0
  1065. package/src/modules/customer_accounts/i18n/es.json +6 -0
  1066. package/src/modules/customer_accounts/i18n/ko.json +354 -0
  1067. package/src/modules/customer_accounts/i18n/pl.json +6 -0
  1068. package/src/modules/customer_accounts/lib/customerAuth.ts +8 -2
  1069. package/src/modules/customer_accounts/lib/customerAuthServer.ts +1 -0
  1070. package/src/modules/customer_accounts/lib/customerEntityOwnership.ts +68 -2
  1071. package/src/modules/customer_accounts/lib/customerUrl.ts +27 -11
  1072. package/src/modules/customer_accounts/lib/invitationEmail.ts +42 -0
  1073. package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +16 -0
  1074. package/src/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.ts +13 -0
  1075. package/src/modules/customer_accounts/services/customerInvitationService.ts +56 -3
  1076. package/src/modules/customer_accounts/services/customerRbacService.ts +16 -3
  1077. package/src/modules/customer_accounts/setup.ts +7 -0
  1078. package/src/modules/customer_accounts/subscribers/autoLinkCrm.ts +75 -8
  1079. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -2
  1080. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +1 -3
  1081. package/src/modules/customer_accounts/widgets/injection-table.ts +4 -1
  1082. package/src/modules/customers/analytics.ts +3 -0
  1083. package/src/modules/customers/api/companies/[id]/route.ts +3 -4
  1084. package/src/modules/customers/api/deals/[id]/people/route.ts +3 -0
  1085. package/src/modules/customers/api/deals/[id]/route.ts +10 -2
  1086. package/src/modules/customers/api/deals/aggregate/route.ts +5 -4
  1087. package/src/modules/customers/api/deals/summary/route.ts +15 -162
  1088. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +3 -2
  1089. package/src/modules/customers/api/utils.ts +25 -37
  1090. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +2 -1
  1091. package/src/modules/customers/backend/customers/companies/page.tsx +2 -1
  1092. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +17 -5
  1093. package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +1 -0
  1094. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +19 -12
  1095. package/src/modules/customers/backend/customers/deals/page.tsx +2 -1
  1096. package/src/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.tsx +35 -3
  1097. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +11 -2
  1098. package/src/modules/customers/backend/customers/people/[id]/page.tsx +2 -1
  1099. package/src/modules/customers/backend/customers/people/page.tsx +2 -1
  1100. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +29 -10
  1101. package/src/modules/customers/cli.ts +28 -11
  1102. package/src/modules/customers/commands/deals.ts +50 -9
  1103. package/src/modules/customers/commands/people.ts +3 -0
  1104. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -1
  1105. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
  1106. package/src/modules/customers/components/detail/ActiveDealCard.tsx +2 -1
  1107. package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +2 -3
  1108. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +30 -7
  1109. package/src/modules/customers/components/detail/CompanyKpiBar.tsx +6 -5
  1110. package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +2 -2
  1111. package/src/modules/customers/components/detail/DealDetailTabs.tsx +34 -9
  1112. package/src/modules/customers/components/detail/DealForm.tsx +5 -1
  1113. package/src/modules/customers/components/detail/DealsSection.tsx +1 -1
  1114. package/src/modules/customers/components/detail/MiniWeekCalendar.tsx +8 -57
  1115. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +34 -9
  1116. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +29 -14
  1117. package/src/modules/customers/components/detail/dashboard/helpers.ts +4 -3
  1118. package/src/modules/customers/components/detail/legacyActivities.ts +79 -0
  1119. package/src/modules/customers/components/formConfig.tsx +12 -8
  1120. package/src/modules/customers/data/entities.ts +9 -1
  1121. package/src/modules/customers/data/validators.ts +6 -1
  1122. package/src/modules/customers/extension-points.ts +40 -0
  1123. package/src/modules/customers/i18n/de.json +72 -0
  1124. package/src/modules/customers/i18n/en.json +72 -0
  1125. package/src/modules/customers/i18n/es.json +72 -0
  1126. package/src/modules/customers/i18n/ko.json +2855 -0
  1127. package/src/modules/customers/i18n/pl.json +72 -0
  1128. package/src/modules/customers/lib/calendar/format.ts +10 -4
  1129. package/src/modules/customers/lib/dealStatus.ts +48 -0
  1130. package/src/modules/customers/lib/dealsSummaryQueries.ts +211 -0
  1131. package/src/modules/customers/lib/optionalBaseCurrency.ts +34 -0
  1132. package/src/modules/customers/lib/visibilityFilter.ts +7 -5
  1133. package/src/modules/customers/migrations/.snapshot-open-mercato.json +27 -1
  1134. package/src/modules/customers/migrations/Migration20260723210000_customers.ts +15 -0
  1135. package/src/modules/customers/search.ts +59 -27
  1136. package/src/modules/customers/utils/phoneDuplicates.ts +6 -3
  1137. package/src/modules/dashboards/api/layout/[itemId]/route.ts +6 -3
  1138. package/src/modules/dashboards/api/layout/route.ts +22 -9
  1139. package/src/modules/dashboards/api/roles/widgets/route.ts +9 -3
  1140. package/src/modules/dashboards/api/users/widgets/route.ts +9 -3
  1141. package/src/modules/dashboards/api/widgets/catalog.ts +6 -3
  1142. package/src/modules/dashboards/api/widgets/data/batch/route.ts +12 -1
  1143. package/src/modules/dashboards/api/widgets/data/route.ts +29 -1
  1144. package/src/modules/dashboards/api/widgets/data/schema.ts +49 -19
  1145. package/src/modules/dashboards/components/UnlabelledAmountNotice.tsx +43 -0
  1146. package/src/modules/dashboards/i18n/de.json +5 -0
  1147. package/src/modules/dashboards/i18n/en.json +5 -0
  1148. package/src/modules/dashboards/i18n/es.json +5 -0
  1149. package/src/modules/dashboards/i18n/ko.json +118 -0
  1150. package/src/modules/dashboards/i18n/pl.json +5 -0
  1151. package/src/modules/dashboards/lib/access.ts +5 -3
  1152. package/src/modules/dashboards/lib/aggregations.ts +198 -48
  1153. package/src/modules/dashboards/lib/exactDecimal.ts +96 -0
  1154. package/src/modules/dashboards/lib/formatters.ts +137 -12
  1155. package/src/modules/dashboards/lib/optionalBaseCurrency.ts +22 -0
  1156. package/src/modules/dashboards/services/widgetDataService.ts +453 -12
  1157. package/src/modules/dashboards/subscribers/invalidateWidgetDataCache.ts +32 -0
  1158. package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.tsx +9 -3
  1159. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/config.ts +86 -0
  1160. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.tsx +42 -21
  1161. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
  1162. package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.tsx +9 -3
  1163. package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.tsx +7 -2
  1164. package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.tsx +25 -15
  1165. package/src/modules/dashboards/widgets/dashboard/top-customers/widget.client.tsx +21 -11
  1166. package/src/modules/dashboards/widgets/dashboard/top-products/widget.client.tsx +9 -3
  1167. package/src/modules/data_sync/AGENTS.md +1 -0
  1168. package/src/modules/data_sync/api/mappings/[id]/route.ts +22 -9
  1169. package/src/modules/data_sync/api/mappings/route.ts +13 -4
  1170. package/src/modules/data_sync/api/options.ts +7 -2
  1171. package/src/modules/data_sync/api/run.ts +7 -2
  1172. package/src/modules/data_sync/api/runs/[id]/cancel.ts +8 -3
  1173. package/src/modules/data_sync/api/runs/[id]/retry.ts +7 -2
  1174. package/src/modules/data_sync/api/runs/[id]/route.ts +8 -3
  1175. package/src/modules/data_sync/api/runs.ts +7 -2
  1176. package/src/modules/data_sync/api/schedules/[id]/route.ts +19 -6
  1177. package/src/modules/data_sync/api/schedules/route.ts +13 -4
  1178. package/src/modules/data_sync/api/validate.ts +9 -4
  1179. package/src/modules/data_sync/backend/data-sync/page.tsx +5 -4
  1180. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +5 -5
  1181. package/src/modules/data_sync/extension-points.ts +10 -0
  1182. package/src/modules/data_sync/i18n/ko.json +125 -0
  1183. package/src/modules/data_sync/lib/adapter.ts +18 -0
  1184. package/src/modules/data_sync/lib/queue-policy.ts +30 -0
  1185. package/src/modules/data_sync/lib/queue.ts +19 -1
  1186. package/src/modules/data_sync/lib/start-run.ts +2 -1
  1187. package/src/modules/data_sync/lib/sync-engine.ts +46 -0
  1188. package/src/modules/data_sync/lib/sync-run-service.ts +82 -1
  1189. package/src/modules/data_sync/workers/sync-export.ts +8 -1
  1190. package/src/modules/data_sync/workers/sync-import.ts +8 -1
  1191. package/src/modules/design_system/AGENTS.md +34 -0
  1192. package/src/modules/design_system/acl.ts +5 -0
  1193. package/src/modules/design_system/backend/design-system/page.meta.ts +11 -0
  1194. package/src/modules/design_system/backend/design-system/page.tsx +14 -0
  1195. package/src/modules/design_system/gallery/components/CodeSnippet.tsx +55 -0
  1196. package/src/modules/design_system/gallery/components/EntryCard.tsx +95 -0
  1197. package/src/modules/design_system/gallery/components/GalleryShell.tsx +206 -0
  1198. package/src/modules/design_system/gallery/components/VariantPreview.tsx +15 -0
  1199. package/src/modules/design_system/gallery/entries/banners.tsx +226 -0
  1200. package/src/modules/design_system/gallery/entries/buttons.tsx +422 -0
  1201. package/src/modules/design_system/gallery/entries/charts.tsx +518 -0
  1202. package/src/modules/design_system/gallery/entries/dates.tsx +325 -0
  1203. package/src/modules/design_system/gallery/entries/detail.tsx +403 -0
  1204. package/src/modules/design_system/gallery/entries/display.tsx +893 -0
  1205. package/src/modules/design_system/gallery/entries/feedback.tsx +746 -0
  1206. package/src/modules/design_system/gallery/entries/filters.tsx +570 -0
  1207. package/src/modules/design_system/gallery/entries/foundations.tsx +529 -0
  1208. package/src/modules/design_system/gallery/entries/icons.tsx +168 -0
  1209. package/src/modules/design_system/gallery/entries/inputs.tsx +1516 -0
  1210. package/src/modules/design_system/gallery/entries/messages.tsx +339 -0
  1211. package/src/modules/design_system/gallery/entries/navigation.tsx +573 -0
  1212. package/src/modules/design_system/gallery/entries/notifications.tsx +285 -0
  1213. package/src/modules/design_system/gallery/entries/overlays.tsx +677 -0
  1214. package/src/modules/design_system/gallery/entries/scaffolding.tsx +430 -0
  1215. package/src/modules/design_system/gallery/entries/schedule.tsx +307 -0
  1216. package/src/modules/design_system/gallery/registry.ts +152 -0
  1217. package/src/modules/design_system/gallery/types.ts +32 -0
  1218. package/src/modules/design_system/i18n/.hardcoded-allowlist.json +71 -0
  1219. package/src/modules/design_system/i18n/de.json +58 -0
  1220. package/src/modules/design_system/i18n/en.json +58 -0
  1221. package/src/modules/design_system/i18n/es.json +58 -0
  1222. package/src/modules/design_system/i18n/ko.json +58 -0
  1223. package/src/modules/design_system/i18n/pl.json +58 -0
  1224. package/src/modules/design_system/index.ts +7 -0
  1225. package/src/modules/design_system/setup.ts +12 -0
  1226. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +39 -11
  1227. package/src/modules/dictionaries/api/openapi.ts +19 -0
  1228. package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +1 -1
  1229. package/src/modules/dictionaries/components/hooks/useDictionaryEntries.ts +35 -36
  1230. package/src/modules/dictionaries/data/validators.ts +14 -0
  1231. package/src/modules/dictionaries/i18n/ko.json +130 -0
  1232. package/src/modules/dictionaries/lib/clientEntries.ts +4 -3
  1233. package/src/modules/dictionaries/lib/fetchAllEntries.ts +72 -0
  1234. package/src/modules/directory/api/organization-branding/route.ts +12 -1
  1235. package/src/modules/directory/api/organization-switcher/route.ts +97 -26
  1236. package/src/modules/directory/api/organizations/route.ts +7 -0
  1237. package/src/modules/directory/api/tenants/route.ts +9 -1
  1238. package/src/modules/directory/backend/directory/branding/page.tsx +34 -9
  1239. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +10 -14
  1240. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -1
  1241. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -1
  1242. package/src/modules/directory/commands/organizations.ts +9 -1
  1243. package/src/modules/directory/commands/tenants.ts +6 -0
  1244. package/src/modules/directory/data/entities.ts +3 -0
  1245. package/src/modules/directory/data/validators.ts +2 -0
  1246. package/src/modules/directory/extension-points.ts +11 -0
  1247. package/src/modules/directory/i18n/de.json +4 -1
  1248. package/src/modules/directory/i18n/en.json +4 -1
  1249. package/src/modules/directory/i18n/es.json +4 -1
  1250. package/src/modules/directory/i18n/ko.json +105 -0
  1251. package/src/modules/directory/i18n/pl.json +4 -1
  1252. package/src/modules/directory/migrations/.snapshot-open-mercato.json +18 -1
  1253. package/src/modules/directory/migrations/Migration20260626145500_directory_logo_preserve_aspect_ratio.ts +13 -0
  1254. package/src/modules/directory/subscribers/invalidateOrgScopeCache.ts +4 -1
  1255. package/src/modules/directory/utils/organizationScope.ts +9 -3
  1256. package/src/modules/entities/api/definitions.ts +55 -3
  1257. package/src/modules/entities/api/entities.ts +30 -2
  1258. package/src/modules/entities/api/entity-settings.ts +66 -22
  1259. package/src/modules/entities/api/records.ts +15 -31
  1260. package/src/modules/entities/api/sidebar-entities.ts +43 -14
  1261. package/src/modules/entities/backend/config/settings/page.meta.ts +34 -0
  1262. package/src/modules/entities/backend/config/settings/page.tsx +12 -0
  1263. package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +1 -1
  1264. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +96 -75
  1265. package/src/modules/entities/backend/entities/user/create/page.tsx +16 -7
  1266. package/src/modules/entities/cli.ts +238 -21
  1267. package/src/modules/entities/components/EntitySettingsManager.tsx +160 -0
  1268. package/src/modules/entities/components/RecordListRelationCell.tsx +90 -0
  1269. package/src/modules/entities/components/SystemEntitiesTable.tsx +2 -1
  1270. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -1
  1271. package/src/modules/entities/components/recordListRelationDisplays.ts +109 -0
  1272. package/src/modules/entities/extension-points.ts +18 -0
  1273. package/src/modules/entities/i18n/de.json +9 -0
  1274. package/src/modules/entities/i18n/en.json +9 -0
  1275. package/src/modules/entities/i18n/es.json +9 -0
  1276. package/src/modules/entities/i18n/ko.json +260 -0
  1277. package/src/modules/entities/i18n/pl.json +9 -0
  1278. package/src/modules/entities/lib/entityAcl.ts +98 -11
  1279. package/src/modules/feature_toggles/components/FeatureGuard.tsx +9 -2
  1280. package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +1 -1
  1281. package/src/modules/feature_toggles/components/hooks/staleTime.ts +5 -0
  1282. package/src/modules/feature_toggles/components/hooks/useFeatureFlagBoolean.ts +13 -1
  1283. package/src/modules/feature_toggles/components/hooks/useFeatureFlagJson.ts +12 -3
  1284. package/src/modules/feature_toggles/components/hooks/useFeatureFlagNumber.ts +10 -1
  1285. package/src/modules/feature_toggles/components/hooks/useFeatureFlagString.ts +10 -1
  1286. package/src/modules/feature_toggles/i18n/ko.json +96 -0
  1287. package/src/modules/inbox_ops/ai-tools.ts +5 -3
  1288. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.ts +17 -1
  1289. package/src/modules/inbox_ops/api/proposals/route.ts +20 -1
  1290. package/src/modules/inbox_ops/api/webhook/inbound.ts +14 -12
  1291. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +6 -6
  1292. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +24 -19
  1293. package/src/modules/inbox_ops/components/proposals/types.ts +1 -0
  1294. package/src/modules/inbox_ops/i18n/de.json +3 -0
  1295. package/src/modules/inbox_ops/i18n/en.json +3 -0
  1296. package/src/modules/inbox_ops/i18n/es.json +3 -0
  1297. package/src/modules/inbox_ops/i18n/ko.json +196 -0
  1298. package/src/modules/inbox_ops/i18n/pl.json +3 -0
  1299. package/src/modules/inbox_ops/search.ts +20 -4
  1300. package/src/modules/inbox_ops/subscribers/search-reindex-proposal-created.ts +39 -0
  1301. package/src/modules/integrations/api/[id]/credentials/route.ts +11 -5
  1302. package/src/modules/integrations/api/[id]/health/route.ts +6 -3
  1303. package/src/modules/integrations/api/[id]/route.ts +6 -3
  1304. package/src/modules/integrations/api/[id]/state/route.ts +6 -3
  1305. package/src/modules/integrations/api/[id]/version/route.ts +6 -3
  1306. package/src/modules/integrations/api/logs/route.ts +6 -3
  1307. package/src/modules/integrations/api/route.ts +6 -3
  1308. package/src/modules/integrations/api/umes-read.ts +2 -2
  1309. package/src/modules/integrations/backend/integrations/[id]/page.tsx +2 -2
  1310. package/src/modules/integrations/extension-points.ts +27 -0
  1311. package/src/modules/integrations/i18n/ko.json +129 -0
  1312. package/src/modules/integrations/lib/organization-scope.ts +5 -25
  1313. package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +0 -5
  1314. package/src/modules/integrations/widgets/injection/external-ids/widget.ts +13 -0
  1315. package/src/modules/messages/api/[id]/route.ts +21 -0
  1316. package/src/modules/messages/api/route.ts +109 -9
  1317. package/src/modules/messages/components/ComposeMessagePageClient.tsx +2 -1
  1318. package/src/modules/messages/components/MessageDetailPageClient.tsx +3 -2
  1319. package/src/modules/messages/components/MessagesInboxPageClient.tsx +2 -1
  1320. package/src/modules/messages/components/message-detail/panels/dialogs.tsx +1 -1
  1321. package/src/modules/messages/extension-points.ts +13 -0
  1322. package/src/modules/messages/i18n/de.json +2 -0
  1323. package/src/modules/messages/i18n/en.json +2 -0
  1324. package/src/modules/messages/i18n/es.json +2 -0
  1325. package/src/modules/messages/i18n/ko.json +263 -0
  1326. package/src/modules/messages/i18n/pl.json +2 -0
  1327. package/src/modules/messages/lib/participantScope.ts +64 -0
  1328. package/src/modules/messages/lib/routeHelpers.ts +4 -6
  1329. package/src/modules/messages/lib/searchLookup.ts +11 -34
  1330. package/src/modules/messages/search.ts +11 -5
  1331. package/src/modules/notifications/api/route.ts +123 -3
  1332. package/src/modules/notifications/api/unread-count/route.ts +42 -5
  1333. package/src/modules/notifications/di.ts +1 -1
  1334. package/src/modules/notifications/events.ts +2 -0
  1335. package/src/modules/notifications/i18n/ko.json +55 -0
  1336. package/src/modules/notifications/lib/notificationRecipients.ts +6 -8
  1337. package/src/modules/notifications/lib/notificationScope.ts +40 -0
  1338. package/src/modules/notifications/lib/notificationService.ts +63 -1
  1339. package/src/modules/notifications/lib/routeHelpers.ts +19 -2
  1340. package/src/modules/payment_gateways/api/capture/route.ts +1 -1
  1341. package/src/modules/payment_gateways/api/sessions/route.ts +6 -3
  1342. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +13 -1
  1343. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +3 -2
  1344. package/src/modules/payment_gateways/data/entities.ts +13 -2
  1345. package/src/modules/payment_gateways/di.ts +28 -2
  1346. package/src/modules/payment_gateways/extension-points.ts +16 -0
  1347. package/src/modules/payment_gateways/i18n/de.json +8 -1
  1348. package/src/modules/payment_gateways/i18n/en.json +8 -1
  1349. package/src/modules/payment_gateways/i18n/es.json +8 -1
  1350. package/src/modules/payment_gateways/i18n/ko.json +87 -0
  1351. package/src/modules/payment_gateways/i18n/pl.json +8 -1
  1352. package/src/modules/payment_gateways/lib/capture-ledger.ts +260 -0
  1353. package/src/modules/payment_gateways/lib/gateway-service.ts +114 -18
  1354. package/src/modules/payment_gateways/lib/order-amount-reconciliation.ts +93 -0
  1355. package/src/modules/payment_gateways/lib/payment-operation-idempotency.ts +1 -0
  1356. package/src/modules/payment_gateways/lib/session-idempotency.ts +36 -0
  1357. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +44 -1
  1358. package/src/modules/payment_gateways/migrations/Migration20260725101500_payment_gateways.ts +21 -0
  1359. package/src/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.ts +17 -0
  1360. package/src/modules/payment_gateways/setup.ts +62 -0
  1361. package/src/modules/payment_gateways/workers/session-initialization-prune.ts +63 -0
  1362. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +4 -4
  1363. package/src/modules/planner/components/unavailabilityReasons.ts +3 -3
  1364. package/src/modules/planner/i18n/ko.json +565 -0
  1365. package/src/modules/portal/extension-points.ts +30 -0
  1366. package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +3 -3
  1367. package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.ts +9 -0
  1368. package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.tsx +164 -0
  1369. package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +4 -4
  1370. package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +3 -3
  1371. package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +3 -3
  1372. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +5 -5
  1373. package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +4 -4
  1374. package/src/modules/portal/frontend/[orgSlug]/portal/verify/page.tsx +1 -1
  1375. package/src/modules/portal/i18n/de.json +18 -0
  1376. package/src/modules/portal/i18n/en.json +18 -0
  1377. package/src/modules/portal/i18n/es.json +18 -0
  1378. package/src/modules/portal/i18n/ko.json +143 -0
  1379. package/src/modules/portal/i18n/pl.json +18 -0
  1380. package/src/modules/portal/lib/navigation.ts +3 -0
  1381. package/src/modules/progress/AGENTS.md +11 -1
  1382. package/src/modules/progress/i18n/ko.json +20 -0
  1383. package/src/modules/progress/lib/progressService.ts +1 -0
  1384. package/src/modules/progress/lib/progressServiceImpl.ts +385 -117
  1385. package/src/modules/query_index/api/openapi.ts +12 -0
  1386. package/src/modules/query_index/api/reindex.ts +15 -0
  1387. package/src/modules/query_index/api/status.ts +238 -136
  1388. package/src/modules/query_index/cli.ts +180 -1
  1389. package/src/modules/query_index/components/QueryIndexesTable.tsx +194 -47
  1390. package/src/modules/query_index/data/entities.ts +7 -0
  1391. package/src/modules/query_index/di.ts +6 -0
  1392. package/src/modules/query_index/events.ts +17 -0
  1393. package/src/modules/query_index/extension-points.ts +10 -0
  1394. package/src/modules/query_index/i18n/de.json +5 -3
  1395. package/src/modules/query_index/i18n/en.json +5 -3
  1396. package/src/modules/query_index/i18n/es.json +5 -3
  1397. package/src/modules/query_index/i18n/ko.json +69 -0
  1398. package/src/modules/query_index/i18n/pl.json +5 -3
  1399. package/src/modules/query_index/lib/batch.ts +11 -4
  1400. package/src/modules/query_index/lib/coverage.ts +47 -14
  1401. package/src/modules/query_index/lib/document.ts +35 -4
  1402. package/src/modules/query_index/lib/engine.ts +136 -59
  1403. package/src/modules/query_index/lib/indexer.ts +130 -21
  1404. package/src/modules/query_index/lib/reindexer.ts +62 -40
  1405. package/src/modules/query_index/lib/search-tokens.ts +48 -16
  1406. package/src/modules/query_index/lib/subscriber-scope.ts +2 -7
  1407. package/src/modules/query_index/migrations/.snapshot-open-mercato.json +12 -0
  1408. package/src/modules/query_index/migrations/Migration20260731105052_query_index.ts +35 -0
  1409. package/src/modules/query_index/subscribers/coverage_refresh.ts +4 -0
  1410. package/src/modules/query_index/subscribers/delete_one.ts +65 -1
  1411. package/src/modules/query_index/subscribers/upsert_one.ts +68 -1
  1412. package/src/modules/resources/api/resources.ts +2 -0
  1413. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -1
  1414. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +9 -3
  1415. package/src/modules/resources/backend/resources/resources/page.tsx +2 -1
  1416. package/src/modules/resources/commands/resources.ts +10 -0
  1417. package/src/modules/resources/components/detail/dictionaries.ts +3 -3
  1418. package/src/modules/resources/data/entities.ts +3 -0
  1419. package/src/modules/resources/data/validators.ts +5 -0
  1420. package/src/modules/resources/extension-points.ts +11 -0
  1421. package/src/modules/resources/i18n/ko.json +770 -0
  1422. package/src/modules/resources/lib/seeds.ts +16 -9
  1423. package/src/modules/resources/migrations/.snapshot-open-mercato.json +17 -1
  1424. package/src/modules/resources/migrations/Migration20260608231000.ts +13 -0
  1425. package/src/modules/sales/analytics.ts +4 -0
  1426. package/src/modules/sales/api/document-history/route.ts +1 -0
  1427. package/src/modules/sales/api/documents/factory.ts +28 -3
  1428. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +11 -3
  1429. package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -4
  1430. package/src/modules/sales/commands/documents.ts +298 -31
  1431. package/src/modules/sales/components/documents/ItemsSection.tsx +34 -11
  1432. package/src/modules/sales/components/documents/LineItemDialog.tsx +13 -5
  1433. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +48 -6
  1434. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +6 -1
  1435. package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +198 -0
  1436. package/src/modules/sales/components/documents/lineItemTypes.ts +1 -0
  1437. package/src/modules/sales/components/useSalesChannelsEnabled.ts +2 -48
  1438. package/src/modules/sales/data/validators.ts +59 -6
  1439. package/src/modules/sales/di.ts +9 -0
  1440. package/src/modules/sales/events.ts +1 -0
  1441. package/src/modules/sales/extension-points.ts +33 -0
  1442. package/src/modules/sales/i18n/de.json +22 -0
  1443. package/src/modules/sales/i18n/en.json +22 -0
  1444. package/src/modules/sales/i18n/es.json +22 -0
  1445. package/src/modules/sales/i18n/ko.json +1442 -0
  1446. package/src/modules/sales/i18n/pl.json +22 -0
  1447. package/src/modules/sales/lib/historyHelpers.ts +88 -1
  1448. package/src/modules/sales/services/paymentOrderTotalResolver.ts +67 -0
  1449. package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +64 -3
  1450. package/src/modules/sales/workflows.ts +10 -7
  1451. package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +11 -1
  1452. package/src/modules/shipping_carriers/i18n/ko.json +85 -0
  1453. package/src/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.tsx +1 -1
  1454. package/src/modules/staff/api/interceptors.ts +6 -4
  1455. package/src/modules/staff/api/leave-requests.ts +54 -47
  1456. package/src/modules/staff/components/detail/dictionaries.ts +3 -3
  1457. package/src/modules/staff/i18n/ko.json +1162 -0
  1458. package/src/modules/sync_excel/api/upload/route.ts +15 -2
  1459. package/src/modules/sync_excel/i18n/ko.json +107 -0
  1460. package/src/modules/sync_excel/widgets/injection/upload-config/widget.client.tsx +1 -1
  1461. package/src/modules/translations/i18n/ko.json +45 -0
  1462. package/src/modules/wms/components/backend/ReleaseReservationDialog.tsx +1 -1
  1463. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +5 -4
  1464. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +4 -3
  1465. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +3 -2
  1466. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +3 -2
  1467. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -1
  1468. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +3 -2
  1469. package/src/modules/wms/extension-points.ts +23 -0
  1470. package/src/modules/wms/i18n/de.json +2 -0
  1471. package/src/modules/wms/i18n/en.json +2 -0
  1472. package/src/modules/wms/i18n/es.json +2 -0
  1473. package/src/modules/wms/i18n/ko.json +1053 -0
  1474. package/src/modules/wms/i18n/pl.json +2 -0
  1475. package/src/modules/workflows/backend/definitions/[id]/page.tsx +2 -2
  1476. package/src/modules/workflows/backend/definitions/create/page.tsx +1 -1
  1477. package/src/modules/workflows/backend/definitions/page.tsx +3 -2
  1478. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +16 -7
  1479. package/src/modules/workflows/backend/instances/page.tsx +10 -9
  1480. package/src/modules/workflows/backend/tasks/page.tsx +8 -7
  1481. package/src/modules/workflows/components/ActivitiesEditor.tsx +98 -14
  1482. package/src/modules/workflows/components/BusinessRulesSelector.tsx +1 -1
  1483. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +3 -3
  1484. package/src/modules/workflows/components/EdgeEditDialogCrudForm.tsx +1 -2
  1485. package/src/modules/workflows/components/NodeEditDialog.tsx +3 -3
  1486. package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +4 -5
  1487. package/src/modules/workflows/components/StepsEditor.tsx +2 -2
  1488. package/src/modules/workflows/components/TransitionsEditor.tsx +78 -20
  1489. package/src/modules/workflows/components/WorkflowGraphImpl.tsx +1 -1
  1490. package/src/modules/workflows/components/WorkflowLegend.tsx +1 -1
  1491. package/src/modules/workflows/components/WorkflowSelector.tsx +1 -1
  1492. package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +1 -1
  1493. package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +2 -2
  1494. package/src/modules/workflows/components/fields/MappingArrayEditor.tsx +1 -1
  1495. package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +1 -1
  1496. package/src/modules/workflows/components/fields/WorkflowSelectorField.tsx +4 -4
  1497. package/src/modules/workflows/data/validators.ts +52 -1
  1498. package/src/modules/workflows/events.ts +1 -0
  1499. package/src/modules/workflows/extension-points.ts +12 -0
  1500. package/src/modules/workflows/i18n/de.json +3 -0
  1501. package/src/modules/workflows/i18n/en.json +3 -0
  1502. package/src/modules/workflows/i18n/es.json +3 -0
  1503. package/src/modules/workflows/i18n/ko.json +1204 -0
  1504. package/src/modules/workflows/i18n/pl.json +3 -0
  1505. package/src/modules/workflows/lib/activity-executor.ts +99 -20
  1506. package/src/modules/workflows/lib/format-validation-error.ts +60 -0
  1507. package/src/modules/workflows/widgets/injection/order-approval/context-keys.ts +18 -0
  1508. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +27 -11
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/lib/setup-app.ts"],
4
- "sourcesContent": ["import { hash } from 'bcryptjs'\nimport { randomBytes } from 'node:crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { Role, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { Tenant, Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'\nimport { normalizeTenantId } from './tenantAccess'\nimport { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { getDefaultEncryptionMaps, type Module } from '@open-mercato/shared/modules/registry'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'setup' })\n\nconst DEFAULT_ROLE_NAMES = ['employee', 'admin', 'superadmin'] as const\nconst DEMO_SUPERADMIN_EMAIL = 'superadmin@acme.com'\nconst DEFAULT_DERIVED_EMAIL_DOMAIN = DEMO_SUPERADMIN_EMAIL.split('@')[1] ?? 'acme.com'\n\nexport type EnsureRolesOptions = {\n roleNames?: string[]\n tenantId?: string\n}\n\nasync function ensureRolesInContext(\n em: EntityManager,\n roleNames: string[],\n tenantId: string,\n) {\n for (const name of roleNames) {\n const existing = await findOneWithDecryption(em, Role, { name, tenantId }, {}, { tenantId, organizationId: null })\n if (existing) continue\n em.persist(em.create(Role, { name, tenantId, createdAt: new Date() }))\n }\n}\n\nexport async function ensureRoles(em: EntityManager, options: EnsureRolesOptions = {}) {\n const roleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const tenantId = normalizeTenantId(options.tenantId ?? null)\n if (!tenantId) {\n throw new Error('ensureRoles requires a tenantId \u2014 global roles are not supported')\n }\n await em.transactional(async (tem) => {\n await ensureRolesInContext(tem, roleNames, tenantId)\n await tem.flush()\n })\n}\n\nasync function findRoleByName(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role | null> {\n const normalizedTenant = normalizeTenantId(tenantId ?? null) ?? null\n return findOneWithDecryption(em, Role, { name, tenantId: normalizedTenant }, {}, { tenantId: normalizedTenant, organizationId: null })\n}\n\nasync function findRoleByNameOrFail(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role> {\n const role = await findRoleByName(em, name, tenantId)\n if (!role) throw new Error(`ROLE_NOT_FOUND:${name}`)\n return role\n}\n\ntype PrimaryUserInput = {\n email: string\n password?: string\n hashedPassword?: string | null\n firstName?: string | null\n lastName?: string | null\n displayName?: string | null\n confirm?: boolean\n}\n\nconst DERIVED_EMAIL_ENV = {\n admin: 'OM_INIT_ADMIN_EMAIL',\n employee: 'OM_INIT_EMPLOYEE_EMAIL',\n} as const\n\nexport type DemoUserRole = 'superadmin' | 'admin' | 'employee'\nexport type DemoUserEmail = { role: DemoUserRole; email: string }\n\n/**\n * Returns the canonical list of demo user emails the setup path may have\n * seeded. Honors OM_INIT_ADMIN_EMAIL / OM_INIT_EMPLOYEE_EMAIL exactly the\n * same way the derived-user seeding branch does, so the deactivation loop\n * never drifts from the seeding loop.\n *\n * Pure function \u2014 no side effects, safe to unit-test in isolation.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport function resolveDemoUserEmails(): DemoUserEmail[] {\n const adminEmail = readEnvValue(DERIVED_EMAIL_ENV.admin) ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = readEnvValue(DERIVED_EMAIL_ENV.employee) ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n return [\n { role: 'superadmin', email: DEMO_SUPERADMIN_EMAIL },\n { role: 'admin', email: adminEmail },\n { role: 'employee', email: employeeEmail },\n ]\n}\n\nexport type SetupInitialTenantOptions = {\n orgName: string\n primaryUser: PrimaryUserInput\n roleNames?: string[]\n includeDerivedUsers?: boolean\n failIfUserExists?: boolean\n primaryUserRoles?: string[]\n includeSuperadminRole?: boolean\n /** Optional list of enabled modules. When provided, module setup hooks are called. */\n modules?: Module[]\n /**\n * Optional global slug to persist on the new Organization. When set, a\n * pre-flight uniqueness check across all tenants throws OrgSlugExistsError\n * on collision so scriptable callers can fail loudly instead of silently\n * reusing or clobbering an existing organization.\n */\n orgSlug?: string\n /**\n * Opt-in flag that allows seeding the derived admin/employee accounts when\n * the OM_INIT_ADMIN_PASSWORD / OM_INIT_EMPLOYEE_PASSWORD env vars are unset.\n *\n * - In non-production (`NODE_ENV !== 'production'`): the demo accounts are\n * seeded with the well-known `'secret'` password so local dev workflows\n * (e.g. `mercato init`) stay predictable for developers.\n * - In production: the fallback uses a randomly generated 96-bit password\n * (printed once by the CLI) so an operator who deliberately opts in still\n * avoids the historical hardcoded credential. When this flag is false/unset\n * in production and the env vars are missing, `DerivedUserPasswordRequiredError`\n * is thrown instead of silently seeding any account.\n */\n allowDemoDerivedPasswords?: boolean\n}\n\nexport class OrgSlugExistsError extends Error {\n constructor(public readonly slug: string) {\n super(`ORG_SLUG_EXISTS: an organization with slug \"${slug}\" already exists`)\n this.name = 'OrgSlugExistsError'\n }\n}\n\nexport class DerivedUserPasswordRequiredError extends Error {\n constructor(public readonly missing: string[]) {\n super(\n `DERIVED_USER_PASSWORD_REQUIRED: missing ${missing.join(', ')} (set the env vars, pass allowDemoDerivedPasswords: true / --include-demo-users in non-production, or disable derived user seeding)`,\n )\n this.name = 'DerivedUserPasswordRequiredError'\n }\n}\n\nexport type SetupInitialTenantResult = {\n tenantId: string\n organizationId: string\n users: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }>\n reusedExistingUser: boolean\n}\n\nexport async function setupInitialTenant(\n em: EntityManager,\n options: SetupInitialTenantOptions,\n): Promise<SetupInitialTenantResult> {\n const {\n primaryUser,\n includeDerivedUsers = true,\n failIfUserExists = false,\n primaryUserRoles,\n includeSuperadminRole = true,\n } = options\n const primaryRolesInput = primaryUserRoles && primaryUserRoles.length ? primaryUserRoles : ['superadmin']\n const primaryRoles = includeSuperadminRole\n ? primaryRolesInput\n : primaryRolesInput.filter((role) => role !== 'superadmin')\n if (primaryRoles.length === 0) {\n throw new Error('PRIMARY_ROLES_REQUIRED')\n }\n const defaultRoleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const resolvedRoleNames = includeSuperadminRole\n ? defaultRoleNames\n : defaultRoleNames.filter((role) => role !== 'superadmin')\n const roleNames = Array.from(new Set([...resolvedRoleNames, ...primaryRoles]))\n const resolvedModules = options.modules ?? tryGetModules()\n const defaultEncryptionMaps = getDefaultEncryptionMaps(resolvedModules)\n\n const mainEmail = primaryUser.email\n const existingUser = await findOneWithDecryption(em, User, { email: mainEmail }, {}, { tenantId: null, organizationId: null })\n if (existingUser && failIfUserExists) {\n throw new Error('USER_EXISTS')\n }\n\n if (options.orgSlug) {\n const slugConflict = await findOneWithDecryption(\n em,\n Organization,\n { slug: options.orgSlug },\n {},\n { tenantId: null, organizationId: null },\n )\n if (slugConflict) {\n throw new OrgSlugExistsError(options.orgSlug)\n }\n }\n\n let tenantId: string | undefined\n let organizationId: string | undefined\n let reusedExistingUser = false\n const userSnapshots: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }> = []\n\n await em.transactional(async (tem) => {\n if (!existingUser) return\n reusedExistingUser = true\n tenantId = existingUser.tenantId ? String(existingUser.tenantId) : undefined\n organizationId = existingUser.organizationId ? String(existingUser.organizationId) : undefined\n const roleTenantId = normalizeTenantId(existingUser.tenantId ?? null) ?? null\n if (!roleTenantId) {\n throw new Error('Cannot reuse a user without a tenantId \u2014 global roles are not supported')\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n const requiredRoleSet = new Set([...roleNames, ...primaryRoles])\n const links = await findWithDecryption(\n tem,\n UserRole,\n { user: existingUser },\n { populate: ['role'] },\n { tenantId: roleTenantId, organizationId: null },\n )\n const currentRoles = new Set(links.map((link) => link.role.name))\n for (const roleName of requiredRoleSet) {\n if (!currentRoles.has(roleName)) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n tem.persist(tem.create(UserRole, { user: existingUser, role, createdAt: new Date() }))\n }\n }\n await tem.flush()\n const roles = Array.from(new Set([...currentRoles, ...roleNames]))\n userSnapshots.push({ user: existingUser, roles, created: false })\n })\n\n if (!existingUser) {\n const baseUsers: Array<{\n email: string\n roles: string[]\n name?: string | null\n passwordHash?: string | null\n generatedPassword?: string | null\n }> = [\n { email: primaryUser.email, roles: primaryRoles, name: resolvePrimaryName(primaryUser) },\n ]\n if (includeDerivedUsers) {\n const adminOverride = readEnvValue(DERIVED_EMAIL_ENV.admin)\n const employeeOverride = readEnvValue(DERIVED_EMAIL_ENV.employee)\n const adminEmail = adminOverride ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = employeeOverride ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const envAdminPwd = readEnvValue('OM_INIT_ADMIN_PASSWORD')\n const envEmployeePwd = readEnvValue('OM_INIT_EMPLOYEE_PASSWORD')\n const isProduction = process.env.NODE_ENV === 'production'\n const allowDemo = options.allowDemoDerivedPasswords === true\n if (isProduction && !allowDemo) {\n const missing: string[] = []\n if (!envAdminPwd) missing.push('OM_INIT_ADMIN_PASSWORD')\n if (!envEmployeePwd) missing.push('OM_INIT_EMPLOYEE_PASSWORD')\n if (missing.length) {\n throw new DerivedUserPasswordRequiredError(missing)\n }\n }\n // In non-production, fall back to the well-known DEMO_DERIVED_PASSWORD so\n // local dev workflows stay predictable (admin@/employee@ login with the\n // documented demo password). In production we either have env-supplied\n // values, or \u2014 for opt-in --include-demo-users flows \u2014 we generate a\n // random one-time password and surface it via `generatedPassword` so the\n // operator can capture it. Production callers without env vars and\n // without the opt-in already threw above.\n const fallbackAdminPwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const fallbackEmployeePwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const adminPasswordPlain = envAdminPwd ?? fallbackAdminPwd\n const employeePasswordPlain = envEmployeePwd ?? fallbackEmployeePwd\n const adminPasswordHash = await hash(adminPasswordPlain, 10)\n const employeePasswordHash = await hash(employeePasswordPlain, 10)\n addUniqueBaseUser(baseUsers, {\n email: adminEmail,\n roles: ['admin'],\n passwordHash: adminPasswordHash,\n generatedPassword: envAdminPwd ? null : adminPasswordPlain,\n })\n addUniqueBaseUser(baseUsers, {\n email: employeeEmail,\n roles: ['employee'],\n passwordHash: employeePasswordHash,\n generatedPassword: envEmployeePwd ? null : employeePasswordPlain,\n })\n }\n const passwordHash = await resolvePasswordHash(primaryUser)\n\n await em.transactional(async (tem) => {\n const tenant = tem.create(Tenant, {\n name: options.orgName,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(tenant)\n await tem.flush()\n\n const organization = tem.create(Organization, {\n name: options.orgName,\n slug: options.orgSlug ?? null,\n tenant,\n isActive: true,\n depth: 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(organization)\n await tem.flush()\n\n tenantId = String(tenant.id)\n organizationId = String(organization.id)\n const roleTenantId = tenantId\n\n if (isTenantDataEncryptionEnabled()) {\n try {\n const kms = createKmsService()\n if (kms.isHealthy()) {\n if (isEncryptionDebugEnabled()) {\n logger.info('Provisioning tenant DEK', { tenantId: String(tenant.id) })\n }\n await kms.createTenantDek(String(tenant.id))\n if (isEncryptionDebugEnabled()) {\n logger.info('Created tenant DEK during setup', { tenantId: String(tenant.id) })\n }\n } else {\n if (isEncryptionDebugEnabled()) {\n logger.warn('KMS not healthy, skipping tenant DEK creation', { tenantId: String(tenant.id) })\n }\n }\n } catch (err) {\n if (isEncryptionDebugEnabled()) {\n logger.warn('Failed to create tenant DEK', { err })\n }\n }\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n if (isTenantDataEncryptionEnabled()) {\n for (const spec of defaultEncryptionMaps) {\n const existing = await findOneWithDecryption(tem, EncryptionMap, { entityId: spec.entityId, tenantId: tenant.id, organizationId: organization.id, deletedAt: null }, {}, { tenantId: String(tenant.id), organizationId: String(organization.id) })\n if (!existing) {\n tem.persist(tem.create(EncryptionMap, {\n entityId: spec.entityId,\n tenantId: tenant.id,\n organizationId: organization.id,\n fieldsJson: spec.fields,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n }))\n } else {\n existing.fieldsJson = spec.fields\n existing.isActive = true\n }\n }\n await tem.flush()\n }\n })\n\n await em.transactional(async (tem) => {\n if (!tenantId || !organizationId) return\n const roleTenantId = tenantId\n const encryptionService = isTenantDataEncryptionEnabled()\n ? new TenantDataEncryptionService(tem as any, { kms: createKmsService() })\n : null\n if (encryptionService) {\n await encryptionService.invalidateMap('auth:user', String(tenantId), String(organizationId))\n await encryptionService.invalidateMap('auth:user', String(tenantId), null)\n }\n\n for (const base of baseUsers) {\n const resolvedPasswordHash = base.passwordHash ?? passwordHash\n let user = await findOneWithDecryption(tem, User, { email: base.email }, {}, { tenantId: tenantId ?? null, organizationId: organizationId ?? null })\n const confirm = primaryUser.confirm ?? true\n const encryptedPayload = encryptionService\n ? await encryptionService.encryptEntityPayload('auth:user', { email: base.email }, tenantId, organizationId)\n : { email: base.email, emailHash: computeEmailHash(base.email) }\n if (user) {\n user.passwordHash = resolvedPasswordHash\n user.organizationId = organizationId\n user.tenantId = tenantId\n if (isTenantDataEncryptionEnabled()) {\n user.email = encryptedPayload.email as any\n user.emailHash = (encryptedPayload as any).emailHash ?? computeEmailHash(base.email)\n }\n if (base.name) user.name = base.name\n if (confirm) user.isConfirmed = true\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: false, generatedPassword: base.generatedPassword ?? null })\n } else {\n user = tem.create(User, {\n email: (encryptedPayload as any).email ?? base.email,\n emailHash: isTenantDataEncryptionEnabled() ? (encryptedPayload as any).emailHash ?? computeEmailHash(base.email) : undefined,\n passwordHash: resolvedPasswordHash,\n organizationId,\n tenantId,\n name: base.name ?? undefined,\n isConfirmed: confirm,\n createdAt: new Date(),\n })\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: true, generatedPassword: base.generatedPassword ?? null })\n }\n await tem.flush()\n for (const roleName of base.roles) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n const existingLink = await findOneWithDecryption(tem, UserRole, { user, role }, {}, { tenantId: tenantId ?? null, organizationId: null })\n if (!existingLink) tem.persist(tem.create(UserRole, { user, role, createdAt: new Date() }))\n }\n await tem.flush()\n }\n })\n }\n\n if (!tenantId || !organizationId) {\n throw new Error('SETUP_FAILED')\n }\n\n if (!reusedExistingUser) {\n await rebuildHierarchyForTenant(em, tenantId)\n }\n\n await ensureDefaultRoleAcls(em, tenantId, resolvedModules, { includeSuperadminRole })\n await deactivateDemoUsersIfSelfOnboardingEnabled(em)\n\n // Call module onTenantCreated hooks\n for (const mod of resolvedModules) {\n if (mod.setup?.onTenantCreated) {\n await mod.setup.onTenantCreated({ em, tenantId, organizationId })\n }\n }\n\n return {\n tenantId,\n organizationId,\n users: userSnapshots,\n reusedExistingUser,\n }\n}\n\nfunction resolvePrimaryName(input: PrimaryUserInput): string | null {\n if (input.displayName && input.displayName.trim()) return input.displayName.trim()\n const parts = [input.firstName, input.lastName].map((value) => value?.trim()).filter(Boolean)\n if (parts.length) return parts.join(' ')\n return null\n}\n\nfunction readEnvValue(key: string): string | undefined {\n const value = process.env[key]\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction addUniqueBaseUser(\n baseUsers: Array<{ email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null }>,\n entry: { email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null },\n) {\n if (!entry.email) return\n const normalized = entry.email.toLowerCase()\n if (baseUsers.some((user) => user.email.toLowerCase() === normalized)) return\n baseUsers.push(entry)\n}\n\n/**\n * Well-known demo password seeded for derived admin@/employee@ accounts in\n * non-production (`NODE_ENV !== 'production'`) when no env override is set.\n * Keeps the documented `yarn dev` / `mercato init` DX predictable. Never used\n * in production: the production branch either consumes env-supplied values or\n * falls back to `generateDerivedPassword()` so credentials remain non-guessable.\n */\nconst DEMO_DERIVED_PASSWORD = 'secret'\n\n/**\n * Generate a 16-character base64url password (96 bits of entropy) for a derived\n * demo user in production when no env override is provided AND the caller\n * explicitly opted in via `allowDemoDerivedPasswords`. Surfaced via the\n * `users[].generatedPassword` snapshot so CLI callers can print it to the\n * operator \u2014 there is no other recovery path for these credentials.\n */\nfunction generateDerivedPassword(): string {\n return randomBytes(12).toString('base64url')\n}\n\nfunction isDemoModeEnabled(): boolean {\n const parsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n return parsed === false ? false : true\n}\n\nfunction shouldKeepDemoSuperadminDuringInit(): boolean {\n if (process.env.OM_INIT_FLOW !== 'true') return false\n if (!readEnvValue('OM_INIT_SUPERADMIN_EMAIL')) return false\n return isDemoModeEnabled()\n}\n\nasync function resolvePasswordHash(input: PrimaryUserInput): Promise<string | null> {\n if (typeof input.hashedPassword === 'string') return input.hashedPassword\n if (input.password) return hash(input.password, 10)\n return null\n}\n\nexport async function ensureDefaultRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules: Module[],\n options: { includeSuperadminRole?: boolean } = {},\n) {\n const includeSuperadminRole = options.includeSuperadminRole ?? true\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const superadminRole = includeSuperadminRole ? await findRoleByName(em, 'superadmin', roleTenantId) : null\n const adminRole = await findRoleByName(em, 'admin', roleTenantId)\n const employeeRole = await findRoleByName(em, 'employee', roleTenantId)\n\n // Merge features from all enabled modules' setup configs\n const builtInRoles = ['superadmin', 'admin', 'employee'] as const\n const superadminFeatures: string[] = []\n const adminFeatures: string[] = []\n const employeeFeatures: string[] = []\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of modules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n if (roleFeatures.superadmin) superadminFeatures.push(...roleFeatures.superadmin)\n if (roleFeatures.admin) adminFeatures.push(...roleFeatures.admin)\n if (roleFeatures.employee) employeeFeatures.push(...roleFeatures.employee)\n\n // Collect features for custom roles (any key not in builtInRoles)\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if ((builtInRoles as readonly string[]).includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n logger.info('Seeded default role features', {\n superadmin: superadminFeatures,\n admin: adminFeatures,\n employee: employeeFeatures,\n ...(customRoleFeatures.size > 0\n ? Object.fromEntries(customRoleFeatures)\n : {}),\n })\n\n if (includeSuperadminRole && superadminRole) {\n await ensureRoleAclFor(em, superadminRole, tenantId, superadminFeatures, { isSuperAdmin: true })\n }\n if (adminRole) {\n await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures)\n }\n if (employeeRole) {\n await ensureRoleAclFor(em, employeeRole, tenantId, employeeFeatures)\n }\n\n // Seed ACLs for custom roles defined by app modules.\n // NOTE: Custom roles may not exist yet if they are created in seedDefaults\n // (which runs after this function). In that case, use ensureCustomRoleAcls()\n // after seedDefaults to pick them up.\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n }\n }\n}\n\n/**\n * Seed ACLs for custom roles defined in module defaultRoleFeatures.\n * Call this AFTER seedDefaults to pick up roles created by app modules.\n * Safe to call multiple times \u2014 ensureRoleAclFor merges features idempotently.\n */\nexport async function ensureCustomRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules?: Module[],\n): Promise<void> {\n const resolvedModules = modules ?? tryGetModules()\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const builtInRoles = ['superadmin', 'admin', 'employee']\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of resolvedModules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if (builtInRoles.includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n if (customRoleFeatures.size === 0) return\n\n let seeded = 0\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n seeded++\n }\n }\n if (seeded > 0) {\n logger.info('Seeded custom role ACLs', { seeded })\n }\n}\n\nasync function ensureRoleAclFor(\n em: EntityManager,\n role: Role,\n tenantId: string,\n features: string[],\n options: { isSuperAdmin?: boolean } = {},\n) {\n const existing = await findOneWithDecryption(em, RoleAcl, { role, tenantId }, {}, { tenantId, organizationId: null })\n if (!existing) {\n const acl = em.create(RoleAcl, {\n role,\n tenantId,\n featuresJson: features,\n isSuperAdmin: !!options.isSuperAdmin,\n createdAt: new Date(),\n })\n await em.persist(acl).flush()\n return\n }\n const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []\n const merged = Array.from(new Set([...currentFeatures, ...features]))\n const changed =\n merged.length !== currentFeatures.length ||\n merged.some((value, index) => value !== currentFeatures[index])\n if (changed) existing.featuresJson = merged\n if (options.isSuperAdmin && !existing.isSuperAdmin) {\n existing.isSuperAdmin = true\n }\n if (changed || options.isSuperAdmin) {\n await em.persist(existing).flush()\n }\n}\n\n/**\n * Neutralizes every demo account the setup path may have seeded\n * (superadmin, admin, employee \u2014 honoring OM_INIT_*_EMAIL overrides)\n * when SELF_SERVICE_ONBOARDING_ENABLED is on and the operator did not\n * opt in to keeping demo credentials via shouldKeepDemoSuperadminDuringInit.\n *\n * Each user is processed in its own try/catch so a single failure (e.g.\n * decryption error on a legacy row) does not skip the remaining accounts.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport async function deactivateDemoUsersIfSelfOnboardingEnabled(em: EntityManager) {\n if (process.env.SELF_SERVICE_ONBOARDING_ENABLED !== 'true') return\n if (shouldKeepDemoSuperadminDuringInit()) return\n for (const { role, email } of resolveDemoUserEmails()) {\n try {\n const user = await findOneWithDecryption(\n em,\n User,\n { email },\n {},\n { tenantId: null, organizationId: null },\n )\n if (!user) continue\n let dirty = false\n if (user.passwordHash) {\n user.passwordHash = null\n dirty = true\n }\n if (user.isConfirmed !== false) {\n user.isConfirmed = false\n dirty = true\n }\n if (dirty) {\n await em.persist(user).flush()\n }\n } catch (error) {\n logger.error('Failed to deactivate demo user', { role, email, err: error })\n }\n }\n}\n\n/**\n * @deprecated Renamed to {@link deactivateDemoUsersIfSelfOnboardingEnabled}\n * because the helper now neutralizes admin/employee demo accounts in addition\n * to superadmin (security tracker finding #5). Kept as an internal alias to\n * avoid breaking any out-of-tree caller that imported the old name; will be\n * removed in a future major.\n */\nconst deactivateDemoSuperAdminIfSelfOnboardingEnabled = deactivateDemoUsersIfSelfOnboardingEnabled\n\n/** Try to get modules from runtime registry; returns empty array if not yet registered. */\nfunction tryGetModules(): Module[] {\n try {\n const { getModules } = require('@open-mercato/shared/lib/modules/registry')\n return getModules()\n } catch {\n return []\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { hash } from 'bcryptjs'\nimport { randomBytes } from 'node:crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { Role, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { Tenant, Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'\nimport { normalizeTenantId } from './tenantAccess'\nimport { computeEmailHash, emailHashLookupValues } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { getDefaultEncryptionMaps, type Module } from '@open-mercato/shared/modules/registry'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'setup' })\n\nconst DEFAULT_ROLE_NAMES = ['employee', 'admin', 'superadmin'] as const\nconst DEMO_SUPERADMIN_EMAIL = 'superadmin@acme.com'\nconst DEFAULT_DERIVED_EMAIL_DOMAIN = DEMO_SUPERADMIN_EMAIL.split('@')[1] ?? 'acme.com'\n\nexport type EnsureRolesOptions = {\n roleNames?: string[]\n tenantId?: string\n}\n\nasync function ensureRolesInContext(\n em: EntityManager,\n roleNames: string[],\n tenantId: string,\n) {\n for (const name of roleNames) {\n const existing = await findOneWithDecryption(em, Role, { name, tenantId }, {}, { tenantId, organizationId: null })\n if (existing) continue\n em.persist(em.create(Role, { name, tenantId, createdAt: new Date() }))\n }\n}\n\nexport async function ensureRoles(em: EntityManager, options: EnsureRolesOptions = {}) {\n const roleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const tenantId = normalizeTenantId(options.tenantId ?? null)\n if (!tenantId) {\n throw new Error('ensureRoles requires a tenantId \u2014 global roles are not supported')\n }\n await em.transactional(async (tem) => {\n await ensureRolesInContext(tem, roleNames, tenantId)\n await tem.flush()\n })\n}\n\nasync function findRoleByName(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role | null> {\n const normalizedTenant = normalizeTenantId(tenantId ?? null) ?? null\n return findOneWithDecryption(em, Role, { name, tenantId: normalizedTenant }, {}, { tenantId: normalizedTenant, organizationId: null })\n}\n\nasync function findRoleByNameOrFail(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role> {\n const role = await findRoleByName(em, name, tenantId)\n if (!role) throw new Error(`ROLE_NOT_FOUND:${name}`)\n return role\n}\n\ntype PrimaryUserInput = {\n email: string\n password?: string\n hashedPassword?: string | null\n firstName?: string | null\n lastName?: string | null\n displayName?: string | null\n confirm?: boolean\n}\n\nconst DERIVED_EMAIL_ENV = {\n admin: 'OM_INIT_ADMIN_EMAIL',\n employee: 'OM_INIT_EMPLOYEE_EMAIL',\n} as const\n\nexport type DemoUserRole = 'superadmin' | 'admin' | 'employee'\nexport type DemoUserEmail = { role: DemoUserRole; email: string }\n\n/**\n * Returns the canonical list of demo user emails the setup path may have\n * seeded. Honors OM_INIT_ADMIN_EMAIL / OM_INIT_EMPLOYEE_EMAIL exactly the\n * same way the derived-user seeding branch does, so the deactivation loop\n * never drifts from the seeding loop.\n *\n * Pure function \u2014 no side effects, safe to unit-test in isolation.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport function resolveDemoUserEmails(): DemoUserEmail[] {\n const adminEmail = readEnvValue(DERIVED_EMAIL_ENV.admin) ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = readEnvValue(DERIVED_EMAIL_ENV.employee) ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n return [\n { role: 'superadmin', email: DEMO_SUPERADMIN_EMAIL },\n { role: 'admin', email: adminEmail },\n { role: 'employee', email: employeeEmail },\n ]\n}\n\nexport type SetupInitialTenantOptions = {\n orgName: string\n primaryUser: PrimaryUserInput\n roleNames?: string[]\n includeDerivedUsers?: boolean\n failIfUserExists?: boolean\n primaryUserRoles?: string[]\n includeSuperadminRole?: boolean\n /** Optional list of enabled modules. When provided, module setup hooks are called. */\n modules?: Module[]\n /**\n * Optional global slug to persist on the new Organization. When set, a\n * pre-flight uniqueness check across all tenants throws OrgSlugExistsError\n * on collision so scriptable callers can fail loudly instead of silently\n * reusing or clobbering an existing organization.\n */\n orgSlug?: string\n /**\n * Opt-in flag that allows seeding the derived admin/employee accounts when\n * the OM_INIT_ADMIN_PASSWORD / OM_INIT_EMPLOYEE_PASSWORD env vars are unset.\n *\n * - In non-production (`NODE_ENV !== 'production'`): the demo accounts are\n * seeded with the well-known `'secret'` password so local dev workflows\n * (e.g. `mercato init`) stay predictable for developers.\n * - In production: the fallback uses a randomly generated 96-bit password\n * (printed once by the CLI) so an operator who deliberately opts in still\n * avoids the historical hardcoded credential. When this flag is false/unset\n * in production and the env vars are missing, `DerivedUserPasswordRequiredError`\n * is thrown instead of silently seeding any account.\n */\n allowDemoDerivedPasswords?: boolean\n}\n\nexport class OrgSlugExistsError extends Error {\n constructor(public readonly slug: string) {\n super(`ORG_SLUG_EXISTS: an organization with slug \"${slug}\" already exists`)\n this.name = 'OrgSlugExistsError'\n }\n}\n\nexport class DerivedUserPasswordRequiredError extends Error {\n constructor(public readonly missing: string[]) {\n super(\n `DERIVED_USER_PASSWORD_REQUIRED: missing ${missing.join(', ')} (set the env vars, pass allowDemoDerivedPasswords: true / --include-demo-users in non-production, or disable derived user seeding)`,\n )\n this.name = 'DerivedUserPasswordRequiredError'\n }\n}\n\nexport type SetupInitialTenantResult = {\n tenantId: string\n organizationId: string\n users: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }>\n reusedExistingUser: boolean\n}\n\nexport async function setupInitialTenant(\n em: EntityManager,\n options: SetupInitialTenantOptions,\n): Promise<SetupInitialTenantResult> {\n const {\n primaryUser,\n includeDerivedUsers = true,\n failIfUserExists = false,\n primaryUserRoles,\n includeSuperadminRole = true,\n } = options\n const primaryRolesInput = primaryUserRoles && primaryUserRoles.length ? primaryUserRoles : ['superadmin']\n const primaryRoles = includeSuperadminRole\n ? primaryRolesInput\n : primaryRolesInput.filter((role) => role !== 'superadmin')\n if (primaryRoles.length === 0) {\n throw new Error('PRIMARY_ROLES_REQUIRED')\n }\n const defaultRoleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const resolvedRoleNames = includeSuperadminRole\n ? defaultRoleNames\n : defaultRoleNames.filter((role) => role !== 'superadmin')\n const roleNames = Array.from(new Set([...resolvedRoleNames, ...primaryRoles]))\n const resolvedModules = options.modules ?? tryGetModules()\n const defaultEncryptionMaps = getDefaultEncryptionMaps(resolvedModules)\n\n const mainEmail = primaryUser.email\n const existingUserByHash = await findOneWithDecryption(\n em,\n User,\n { emailHash: { $in: emailHashLookupValues(mainEmail) }, deletedAt: null },\n {},\n { tenantId: null, organizationId: null },\n )\n const existingUser = existingUserByHash ?? await findOneWithDecryption(\n em,\n User,\n { email: mainEmail, deletedAt: null },\n {},\n { tenantId: null, organizationId: null },\n )\n if (existingUser && failIfUserExists) {\n throw new Error('USER_EXISTS')\n }\n\n if (options.orgSlug) {\n const slugConflict = await findOneWithDecryption(\n em,\n Organization,\n { slug: options.orgSlug },\n {},\n { tenantId: null, organizationId: null },\n )\n if (slugConflict) {\n throw new OrgSlugExistsError(options.orgSlug)\n }\n }\n\n let tenantId: string | undefined\n let organizationId: string | undefined\n let reusedExistingUser = false\n const userSnapshots: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }> = []\n\n await em.transactional(async (tem) => {\n if (!existingUser) return\n reusedExistingUser = true\n tenantId = existingUser.tenantId ? String(existingUser.tenantId) : undefined\n organizationId = existingUser.organizationId ? String(existingUser.organizationId) : undefined\n const roleTenantId = normalizeTenantId(existingUser.tenantId ?? null) ?? null\n if (!roleTenantId) {\n throw new Error('Cannot reuse a user without a tenantId \u2014 global roles are not supported')\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n const requiredRoleSet = new Set([...roleNames, ...primaryRoles])\n const links = await findWithDecryption(\n tem,\n UserRole,\n { user: existingUser },\n { populate: ['role'] },\n { tenantId: roleTenantId, organizationId: null },\n )\n const currentRoles = new Set(links.map((link) => link.role.name))\n for (const roleName of requiredRoleSet) {\n if (!currentRoles.has(roleName)) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n tem.persist(tem.create(UserRole, { user: existingUser, role, createdAt: new Date() }))\n }\n }\n await tem.flush()\n const roles = Array.from(new Set([...currentRoles, ...roleNames]))\n userSnapshots.push({ user: existingUser, roles, created: false })\n })\n\n if (!existingUser) {\n const baseUsers: Array<{\n email: string\n roles: string[]\n name?: string | null\n passwordHash?: string | null\n generatedPassword?: string | null\n }> = [\n { email: primaryUser.email, roles: primaryRoles, name: resolvePrimaryName(primaryUser) },\n ]\n if (includeDerivedUsers) {\n const adminOverride = readEnvValue(DERIVED_EMAIL_ENV.admin)\n const employeeOverride = readEnvValue(DERIVED_EMAIL_ENV.employee)\n const adminEmail = adminOverride ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = employeeOverride ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const envAdminPwd = readEnvValue('OM_INIT_ADMIN_PASSWORD')\n const envEmployeePwd = readEnvValue('OM_INIT_EMPLOYEE_PASSWORD')\n const isProduction = process.env.NODE_ENV === 'production'\n const allowDemo = options.allowDemoDerivedPasswords === true\n if (isProduction && !allowDemo) {\n const missing: string[] = []\n if (!envAdminPwd) missing.push('OM_INIT_ADMIN_PASSWORD')\n if (!envEmployeePwd) missing.push('OM_INIT_EMPLOYEE_PASSWORD')\n if (missing.length) {\n throw new DerivedUserPasswordRequiredError(missing)\n }\n }\n // In non-production, fall back to the well-known DEMO_DERIVED_PASSWORD so\n // local dev workflows stay predictable (admin@/employee@ login with the\n // documented demo password). In production we either have env-supplied\n // values, or \u2014 for opt-in --include-demo-users flows \u2014 we generate a\n // random one-time password and surface it via `generatedPassword` so the\n // operator can capture it. Production callers without env vars and\n // without the opt-in already threw above.\n const fallbackAdminPwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const fallbackEmployeePwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const adminPasswordPlain = envAdminPwd ?? fallbackAdminPwd\n const employeePasswordPlain = envEmployeePwd ?? fallbackEmployeePwd\n const adminPasswordHash = await hash(adminPasswordPlain, 10)\n const employeePasswordHash = await hash(employeePasswordPlain, 10)\n addUniqueBaseUser(baseUsers, {\n email: adminEmail,\n roles: ['admin'],\n passwordHash: adminPasswordHash,\n generatedPassword: envAdminPwd ? null : adminPasswordPlain,\n })\n addUniqueBaseUser(baseUsers, {\n email: employeeEmail,\n roles: ['employee'],\n passwordHash: employeePasswordHash,\n generatedPassword: envEmployeePwd ? null : employeePasswordPlain,\n })\n }\n const passwordHash = await resolvePasswordHash(primaryUser)\n\n await em.transactional(async (tem) => {\n const tenant = tem.create(Tenant, {\n name: options.orgName,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(tenant)\n await tem.flush()\n\n const organization = tem.create(Organization, {\n name: options.orgName,\n slug: options.orgSlug ?? null,\n tenant,\n isActive: true,\n depth: 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n logoPreserveAspectRatio: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(organization)\n await tem.flush()\n\n tenantId = String(tenant.id)\n organizationId = String(organization.id)\n const roleTenantId = tenantId\n\n if (isTenantDataEncryptionEnabled()) {\n try {\n const kms = createKmsService()\n if (kms.isHealthy()) {\n if (isEncryptionDebugEnabled()) {\n logger.info('Provisioning tenant DEK', { tenantId: String(tenant.id) })\n }\n await kms.createTenantDek(String(tenant.id))\n if (isEncryptionDebugEnabled()) {\n logger.info('Created tenant DEK during setup', { tenantId: String(tenant.id) })\n }\n } else {\n if (isEncryptionDebugEnabled()) {\n logger.warn('KMS not healthy, skipping tenant DEK creation', { tenantId: String(tenant.id) })\n }\n }\n } catch (err) {\n if (isEncryptionDebugEnabled()) {\n logger.warn('Failed to create tenant DEK', { err })\n }\n }\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n if (isTenantDataEncryptionEnabled()) {\n // System-scoped maps are resolved from module code, never from a tenant row.\n // Persisting one here would make the tenant-scoped encryption CLIs believe they\n // own that entity and re-wrap its `system:<entityId>` ciphertext under the tenant\n // DEK, which runtime decryption can no longer read.\n for (const spec of defaultEncryptionMaps) {\n if (spec.keyScope === 'system') continue\n const existing = await findOneWithDecryption(tem, EncryptionMap, { entityId: spec.entityId, tenantId: tenant.id, organizationId: organization.id, deletedAt: null }, {}, { tenantId: String(tenant.id), organizationId: String(organization.id) })\n if (!existing) {\n tem.persist(tem.create(EncryptionMap, {\n entityId: spec.entityId,\n tenantId: tenant.id,\n organizationId: organization.id,\n fieldsJson: spec.fields,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n }))\n } else {\n existing.fieldsJson = spec.fields\n existing.isActive = true\n }\n }\n await tem.flush()\n }\n })\n\n await em.transactional(async (tem) => {\n if (!tenantId || !organizationId) return\n const roleTenantId = tenantId\n const encryptionService = isTenantDataEncryptionEnabled()\n ? new TenantDataEncryptionService(tem as any, { kms: createKmsService() })\n : null\n if (encryptionService) {\n await encryptionService.invalidateMap('auth:user', String(tenantId), String(organizationId))\n await encryptionService.invalidateMap('auth:user', String(tenantId), null)\n }\n\n for (const base of baseUsers) {\n const resolvedPasswordHash = base.passwordHash ?? passwordHash\n let user = await findOneWithDecryption(tem, User, { email: base.email }, {}, { tenantId: tenantId ?? null, organizationId: organizationId ?? null })\n const confirm = primaryUser.confirm ?? true\n const encryptedPayload = encryptionService\n ? await encryptionService.encryptEntityPayload('auth:user', { email: base.email }, tenantId, organizationId)\n : { email: base.email, emailHash: computeEmailHash(base.email) }\n if (user) {\n user.passwordHash = resolvedPasswordHash\n user.organizationId = organizationId\n user.tenantId = tenantId\n if (isTenantDataEncryptionEnabled()) {\n user.email = encryptedPayload.email as any\n user.emailHash = (encryptedPayload as any).emailHash ?? computeEmailHash(base.email)\n }\n if (base.name) user.name = base.name\n if (confirm) user.isConfirmed = true\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: false, generatedPassword: base.generatedPassword ?? null })\n } else {\n user = tem.create(User, {\n email: (encryptedPayload as any).email ?? base.email,\n emailHash: isTenantDataEncryptionEnabled() ? (encryptedPayload as any).emailHash ?? computeEmailHash(base.email) : undefined,\n passwordHash: resolvedPasswordHash,\n organizationId,\n tenantId,\n name: base.name ?? undefined,\n isConfirmed: confirm,\n createdAt: new Date(),\n })\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: true, generatedPassword: base.generatedPassword ?? null })\n }\n await tem.flush()\n for (const roleName of base.roles) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n const existingLink = await findOneWithDecryption(tem, UserRole, { user, role }, {}, { tenantId: tenantId ?? null, organizationId: null })\n if (!existingLink) tem.persist(tem.create(UserRole, { user, role, createdAt: new Date() }))\n }\n await tem.flush()\n }\n })\n }\n\n if (!tenantId || !organizationId) {\n throw new Error('SETUP_FAILED')\n }\n\n if (!reusedExistingUser) {\n await rebuildHierarchyForTenant(em, tenantId)\n }\n\n await ensureDefaultRoleAcls(em, tenantId, resolvedModules, { includeSuperadminRole })\n await deactivateDemoUsersIfSelfOnboardingEnabled(em)\n\n // Call module onTenantCreated hooks\n for (const mod of resolvedModules) {\n if (mod.setup?.onTenantCreated) {\n await mod.setup.onTenantCreated({ em, tenantId, organizationId })\n }\n }\n\n return {\n tenantId,\n organizationId,\n users: userSnapshots,\n reusedExistingUser,\n }\n}\n\nfunction resolvePrimaryName(input: PrimaryUserInput): string | null {\n if (input.displayName && input.displayName.trim()) return input.displayName.trim()\n const parts = [input.firstName, input.lastName].map((value) => value?.trim()).filter(Boolean)\n if (parts.length) return parts.join(' ')\n return null\n}\n\nfunction readEnvValue(key: string): string | undefined {\n const value = process.env[key]\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction addUniqueBaseUser(\n baseUsers: Array<{ email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null }>,\n entry: { email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null },\n) {\n if (!entry.email) return\n const normalized = entry.email.toLowerCase()\n if (baseUsers.some((user) => user.email.toLowerCase() === normalized)) return\n baseUsers.push(entry)\n}\n\n/**\n * Well-known demo password seeded for derived admin@/employee@ accounts in\n * non-production (`NODE_ENV !== 'production'`) when no env override is set.\n * Keeps the documented `yarn dev` / `mercato init` DX predictable. Never used\n * in production: the production branch either consumes env-supplied values or\n * falls back to `generateDerivedPassword()` so credentials remain non-guessable.\n */\nconst DEMO_DERIVED_PASSWORD = 'secret'\n\n/**\n * Generate a 16-character base64url password (96 bits of entropy) for a derived\n * demo user in production when no env override is provided AND the caller\n * explicitly opted in via `allowDemoDerivedPasswords`. Surfaced via the\n * `users[].generatedPassword` snapshot so CLI callers can print it to the\n * operator \u2014 there is no other recovery path for these credentials.\n */\nfunction generateDerivedPassword(): string {\n return randomBytes(12).toString('base64url')\n}\n\nfunction isDemoModeEnabled(): boolean {\n const parsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n return parsed === false ? false : true\n}\n\nfunction shouldKeepDemoSuperadminDuringInit(): boolean {\n if (process.env.OM_INIT_FLOW !== 'true') return false\n if (!readEnvValue('OM_INIT_SUPERADMIN_EMAIL')) return false\n return isDemoModeEnabled()\n}\n\nasync function resolvePasswordHash(input: PrimaryUserInput): Promise<string | null> {\n if (typeof input.hashedPassword === 'string') return input.hashedPassword\n if (input.password) return hash(input.password, 10)\n return null\n}\n\nexport async function ensureDefaultRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules: Module[],\n options: { includeSuperadminRole?: boolean } = {},\n) {\n const includeSuperadminRole = options.includeSuperadminRole ?? true\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const superadminRole = includeSuperadminRole ? await findRoleByName(em, 'superadmin', roleTenantId) : null\n const adminRole = await findRoleByName(em, 'admin', roleTenantId)\n const employeeRole = await findRoleByName(em, 'employee', roleTenantId)\n\n // Merge features from all enabled modules' setup configs\n const builtInRoles = ['superadmin', 'admin', 'employee'] as const\n const superadminFeatures: string[] = []\n const adminFeatures: string[] = []\n const employeeFeatures: string[] = []\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of modules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n if (roleFeatures.superadmin) superadminFeatures.push(...roleFeatures.superadmin)\n if (roleFeatures.admin) adminFeatures.push(...roleFeatures.admin)\n if (roleFeatures.employee) employeeFeatures.push(...roleFeatures.employee)\n\n // Collect features for custom roles (any key not in builtInRoles)\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if ((builtInRoles as readonly string[]).includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n logger.info('Seeded default role features', {\n superadmin: superadminFeatures,\n admin: adminFeatures,\n employee: employeeFeatures,\n ...(customRoleFeatures.size > 0\n ? Object.fromEntries(customRoleFeatures)\n : {}),\n })\n\n if (includeSuperadminRole && superadminRole) {\n await ensureRoleAclFor(em, superadminRole, tenantId, superadminFeatures, { isSuperAdmin: true })\n }\n if (adminRole) {\n await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures)\n }\n if (employeeRole) {\n await ensureRoleAclFor(em, employeeRole, tenantId, employeeFeatures)\n }\n\n // Seed ACLs for custom roles defined by app modules.\n // NOTE: Custom roles may not exist yet if they are created in seedDefaults\n // (which runs after this function). In that case, use ensureCustomRoleAcls()\n // after seedDefaults to pick them up.\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n }\n }\n}\n\n/**\n * Seed ACLs for custom roles defined in module defaultRoleFeatures.\n * Call this AFTER seedDefaults to pick up roles created by app modules.\n * Safe to call multiple times \u2014 ensureRoleAclFor merges features idempotently.\n */\nexport async function ensureCustomRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules?: Module[],\n): Promise<void> {\n const resolvedModules = modules ?? tryGetModules()\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const builtInRoles = ['superadmin', 'admin', 'employee']\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of resolvedModules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if (builtInRoles.includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n if (customRoleFeatures.size === 0) return\n\n let seeded = 0\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n seeded++\n }\n }\n if (seeded > 0) {\n logger.info('Seeded custom role ACLs', { seeded })\n }\n}\n\nasync function ensureRoleAclFor(\n em: EntityManager,\n role: Role,\n tenantId: string,\n features: string[],\n options: { isSuperAdmin?: boolean } = {},\n) {\n const existing = await findOneWithDecryption(em, RoleAcl, { role, tenantId }, {}, { tenantId, organizationId: null })\n if (!existing) {\n const acl = em.create(RoleAcl, {\n role,\n tenantId,\n featuresJson: features,\n isSuperAdmin: !!options.isSuperAdmin,\n createdAt: new Date(),\n })\n await em.persist(acl).flush()\n return\n }\n const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []\n const merged = Array.from(new Set([...currentFeatures, ...features]))\n const changed =\n merged.length !== currentFeatures.length ||\n merged.some((value, index) => value !== currentFeatures[index])\n if (changed) existing.featuresJson = merged\n if (options.isSuperAdmin && !existing.isSuperAdmin) {\n existing.isSuperAdmin = true\n }\n if (changed || options.isSuperAdmin) {\n await em.persist(existing).flush()\n }\n}\n\n/**\n * Neutralizes every demo account the setup path may have seeded\n * (superadmin, admin, employee \u2014 honoring OM_INIT_*_EMAIL overrides)\n * when SELF_SERVICE_ONBOARDING_ENABLED is on and the operator did not\n * opt in to keeping demo credentials via shouldKeepDemoSuperadminDuringInit.\n *\n * Each user is processed in its own try/catch so a single failure (e.g.\n * decryption error on a legacy row) does not skip the remaining accounts.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport async function deactivateDemoUsersIfSelfOnboardingEnabled(em: EntityManager) {\n if (process.env.SELF_SERVICE_ONBOARDING_ENABLED !== 'true') return\n if (shouldKeepDemoSuperadminDuringInit()) return\n for (const { role, email } of resolveDemoUserEmails()) {\n try {\n const user = await findOneWithDecryption(\n em,\n User,\n { email },\n {},\n { tenantId: null, organizationId: null },\n )\n if (!user) continue\n let dirty = false\n if (user.passwordHash) {\n user.passwordHash = null\n dirty = true\n }\n if (user.isConfirmed !== false) {\n user.isConfirmed = false\n dirty = true\n }\n if (dirty) {\n await em.persist(user).flush()\n }\n } catch (error) {\n logger.error('Failed to deactivate demo user', { role, email, err: error })\n }\n }\n}\n\n/**\n * @deprecated Renamed to {@link deactivateDemoUsersIfSelfOnboardingEnabled}\n * because the helper now neutralizes admin/employee demo accounts in addition\n * to superadmin (security tracker finding #5). Kept as an internal alias to\n * avoid breaking any out-of-tree caller that imported the old name; will be\n * removed in a future major.\n */\nconst deactivateDemoSuperAdminIfSelfOnboardingEnabled = deactivateDemoUsersIfSelfOnboardingEnabled\n\n/** Try to get modules from runtime registry; returns empty array if not yet registered. */\nfunction tryGetModules(): Module[] {\n try {\n const { getModules } = require('@open-mercato/shared/lib/modules/registry')\n return getModules()\n } catch {\n return []\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -57,9 +57,16 @@ async function enforceTenantSelection(ctx, requested) {
57
57
  if (normalized === actorTenant) return actorTenant;
58
58
  throw forbidden("Not authorized to target this tenant.");
59
59
  }
60
+ async function requireSuperAdmin(ctx) {
61
+ const isSuperAdmin = await resolveIsSuperAdmin(ctx);
62
+ if (!isSuperAdmin) {
63
+ throw forbidden("Forbidden");
64
+ }
65
+ }
60
66
  export {
61
67
  enforceTenantSelection,
62
68
  normalizeTenantId,
69
+ requireSuperAdmin,
63
70
  resolveIsSuperAdmin
64
71
  };
65
72
  //# sourceMappingURL=tenantAccess.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/lib/tenantAccess.ts"],
4
- "sourcesContent": ["import { forbidden } from '@open-mercato/shared/lib/crud/errors'\nimport { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'tenant-access' })\n\ntype TenantGuardCtx = {\n auth: {\n sub?: string | null\n tenantId?: string | null\n orgId?: string | null\n roles?: string[]\n isSuperAdmin?: boolean\n } | null\n container: { resolve<T = unknown>(name: string): T }\n}\n\nconst SUPER_ADMIN_SYMBOL = Symbol.for('auth.tenantGuard.isSuperAdmin')\n\nexport function normalizeTenantId(value: unknown): string | null | undefined {\n if (value === undefined) return undefined\n if (value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n }\n return null\n}\n\nexport async function resolveIsSuperAdmin(ctx: TenantGuardCtx): Promise<boolean> {\n const cacheStore = ctx as { [SUPER_ADMIN_SYMBOL]?: boolean }\n const cached = cacheStore[SUPER_ADMIN_SYMBOL]\n if (typeof cached === 'boolean') return cached\n const auth = ctx.auth\n if (!auth?.sub) {\n cacheStore[SUPER_ADMIN_SYMBOL] = false\n return false\n }\n if (auth.isSuperAdmin === true) {\n cacheStore[SUPER_ADMIN_SYMBOL] = true\n return true\n }\n try {\n const rbac = (ctx.container.resolve('rbacService') as RbacService)\n const acl = await rbac.loadAcl(auth.sub, {\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n })\n const value = !!acl?.isSuperAdmin\n cacheStore[SUPER_ADMIN_SYMBOL] = value\n return value\n } catch (error) {\n logger.error('Failed to resolve rbac', { err: error })\n cacheStore[SUPER_ADMIN_SYMBOL] = false\n return false\n }\n}\n\nexport async function enforceTenantSelection(ctx: TenantGuardCtx, requested: unknown): Promise<string | null> {\n const normalized = normalizeTenantId(requested)\n const actorTenant = normalizeTenantId(ctx.auth?.tenantId ?? null) ?? null\n const isSuperAdmin = await resolveIsSuperAdmin(ctx)\n\n if (isSuperAdmin) {\n if (normalized === undefined) return actorTenant\n return normalized ?? null\n }\n\n if (!actorTenant) {\n if (normalized && normalized !== null) {\n throw forbidden('Not authorized to target this tenant.')\n }\n return actorTenant\n }\n\n if (normalized === undefined) return actorTenant\n if (normalized === actorTenant) return actorTenant\n throw forbidden('Not authorized to target this tenant.')\n}\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,MAAM,EAAE,MAAM,EAAE,WAAW,gBAAgB,CAAC;AAaxE,MAAM,qBAAqB,uBAAO,IAAI,+BAA+B;AAE9D,SAAS,kBAAkB,OAA2C;AAC3E,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC;AACA,SAAO;AACT;AAEA,eAAsB,oBAAoB,KAAuC;AAC/E,QAAM,aAAa;AACnB,QAAM,SAAS,WAAW,kBAAkB;AAC5C,MAAI,OAAO,WAAW,UAAW,QAAO;AACxC,QAAM,OAAO,IAAI;AACjB,MAAI,CAAC,MAAM,KAAK;AACd,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT;AACA,MAAI,KAAK,iBAAiB,MAAM;AAC9B,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAQ,IAAI,UAAU,QAAQ,aAAa;AACjD,UAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,KAAK;AAAA,MACvC,UAAU,KAAK,YAAY;AAAA,MAC3B,gBAAgB,KAAK,SAAS;AAAA,IAChC,CAAC;AACD,UAAM,QAAQ,CAAC,CAAC,KAAK;AACrB,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO,MAAM,0BAA0B,EAAE,KAAK,MAAM,CAAC;AACrD,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,uBAAuB,KAAqB,WAA4C;AAC5G,QAAM,aAAa,kBAAkB,SAAS;AAC9C,QAAM,cAAc,kBAAkB,IAAI,MAAM,YAAY,IAAI,KAAK;AACrE,QAAM,eAAe,MAAM,oBAAoB,GAAG;AAElD,MAAI,cAAc;AAChB,QAAI,eAAe,OAAW,QAAO;AACrC,WAAO,cAAc;AAAA,EACvB;AAEA,MAAI,CAAC,aAAa;AAChB,QAAI,cAAc,eAAe,MAAM;AACrC,YAAM,UAAU,uCAAuC;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,OAAW,QAAO;AACrC,MAAI,eAAe,YAAa,QAAO;AACvC,QAAM,UAAU,uCAAuC;AACzD;",
4
+ "sourcesContent": ["import { forbidden } from '@open-mercato/shared/lib/crud/errors'\nimport { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'tenant-access' })\n\ntype TenantGuardCtx = {\n auth: {\n sub?: string | null\n tenantId?: string | null\n orgId?: string | null\n roles?: string[]\n isSuperAdmin?: boolean\n } | null\n container: { resolve<T = unknown>(name: string): T }\n}\n\nconst SUPER_ADMIN_SYMBOL = Symbol.for('auth.tenantGuard.isSuperAdmin')\n\nexport function normalizeTenantId(value: unknown): string | null | undefined {\n if (value === undefined) return undefined\n if (value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n }\n return null\n}\n\nexport async function resolveIsSuperAdmin(ctx: TenantGuardCtx): Promise<boolean> {\n const cacheStore = ctx as { [SUPER_ADMIN_SYMBOL]?: boolean }\n const cached = cacheStore[SUPER_ADMIN_SYMBOL]\n if (typeof cached === 'boolean') return cached\n const auth = ctx.auth\n if (!auth?.sub) {\n cacheStore[SUPER_ADMIN_SYMBOL] = false\n return false\n }\n if (auth.isSuperAdmin === true) {\n cacheStore[SUPER_ADMIN_SYMBOL] = true\n return true\n }\n try {\n const rbac = (ctx.container.resolve('rbacService') as RbacService)\n const acl = await rbac.loadAcl(auth.sub, {\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n })\n const value = !!acl?.isSuperAdmin\n cacheStore[SUPER_ADMIN_SYMBOL] = value\n return value\n } catch (error) {\n logger.error('Failed to resolve rbac', { err: error })\n cacheStore[SUPER_ADMIN_SYMBOL] = false\n return false\n }\n}\n\nexport async function enforceTenantSelection(ctx: TenantGuardCtx, requested: unknown): Promise<string | null> {\n const normalized = normalizeTenantId(requested)\n const actorTenant = normalizeTenantId(ctx.auth?.tenantId ?? null) ?? null\n const isSuperAdmin = await resolveIsSuperAdmin(ctx)\n\n if (isSuperAdmin) {\n if (normalized === undefined) return actorTenant\n return normalized ?? null\n }\n\n if (!actorTenant) {\n if (normalized && normalized !== null) {\n throw forbidden('Not authorized to target this tenant.')\n }\n return actorTenant\n }\n\n if (normalized === undefined) return actorTenant\n if (normalized === actorTenant) return actorTenant\n throw forbidden('Not authorized to target this tenant.')\n}\n\nexport async function requireSuperAdmin(ctx: TenantGuardCtx): Promise<void> {\n const isSuperAdmin = await resolveIsSuperAdmin(ctx)\n if (!isSuperAdmin) {\n throw forbidden('Forbidden')\n }\n}\n\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,MAAM,EAAE,MAAM,EAAE,WAAW,gBAAgB,CAAC;AAaxE,MAAM,qBAAqB,uBAAO,IAAI,+BAA+B;AAE9D,SAAS,kBAAkB,OAA2C;AAC3E,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC;AACA,SAAO;AACT;AAEA,eAAsB,oBAAoB,KAAuC;AAC/E,QAAM,aAAa;AACnB,QAAM,SAAS,WAAW,kBAAkB;AAC5C,MAAI,OAAO,WAAW,UAAW,QAAO;AACxC,QAAM,OAAO,IAAI;AACjB,MAAI,CAAC,MAAM,KAAK;AACd,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT;AACA,MAAI,KAAK,iBAAiB,MAAM;AAC9B,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAQ,IAAI,UAAU,QAAQ,aAAa;AACjD,UAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,KAAK;AAAA,MACvC,UAAU,KAAK,YAAY;AAAA,MAC3B,gBAAgB,KAAK,SAAS;AAAA,IAChC,CAAC;AACD,UAAM,QAAQ,CAAC,CAAC,KAAK;AACrB,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO,MAAM,0BAA0B,EAAE,KAAK,MAAM,CAAC;AACrD,eAAW,kBAAkB,IAAI;AACjC,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,uBAAuB,KAAqB,WAA4C;AAC5G,QAAM,aAAa,kBAAkB,SAAS;AAC9C,QAAM,cAAc,kBAAkB,IAAI,MAAM,YAAY,IAAI,KAAK;AACrE,QAAM,eAAe,MAAM,oBAAoB,GAAG;AAElD,MAAI,cAAc;AAChB,QAAI,eAAe,OAAW,QAAO;AACrC,WAAO,cAAc;AAAA,EACvB;AAEA,MAAI,CAAC,aAAa;AAChB,QAAI,cAAc,eAAe,MAAM;AACrC,YAAM,UAAU,uCAAuC;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,OAAW,QAAO;AACrC,MAAI,eAAe,YAAa,QAAO;AACvC,QAAM,UAAU,uCAAuC;AACzD;AAEA,eAAsB,kBAAkB,KAAoC;AAC1E,QAAM,eAAe,MAAM,oBAAoB,GAAG;AAClD,MAAI,CAAC,cAAc;AACjB,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,8 +3,11 @@ import { UserAcl, RoleAcl, User, UserRole } from "@open-mercato/core/modules/aut
3
3
  import { ApiKey } from "@open-mercato/core/modules/api_keys/data/entities";
4
4
  import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
5
5
  import { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from "@open-mercato/core/modules/directory/utils/organizationScope";
6
- import { matchFeature as sharedMatchFeature, hasAllFeatures as sharedHasAllFeatures } from "@open-mercato/shared/lib/auth/featureMatch";
7
- import { filterGrantsByEnabledModules, getOwningModuleId, getEnabledModuleIds } from "@open-mercato/shared/security/enabledModulesRegistry";
6
+ import {
7
+ authorizeFeatures,
8
+ resolveEffectiveFeatures
9
+ } from "@open-mercato/shared/security/featurePolicy";
10
+ import { filterGrantsByEnabledModules } from "@open-mercato/shared/security/enabledModulesRegistry";
8
11
  function isAclData(value) {
9
12
  if (typeof value !== "object" || value === null) return false;
10
13
  const record = value;
@@ -32,31 +35,9 @@ class RbacService {
32
35
  setCacheTtl(ttlMs) {
33
36
  this.cacheTtlMs = ttlMs;
34
37
  }
35
- /**
36
- * Checks if a required feature is satisfied by a granted feature permission.
37
- *
38
- * Wildcard patterns:
39
- * - `*` (global wildcard): Grants access to all features
40
- * - `prefix.*` (module wildcard): Grants access to all features starting with `prefix.`
41
- * and also the exact prefix itself (e.g., `entities.*` matches both `entities` and `entities.records.view`)
42
- * - Exact match: Feature must match exactly (e.g., `users.view` only matches `users.view`)
43
- *
44
- * @param required - The feature being requested (e.g., 'entities.records.view')
45
- * @param granted - The feature permission granted (e.g., 'entities.*' or '*')
46
- * @returns true if the granted permission satisfies the required feature
47
- *
48
- * @example
49
- * matchFeature('users.view', '*') // true - global wildcard
50
- * matchFeature('entities.records.view', 'entities.*') // true - module wildcard
51
- * matchFeature('entities', 'entities.*') // true - exact prefix match
52
- * matchFeature('users.view', 'entities.*') // false - different module
53
- * matchFeature('users.view', 'users.view') // true - exact match
54
- */
55
- matchFeature(required, granted) {
56
- return sharedMatchFeature(required, granted);
57
- }
38
+ /** Compatibility wrapper for callers that already have both feature lists. */
58
39
  hasAllFeatures(required, granted) {
59
- return sharedHasAllFeatures(required, granted);
40
+ return authorizeFeatures(required, { grantedFeatures: granted });
60
41
  }
61
42
  roleAclAllowsOrganization(acl, organizationId) {
62
43
  if (!organizationId) return true;
@@ -324,17 +305,19 @@ class RbacService {
324
305
  */
325
306
  async tenantHasFeature(tenantId, feature, opts) {
326
307
  if (!tenantId || !feature) return false;
327
- const enabledIds = getEnabledModuleIds();
328
- if (enabledIds.length && !enabledIds.includes(getOwningModuleId(feature))) return false;
329
308
  const em = this.em.fork();
330
309
  const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null }, {});
331
310
  const list = Array.isArray(roleAcls) ? roleAcls : [];
332
311
  const organizationId = opts?.organizationId ?? null;
333
312
  for (const acl of list) {
334
313
  if (!this.roleAclAllowsOrganization(acl, organizationId)) continue;
335
- if (acl.isSuperAdmin) return true;
336
314
  const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : [];
337
- if (this.hasAllFeatures([feature], filterGrantsByEnabledModules(grants))) return true;
315
+ if (authorizeFeatures([feature], {
316
+ grantedFeatures: grants,
317
+ unrestricted: acl.isSuperAdmin
318
+ })) {
319
+ return true;
320
+ }
338
321
  }
339
322
  return false;
340
323
  }
@@ -376,22 +359,17 @@ class RbacService {
376
359
  async userHasAllFeatures(userId, required, scope) {
377
360
  if (!required.length) return true;
378
361
  const acl = await this.loadAcl(userId, scope);
379
- if (acl.isSuperAdmin) {
380
- const enabledIds = getEnabledModuleIds();
381
- if (!enabledIds.length) return true;
382
- const enabledSet = new Set(enabledIds);
383
- return required.every((feature) => enabledSet.has(getOwningModuleId(feature)));
384
- }
385
- if (acl.organizations && scope.organizationId && !acl.organizations.includes(scope.organizationId) && !acl.organizations.includes("__all__")) return false;
386
- return this.hasAllFeatures(required, filterGrantsByEnabledModules(acl.features));
362
+ const organizationAllowed = acl.isSuperAdmin || !acl.organizations || !scope.organizationId || acl.organizations.includes(scope.organizationId) || acl.organizations.includes("__all__");
363
+ return authorizeFeatures(required, {
364
+ grantedFeatures: acl.features,
365
+ unrestricted: acl.isSuperAdmin,
366
+ scopeAllowed: organizationAllowed
367
+ });
387
368
  }
388
369
  /**
389
- * Returns the effective feature grant list for a user within a scope,
390
- * filtered to enabled modules only. Super admins receive `['*']` expanded
391
- * to per-module wildcards via `filterGrantsByEnabledModules` — consistent
392
- * with `userHasAllFeatures` which also enforces disabled-module boundaries
393
- * for super admins. Returns `[]` when the requested organization is outside
394
- * the user's visibility list, or when the user does not exist.
370
+ * Returns the user's infrastructure grant list, filtered to enabled modules.
371
+ * The result may contain wildcards; authoritative checks must still go through
372
+ * `authorizeFeatures` or `userHasAllFeatures` so null overrides are enforced.
395
373
  */
396
374
  async getGrantedFeatures(userId, scope) {
397
375
  const acl = await this.loadAcl(userId, scope);
@@ -401,6 +379,13 @@ class RbacService {
401
379
  }
402
380
  return filterGrantsByEnabledModules(acl.features);
403
381
  }
382
+ /** Returns concrete active feature IDs for browser capability payloads. */
383
+ async getEffectiveFeatures(userId, scope) {
384
+ const acl = await this.loadAcl(userId, scope);
385
+ const organizationAllowed = acl.isSuperAdmin || !acl.organizations || !scope.organizationId || acl.organizations.includes(scope.organizationId) || acl.organizations.includes("__all__");
386
+ if (!organizationAllowed) return [];
387
+ return resolveEffectiveFeatures(acl.isSuperAdmin ? ["*"] : acl.features);
388
+ }
404
389
  }
405
390
  export {
406
391
  RbacService
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/services/rbacService.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getCurrentCacheTenant, runWithCacheTenant } from '@open-mercato/cache'\nimport { UserAcl, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { ApiKey } from '@open-mercato/core/modules/api_keys/data/entities'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { matchFeature as sharedMatchFeature, hasAllFeatures as sharedHasAllFeatures } from '@open-mercato/shared/lib/auth/featureMatch'\nimport { filterGrantsByEnabledModules, getOwningModuleId, getEnabledModuleIds } from '@open-mercato/shared/security/enabledModulesRegistry'\n\ninterface AclData {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nfunction isAclData(value: unknown): value is AclData {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<AclData>\n if (typeof record.isSuperAdmin !== 'boolean') return false\n if (!Array.isArray(record.features) || record.features.some((feature) => typeof feature !== 'string')) return false\n if (record.organizations !== null && record.organizations !== undefined) {\n if (!Array.isArray(record.organizations)) return false\n if (record.organizations.some((org) => typeof org !== 'string')) return false\n }\n return true\n}\n\nexport class RbacService {\n private cacheTtlMs: number = 5 * 60 * 1000 // 5 minutes default\n private cache: CacheStrategy | null = null\n private globalSuperAdminCache = new Map<string, boolean>()\n\n constructor(private em: EntityManager, cache?: CacheStrategy) {\n this.cache = cache || null\n }\n\n /**\n * Set cache TTL in milliseconds\n * @param ttlMs - Time to live in milliseconds\n */\n setCacheTtl(ttlMs: number) {\n this.cacheTtlMs = ttlMs\n }\n\n /**\n * Checks if a required feature is satisfied by a granted feature permission.\n * \n * Wildcard patterns:\n * - `*` (global wildcard): Grants access to all features\n * - `prefix.*` (module wildcard): Grants access to all features starting with `prefix.`\n * and also the exact prefix itself (e.g., `entities.*` matches both `entities` and `entities.records.view`)\n * - Exact match: Feature must match exactly (e.g., `users.view` only matches `users.view`)\n * \n * @param required - The feature being requested (e.g., 'entities.records.view')\n * @param granted - The feature permission granted (e.g., 'entities.*' or '*')\n * @returns true if the granted permission satisfies the required feature\n * \n * @example\n * matchFeature('users.view', '*') // true - global wildcard\n * matchFeature('entities.records.view', 'entities.*') // true - module wildcard\n * matchFeature('entities', 'entities.*') // true - exact prefix match\n * matchFeature('users.view', 'entities.*') // false - different module\n * matchFeature('users.view', 'users.view') // true - exact match\n */\n private matchFeature(required: string, granted: string): boolean {\n return sharedMatchFeature(required, granted)\n }\n\n public hasAllFeatures(required: string[], granted: string[]): boolean {\n return sharedHasAllFeatures(required, granted)\n }\n\n private roleAclAllowsOrganization(acl: RoleAcl, organizationId: string | null | undefined): boolean {\n if (!organizationId) return true\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || !organizations.length || organizations.includes('__all__')) return true\n return organizations.includes(organizationId)\n }\n\n private getCacheKey(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string {\n return `rbac:${userId}:${scope.tenantId || 'null'}:${scope.organizationId || 'null'}`\n }\n\n private getUserTag(userId: string): string {\n return `rbac:user:${userId}`\n }\n\n private getTenantTag(tenantId: string): string {\n return `rbac:tenant:${tenantId}`\n }\n\n private getOrganizationTag(organizationId: string): string {\n return `rbac:org:${organizationId}`\n }\n\n private async getFromCache(cacheKey: string): Promise<AclData | null> {\n if (!this.cache) return null\n const cached = await this.cache.get(cacheKey)\n if (!cached) return null\n return isAclData(cached) ? cached : null\n }\n\n private async setCache(cacheKey: string, data: AclData, userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<void> {\n if (!this.cache) return\n\n const tags = [\n this.getUserTag(userId),\n 'rbac:all'\n ]\n\n if (scope.tenantId) {\n tags.push(this.getTenantTag(scope.tenantId))\n }\n\n if (scope.organizationId) {\n tags.push(this.getOrganizationTag(scope.organizationId))\n }\n\n await this.cache.set(cacheKey, data, {\n ttl: this.cacheTtlMs,\n tags\n })\n }\n\n /**\n * Invalidates cached ACL data for a specific user across all tenants and organizations.\n * Call this when a user's roles or user-specific ACL is modified.\n * \n * @param userId - The ID of the user whose cache should be invalidated\n */\n async invalidateUserCache(userId: string): Promise<void> {\n this.globalSuperAdminCache.delete(userId)\n // Also drop the directory OrganizationScope cache for this user. That scope's\n // accessible-org set is derived from this user's ACL/role grants, so any\n // permission change that invalidates the RBAC cache must invalidate the\n // resolved scope too. This is the missing `org-scope:user:*` caller required\n // before the cross-request scope TTL can be safely enabled (issue #2259).\n await this.deleteCacheByTags([this.getUserTag(userId), buildOrgScopeUserCacheTag(userId)])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific tenant.\n * Call this when a role's ACL is modified, since roles are tenant-scoped\n * and affect all users in that tenant who have that role.\n * \n * @param tenantId - The ID of the tenant whose cache should be invalidated\n */\n async invalidateTenantCache(tenantId: string): Promise<void> {\n this.globalSuperAdminCache.clear()\n // Role ACL changes invalidate every user in the tenant; the resolved\n // OrganizationScope for those users derives from the same grants, so drop\n // the tenant-tagged scope entries alongside the RBAC ones (issue #2259).\n await this.deleteCacheByTags([this.getTenantTag(tenantId), buildOrgScopeTenantCacheTag(tenantId)], [tenantId])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific organization.\n * Call this when organization-level permissions or visibility changes.\n * \n * @param organizationId - The ID of the organization whose cache should be invalidated\n */\n async invalidateOrganizationCache(organizationId: string): Promise<void> {\n await this.deleteCacheByTags([this.getOrganizationTag(organizationId)])\n }\n\n /**\n * Clears all cached ACL data.\n * Use this for bulk operations or system-wide ACL changes.\n */\n async invalidateAllCache(): Promise<void> {\n this.globalSuperAdminCache.clear()\n await this.deleteCacheByTags(['rbac:all'])\n }\n\n private async deleteCacheByTags(tags: string[], tenantHints?: Array<string | null>): Promise<void> {\n if (!this.cache) return\n const contexts = new Set<string | null>()\n const current = getCurrentCacheTenant()\n contexts.add(current ?? null)\n contexts.add(null)\n if (Array.isArray(tenantHints)) {\n for (const hint of tenantHints) {\n contexts.add(hint ?? null)\n }\n }\n for (const ctx of contexts) {\n if (ctx === current) {\n await this.cache.deleteByTags(tags)\n } else {\n await runWithCacheTenant(ctx, async () => {\n await this.cache!.deleteByTags(tags)\n })\n }\n }\n }\n\n private async isGlobalSuperAdmin(userId: string): Promise<boolean> {\n if (this.globalSuperAdminCache.has(userId)) return this.globalSuperAdminCache.get(userId)!\n const em = this.em.fork()\n const userSuper = await em.findOne(UserAcl, { user: userId as any, isSuperAdmin: true })\n if (userSuper && (userSuper as any).isSuperAdmin) {\n this.globalSuperAdminCache.set(userId, true)\n return true\n }\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const linkList = Array.isArray(links) ? links : []\n if (!linkList.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleIds = Array.from(new Set(linkList.map((link) => {\n const role = link.role as any\n return role?.id ? String(role.id) : null\n }).filter((id): id is string => typeof id === 'string' && id.length > 0)))\n if (!roleIds.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleSuper = await em.findOne(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds as any } } as any)\n const result = !!(roleSuper && (roleSuper as any).isSuperAdmin)\n this.globalSuperAdminCache.set(userId, result)\n return result\n }\n\n /**\n * Loads the Access Control List (ACL) for a user within a given scope.\n * \n * The ACL resolution follows this priority:\n * 1. Per-user ACL (UserAcl) - if exists, use it exclusively\n * 2. Aggregated role ACLs (RoleAcl) - combine permissions from all user's roles\n * \n * Results are cached for performance (default 5 minutes TTL).\n * Cache is automatically invalidated when ACL-related data changes.\n * \n * @param userId - The ID of the user\n * @param scope - The tenant and organization context for ACL evaluation\n * @returns An object containing:\n * - isSuperAdmin: If true, user has unrestricted access to all features\n * - features: Array of feature strings (may include wildcards like 'entities.*')\n * - organizations: Array of organization IDs user can access, or null for all organizations\n * \n * @example\n * const acl = await rbacService.loadAcl('user-123', { tenantId: 'tenant-1', organizationId: 'org-1' })\n * // Returns: { isSuperAdmin: false, features: ['users.view', 'entities.*'], organizations: ['org-1', 'org-2'] }\n */\n async loadAcl(userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<{\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n }> {\n const cacheKey = this.getCacheKey(userId, scope)\n const cached = await this.getFromCache(cacheKey)\n if (cached) return cached\n\n if (!userId.startsWith('api_key:')) {\n if (await this.isGlobalSuperAdmin(userId)) {\n const result = { isSuperAdmin: true, features: ['*'], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n }\n\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const em = this.em.fork()\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = key.organizationId ? [key.organizationId] : null\n if (tenantId && roleIds.length) {\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any)\n for (const acl of racls) {\n isSuper = isSuper || !!acl.isSuperAdmin\n if (Array.isArray(acl.featuresJson)) {\n for (const f of acl.featuresJson) if (!features.includes(f)) features.push(f)\n }\n if (organizations !== null) {\n if (acl.organizationsJson == null) {\n organizations = null\n } else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes('__all__')) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...(organizations || []), ...acl.organizationsJson]))\n }\n }\n }\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Use a forked EntityManager to avoid inheriting an aborted transaction from callers\n const em = this.em.fork()\n const user = await em.findOne(User, { id: userId })\n if (!user) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || user.tenantId || null\n const orgId = scope.organizationId || user.organizationId || null\n\n if (!tenantId) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Per-user ACL first\n const uacl = await em.findOne(UserAcl, { user: userId as any, tenantId })\n if (uacl) {\n const result = {\n isSuperAdmin: !!uacl.isSuperAdmin,\n features: Array.isArray(uacl.featuresJson) ? (uacl.featuresJson as string[]) : [],\n organizations: Array.isArray(uacl.organizationsJson) ? (uacl.organizationsJson as string[]) : null,\n }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Aggregate role ACLs\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any, role: { tenantId } } as any,\n { populate: ['role'] },\n { tenantId, organizationId: orgId },\n )\n const linkList = Array.isArray(links) ? links : []\n const roleIds = linkList.map((l) => (l.role as any)?.id).filter(Boolean)\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = []\n if (roleIds.length) {\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any, {})\n const roleAcls = Array.isArray(racls) ? racls : []\n for (const r of roleAcls) {\n isSuper = isSuper || !!r.isSuperAdmin\n if (Array.isArray(r.featuresJson)) for (const f of r.featuresJson) if (!features.includes(f)) features.push(f)\n if (organizations !== null) {\n if (r.organizationsJson == null) organizations = null\n else if (Array.isArray(r.organizationsJson) && r.organizationsJson.includes('__all__')) organizations = null\n else organizations = Array.from(new Set([...(organizations || []), ...r.organizationsJson]))\n }\n }\n }\n if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes('__all__')) {\n // Out-of-scope org; caller will enforce\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n /**\n * Checks whether any tenant role grants a feature.\n *\n * This supports non-user runtimes such as scheduler workers that execute with\n * tenant scope but without an authenticated user.\n */\n async tenantHasFeature(\n tenantId: string | null | undefined,\n feature: string,\n opts?: { organizationId?: string | null },\n ): Promise<boolean> {\n if (!tenantId || !feature) return false\n\n const enabledIds = getEnabledModuleIds()\n if (enabledIds.length && !enabledIds.includes(getOwningModuleId(feature))) return false\n\n const em = this.em.fork()\n const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null } as any, {})\n const list = Array.isArray(roleAcls) ? roleAcls : []\n const organizationId = opts?.organizationId ?? null\n\n for (const acl of list) {\n if (!this.roleAclAllowsOrganization(acl, organizationId)) continue\n if (acl.isSuperAdmin) return true\n const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : []\n if (this.hasAllFeatures([feature], filterGrantsByEnabledModules(grants))) return true\n }\n\n return false\n }\n\n /**\n * Checks if a user has all required features within a given scope.\n *\n * This is the primary authorization check method used throughout the application.\n * It combines feature checking with organization visibility validation.\n *\n * Authorization logic:\n * 1. No features required \u2192 always returns true\n * 2. User is super admin \u2192 always returns true\n * 3. Organization restriction check: If the user's ACL has a restricted organization list\n * and the requested organization is not in that list \u2192 returns false\n * 4. Feature matching: User must have all required features (supports wildcards)\n *\n * @param userId - The ID of the user\n * @param required - Array of feature strings to check (e.g., ['users.view', 'users.edit'])\n * @param scope - The tenant and organization context for authorization\n * @returns true if the user has all required features and organization access, false otherwise\n *\n * @example\n * // Check if user can view and edit users\n * const canManageUsers = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['users.view', 'users.edit'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n *\n * @example\n * // Check with wildcard features\n * const canAccessEntities = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['entities.records.view'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n * // Returns true if user has 'entities.*', '*', or 'entities.records.view'\n */\n async userHasAllFeatures(userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) {\n const enabledIds = getEnabledModuleIds()\n if (!enabledIds.length) return true\n const enabledSet = new Set(enabledIds)\n return required.every((feature) => enabledSet.has(getOwningModuleId(feature)))\n }\n if (acl.organizations && scope.organizationId && !acl.organizations.includes(scope.organizationId) && !acl.organizations.includes('__all__')) return false\n return this.hasAllFeatures(required, filterGrantsByEnabledModules(acl.features))\n }\n\n /**\n * Returns the effective feature grant list for a user within a scope,\n * filtered to enabled modules only. Super admins receive `['*']` expanded\n * to per-module wildcards via `filterGrantsByEnabledModules` \u2014 consistent\n * with `userHasAllFeatures` which also enforces disabled-module boundaries\n * for super admins. Returns `[]` when the requested organization is outside\n * the user's visibility list, or when the user does not exist.\n */\n async getGrantedFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations &&\n scope.organizationId &&\n !acl.organizations.includes(scope.organizationId) &&\n !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n}\n"],
5
- "mappings": "AAEA,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,SAAS,SAAS,MAAM,gBAAgB;AACjD,SAAS,cAAc;AACvB,SAAS,0BAA0B;AACnC,SAAS,2BAA2B,mCAAmC;AACvE,SAAS,gBAAgB,oBAAoB,kBAAkB,4BAA4B;AAC3F,SAAS,8BAA8B,mBAAmB,2BAA2B;AAQrF,SAAS,UAAU,OAAkC;AACnD,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,SAAS;AACf,MAAI,OAAO,OAAO,iBAAiB,UAAW,QAAO;AACrD,MAAI,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,KAAK,CAAC,YAAY,OAAO,YAAY,QAAQ,EAAG,QAAO;AAC9G,MAAI,OAAO,kBAAkB,QAAQ,OAAO,kBAAkB,QAAW;AACvE,QAAI,CAAC,MAAM,QAAQ,OAAO,aAAa,EAAG,QAAO;AACjD,QAAI,OAAO,cAAc,KAAK,CAAC,QAAQ,OAAO,QAAQ,QAAQ,EAAG,QAAO;AAAA,EAC1E;AACA,SAAO;AACT;AAEO,MAAM,YAAY;AAAA,EAKvB,YAAoB,IAAmB,OAAuB;AAA1C;AAJpB,SAAQ,aAAqB,IAAI,KAAK;AACtC;AAAA,SAAQ,QAA8B;AACtC,SAAQ,wBAAwB,oBAAI,IAAqB;AAGvD,SAAK,QAAQ,SAAS;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,OAAe;AACzB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBQ,aAAa,UAAkB,SAA0B;AAC/D,WAAO,mBAAmB,UAAU,OAAO;AAAA,EAC7C;AAAA,EAEO,eAAe,UAAoB,SAA4B;AACpE,WAAO,qBAAqB,UAAU,OAAO;AAAA,EAC/C;AAAA,EAEQ,0BAA0B,KAAc,gBAAoD;AAClG,QAAI,CAAC,eAAgB,QAAO;AAC5B,UAAM,gBAAgB,MAAM,QAAQ,IAAI,iBAAiB,IAAI,IAAI,oBAAoB;AACrF,QAAI,CAAC,iBAAiB,CAAC,cAAc,UAAU,cAAc,SAAS,SAAS,EAAG,QAAO;AACzF,WAAO,cAAc,SAAS,cAAc;AAAA,EAC9C;AAAA,EAEQ,YAAY,QAAgB,OAA2E;AAC7G,WAAO,QAAQ,MAAM,IAAI,MAAM,YAAY,MAAM,IAAI,MAAM,kBAAkB,MAAM;AAAA,EACrF;AAAA,EAEQ,WAAW,QAAwB;AACzC,WAAO,aAAa,MAAM;AAAA,EAC5B;AAAA,EAEQ,aAAa,UAA0B;AAC7C,WAAO,eAAe,QAAQ;AAAA,EAChC;AAAA,EAEQ,mBAAmB,gBAAgC;AACzD,WAAO,YAAY,cAAc;AAAA,EACnC;AAAA,EAEA,MAAc,aAAa,UAA2C;AACpE,QAAI,CAAC,KAAK,MAAO,QAAO;AACxB,UAAM,SAAS,MAAM,KAAK,MAAM,IAAI,QAAQ;AAC5C,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,UAAU,MAAM,IAAI,SAAS;AAAA,EACtC;AAAA,EAEA,MAAc,SAAS,UAAkB,MAAe,QAAgB,OAAkF;AACxJ,QAAI,CAAC,KAAK,MAAO;AAEjB,UAAM,OAAO;AAAA,MACX,KAAK,WAAW,MAAM;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,MAAM,UAAU;AAClB,WAAK,KAAK,KAAK,aAAa,MAAM,QAAQ,CAAC;AAAA,IAC7C;AAEA,QAAI,MAAM,gBAAgB;AACxB,WAAK,KAAK,KAAK,mBAAmB,MAAM,cAAc,CAAC;AAAA,IACzD;AAEA,UAAM,KAAK,MAAM,IAAI,UAAU,MAAM;AAAA,MACnC,KAAK,KAAK;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,oBAAoB,QAA+B;AACvD,SAAK,sBAAsB,OAAO,MAAM;AAMxC,UAAM,KAAK,kBAAkB,CAAC,KAAK,WAAW,MAAM,GAAG,0BAA0B,MAAM,CAAC,CAAC;AAAA,EAC3F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,sBAAsB,UAAiC;AAC3D,SAAK,sBAAsB,MAAM;AAIjC,UAAM,KAAK,kBAAkB,CAAC,KAAK,aAAa,QAAQ,GAAG,4BAA4B,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;AAAA,EAC/G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,4BAA4B,gBAAuC;AACvE,UAAM,KAAK,kBAAkB,CAAC,KAAK,mBAAmB,cAAc,CAAC,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,qBAAoC;AACxC,SAAK,sBAAsB,MAAM;AACjC,UAAM,KAAK,kBAAkB,CAAC,UAAU,CAAC;AAAA,EAC3C;AAAA,EAEA,MAAc,kBAAkB,MAAgB,aAAmD;AACjG,QAAI,CAAC,KAAK,MAAO;AACjB,UAAM,WAAW,oBAAI,IAAmB;AACxC,UAAM,UAAU,sBAAsB;AACtC,aAAS,IAAI,WAAW,IAAI;AAC5B,aAAS,IAAI,IAAI;AACjB,QAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,iBAAW,QAAQ,aAAa;AAC9B,iBAAS,IAAI,QAAQ,IAAI;AAAA,MAC3B;AAAA,IACF;AACA,eAAW,OAAO,UAAU;AAC1B,UAAI,QAAQ,SAAS;AACnB,cAAM,KAAK,MAAM,aAAa,IAAI;AAAA,MACpC,OAAO;AACL,cAAM,mBAAmB,KAAK,YAAY;AACxC,gBAAM,KAAK,MAAO,aAAa,IAAI;AAAA,QACrC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,QAAkC;AACjE,QAAI,KAAK,sBAAsB,IAAI,MAAM,EAAG,QAAO,KAAK,sBAAsB,IAAI,MAAM;AACxF,UAAM,KAAK,KAAK,GAAG,KAAK;AACxB,UAAM,YAAY,MAAM,GAAG,QAAQ,SAAS,EAAE,MAAM,QAAe,cAAc,KAAK,CAAC;AACvF,QAAI,aAAc,UAAkB,cAAc;AAChD,WAAK,sBAAsB,IAAI,QAAQ,IAAI;AAC3C,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA,EAAE,MAAM,OAAc;AAAA,MACtB,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,MACrB,EAAE,UAAU,MAAM,gBAAgB,KAAK;AAAA,IACzC;AACA,UAAM,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AACjD,QAAI,CAAC,SAAS,QAAQ;AACpB,WAAK,sBAAsB,IAAI,QAAQ,KAAK;AAC5C,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MAAM,KAAK,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS;AACxD,YAAM,OAAO,KAAK;AAClB,aAAO,MAAM,KAAK,OAAO,KAAK,EAAE,IAAI;AAAA,IACtC,CAAC,EAAE,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC;AACzE,QAAI,CAAC,QAAQ,QAAQ;AACnB,WAAK,sBAAsB,IAAI,QAAQ,KAAK;AAC5C,aAAO;AAAA,IACT;AACA,UAAM,YAAY,MAAM,GAAG,QAAQ,SAAS,EAAE,cAAc,MAAM,MAAM,EAAE,KAAK,QAAe,EAAE,CAAQ;AACxG,UAAM,SAAS,CAAC,EAAE,aAAc,UAAkB;AAClD,SAAK,sBAAsB,IAAI,QAAQ,MAAM;AAC7C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,MAAM,QAAQ,QAAgB,OAI3B;AACD,UAAM,WAAW,KAAK,YAAY,QAAQ,KAAK;AAC/C,UAAM,SAAS,MAAM,KAAK,aAAa,QAAQ;AAC/C,QAAI,OAAQ,QAAO;AAEnB,QAAI,CAAC,OAAO,WAAW,UAAU,GAAG;AAClC,UAAI,MAAM,KAAK,mBAAmB,MAAM,GAAG;AACzC,cAAMA,UAAS,EAAE,cAAc,MAAM,UAAU,CAAC,GAAG,GAAG,eAAe,KAAK;AAC1E,cAAM,KAAK,SAAS,UAAUA,SAAQ,QAAQ,KAAK;AACnD,eAAOA;AAAA,MACT;AAAA,IACF;AAEA,QAAI,OAAO,WAAW,UAAU,GAAG;AACjC,YAAM,WAAW,OAAO,MAAM,WAAW,MAAM;AAC/C,YAAMC,MAAK,KAAK,GAAG,KAAK;AACxB,YAAM,MAAM,MAAMA,IAAG,QAAQ,QAAQ,EAAE,IAAI,UAAU,WAAW,KAAK,CAAC;AACtE,UAAI,CAAC,OAAQ,IAAI,aAAa,IAAI,UAAU,QAAQ,IAAI,KAAK,IAAI,GAAI;AACnE,cAAMD,UAAS,EAAE,cAAc,OAAO,UAAU,CAAC,GAAG,eAAe,KAAK;AACxE,cAAM,KAAK,SAAS,UAAUA,SAAQ,QAAQ,KAAK;AACnD,eAAOA;AAAA,MACT;AACA,YAAME,YAAW,MAAM,YAAY,IAAI,YAAY;AACnD,YAAMC,WAAU,MAAM,QAAQ,IAAI,SAAS,IAAI,IAAI,UAAU,OAAO,OAAO,IAAI,CAAC;AAChF,UAAIC,WAAU;AACd,YAAMC,YAAqB,CAAC;AAC5B,UAAIC,iBAAiC,IAAI,iBAAiB,CAAC,IAAI,cAAc,IAAI;AACjF,UAAIJ,aAAYC,SAAQ,QAAQ;AAC9B,cAAM,QAAQ,MAAMF,IAAG,KAAK,SAAS,EAAE,UAAAC,WAAU,MAAM,EAAE,KAAKC,SAAe,EAAE,CAAQ;AACvF,mBAAW,OAAO,OAAO;AACvB,UAAAC,WAAUA,YAAW,CAAC,CAAC,IAAI;AAC3B,cAAI,MAAM,QAAQ,IAAI,YAAY,GAAG;AACnC,uBAAW,KAAK,IAAI,aAAc,KAAI,CAACC,UAAS,SAAS,CAAC,EAAG,CAAAA,UAAS,KAAK,CAAC;AAAA,UAC9E;AACA,cAAIC,mBAAkB,MAAM;AAC1B,gBAAI,IAAI,qBAAqB,MAAM;AACjC,cAAAA,iBAAgB;AAAA,YAClB,WAAW,MAAM,QAAQ,IAAI,iBAAiB,KAAK,IAAI,kBAAkB,SAAS,SAAS,GAAG;AAC5F,cAAAA,iBAAgB;AAAA,YAClB,OAAO;AACL,cAAAA,iBAAgB,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAIA,kBAAiB,CAAC,GAAI,GAAG,IAAI,iBAAiB,CAAC,CAAC;AAAA,YAC1F;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,YAAMN,UAAS,EAAE,cAAcI,UAAS,UAAAC,WAAU,eAAAC,eAAc;AAChE,YAAM,KAAK,SAAS,UAAUN,SAAQ,QAAQ,KAAK;AACnD,aAAOA;AAAA,IACT;AAGA,UAAM,KAAK,KAAK,GAAG,KAAK;AACxB,UAAM,OAAO,MAAM,GAAG,QAAQ,MAAM,EAAE,IAAI,OAAO,CAAC;AAClD,QAAI,CAAC,MAAM;AACT,YAAMA,UAAS,EAAE,cAAc,OAAO,UAAU,CAAC,GAAG,eAAe,KAAK;AACxE,YAAM,KAAK,SAAS,UAAUA,SAAQ,QAAQ,KAAK;AACnD,aAAOA;AAAA,IACT;AACA,UAAM,WAAW,MAAM,YAAY,KAAK,YAAY;AACpD,UAAM,QAAQ,MAAM,kBAAkB,KAAK,kBAAkB;AAE7D,QAAI,CAAC,UAAU;AACb,YAAMA,UAAS,EAAE,cAAc,OAAO,UAAU,CAAC,GAAG,eAAe,KAAK;AACxE,YAAM,KAAK,SAAS,UAAUA,SAAQ,QAAQ,KAAK;AACnD,aAAOA;AAAA,IACT;AAGA,UAAM,OAAO,MAAM,GAAG,QAAQ,SAAS,EAAE,MAAM,QAAe,SAAS,CAAC;AACxE,QAAI,MAAM;AACR,YAAMA,UAAS;AAAA,QACb,cAAc,CAAC,CAAC,KAAK;AAAA,QACrB,UAAU,MAAM,QAAQ,KAAK,YAAY,IAAK,KAAK,eAA4B,CAAC;AAAA,QAChF,eAAe,MAAM,QAAQ,KAAK,iBAAiB,IAAK,KAAK,oBAAiC;AAAA,MAChG;AACA,YAAM,KAAK,SAAS,UAAUA,SAAQ,QAAQ,KAAK;AACnD,aAAOA;AAAA,IACT;AAGA,UAAM,QAAQ,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA,EAAE,MAAM,QAAe,MAAM,EAAE,SAAS,EAAE;AAAA,MAC1C,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,MACrB,EAAE,UAAU,gBAAgB,MAAM;AAAA,IACpC;AACA,UAAM,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AACjD,UAAM,UAAU,SAAS,IAAI,CAAC,MAAO,EAAE,MAAc,EAAE,EAAE,OAAO,OAAO;AACvE,QAAI,UAAU;AACd,UAAM,WAAqB,CAAC;AAC5B,QAAI,gBAAiC,CAAC;AACtC,QAAI,QAAQ,QAAQ;AAClB,YAAM,QAAQ,MAAM,GAAG,KAAK,SAAS,EAAE,UAAU,MAAM,EAAE,KAAK,QAAe,EAAE,GAAU,CAAC,CAAC;AAC3F,YAAM,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AACjD,iBAAW,KAAK,UAAU;AACxB,kBAAU,WAAW,CAAC,CAAC,EAAE;AACzB,YAAI,MAAM,QAAQ,EAAE,YAAY;AAAG,qBAAW,KAAK,EAAE,aAAc,KAAI,CAAC,SAAS,SAAS,CAAC,EAAG,UAAS,KAAK,CAAC;AAAA;AAC7G,YAAI,kBAAkB,MAAM;AAC1B,cAAI,EAAE,qBAAqB,KAAM,iBAAgB;AAAA,mBACxC,MAAM,QAAQ,EAAE,iBAAiB,KAAK,EAAE,kBAAkB,SAAS,SAAS,EAAG,iBAAgB;AAAA,cACnG,iBAAgB,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAI,iBAAiB,CAAC,GAAI,GAAG,EAAE,iBAAiB,CAAC,CAAC;AAAA,QAC7F;AAAA,MACF;AAAA,IACF;AACA,QAAI,iBAAiB,SAAS,CAAC,cAAc,SAAS,KAAK,KAAK,CAAC,cAAc,SAAS,SAAS,GAAG;AAAA,IAEpG;AACA,UAAM,SAAS,EAAE,cAAc,SAAS,UAAU,cAAc;AAChE,UAAM,KAAK,SAAS,UAAU,QAAQ,QAAQ,KAAK;AACnD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,iBACJ,UACA,SACA,MACkB;AAClB,QAAI,CAAC,YAAY,CAAC,QAAS,QAAO;AAElC,UAAM,aAAa,oBAAoB;AACvC,QAAI,WAAW,UAAU,CAAC,WAAW,SAAS,kBAAkB,OAAO,CAAC,EAAG,QAAO;AAElF,UAAM,KAAK,KAAK,GAAG,KAAK;AACxB,UAAM,WAAW,MAAM,GAAG,KAAK,SAAS,EAAE,UAAU,WAAW,KAAK,GAAU,CAAC,CAAC;AAChF,UAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC;AACnD,UAAM,iBAAiB,MAAM,kBAAkB;AAE/C,eAAW,OAAO,MAAM;AACtB,UAAI,CAAC,KAAK,0BAA0B,KAAK,cAAc,EAAG;AAC1D,UAAI,IAAI,aAAc,QAAO;AAC7B,YAAM,SAAS,MAAM,QAAQ,IAAI,YAAY,IAAI,IAAI,eAAe,CAAC;AACrE,UAAI,KAAK,eAAe,CAAC,OAAO,GAAG,6BAA6B,MAAM,CAAC,EAAG,QAAO;AAAA,IACnF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqCA,MAAM,mBAAmB,QAAgB,UAAoB,OAAqF;AAChJ,QAAI,CAAC,SAAS,OAAQ,QAAO;AAC7B,UAAM,MAAM,MAAM,KAAK,QAAQ,QAAQ,KAAK;AAC5C,QAAI,IAAI,cAAc;AACpB,YAAM,aAAa,oBAAoB;AACvC,UAAI,CAAC,WAAW,OAAQ,QAAO;AAC/B,YAAM,aAAa,IAAI,IAAI,UAAU;AACrC,aAAO,SAAS,MAAM,CAAC,YAAY,WAAW,IAAI,kBAAkB,OAAO,CAAC,CAAC;AAAA,IAC/E;AACA,QAAI,IAAI,iBAAiB,MAAM,kBAAkB,CAAC,IAAI,cAAc,SAAS,MAAM,cAAc,KAAK,CAAC,IAAI,cAAc,SAAS,SAAS,EAAG,QAAO;AACrJ,WAAO,KAAK,eAAe,UAAU,6BAA6B,IAAI,QAAQ,CAAC;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,mBACJ,QACA,OACmB;AACnB,UAAM,MAAM,MAAM,KAAK,QAAQ,QAAQ,KAAK;AAC5C,QAAI,IAAI,aAAc,QAAO,6BAA6B,CAAC,GAAG,CAAC;AAC/D,QACE,IAAI,iBACJ,MAAM,kBACN,CAAC,IAAI,cAAc,SAAS,MAAM,cAAc,KAChD,CAAC,IAAI,cAAc,SAAS,SAAS,GACrC;AACA,aAAO,CAAC;AAAA,IACV;AACA,WAAO,6BAA6B,IAAI,QAAQ;AAAA,EAClD;AACF;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getCurrentCacheTenant, runWithCacheTenant } from '@open-mercato/cache'\nimport { UserAcl, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { ApiKey } from '@open-mercato/core/modules/api_keys/data/entities'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n authorizeFeatures,\n resolveEffectiveFeatures,\n} from '@open-mercato/shared/security/featurePolicy'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\n\ninterface AclData {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nfunction isAclData(value: unknown): value is AclData {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<AclData>\n if (typeof record.isSuperAdmin !== 'boolean') return false\n if (!Array.isArray(record.features) || record.features.some((feature) => typeof feature !== 'string')) return false\n if (record.organizations !== null && record.organizations !== undefined) {\n if (!Array.isArray(record.organizations)) return false\n if (record.organizations.some((org) => typeof org !== 'string')) return false\n }\n return true\n}\n\nexport class RbacService {\n private cacheTtlMs: number = 5 * 60 * 1000 // 5 minutes default\n private cache: CacheStrategy | null = null\n private globalSuperAdminCache = new Map<string, boolean>()\n\n constructor(private em: EntityManager, cache?: CacheStrategy) {\n this.cache = cache || null\n }\n\n /**\n * Set cache TTL in milliseconds\n * @param ttlMs - Time to live in milliseconds\n */\n setCacheTtl(ttlMs: number) {\n this.cacheTtlMs = ttlMs\n }\n\n /** Compatibility wrapper for callers that already have both feature lists. */\n public hasAllFeatures(required: string[], granted: string[]): boolean {\n return authorizeFeatures(required, { grantedFeatures: granted })\n }\n\n private roleAclAllowsOrganization(acl: RoleAcl, organizationId: string | null | undefined): boolean {\n if (!organizationId) return true\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || !organizations.length || organizations.includes('__all__')) return true\n return organizations.includes(organizationId)\n }\n\n private getCacheKey(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string {\n return `rbac:${userId}:${scope.tenantId || 'null'}:${scope.organizationId || 'null'}`\n }\n\n private getUserTag(userId: string): string {\n return `rbac:user:${userId}`\n }\n\n private getTenantTag(tenantId: string): string {\n return `rbac:tenant:${tenantId}`\n }\n\n private getOrganizationTag(organizationId: string): string {\n return `rbac:org:${organizationId}`\n }\n\n private async getFromCache(cacheKey: string): Promise<AclData | null> {\n if (!this.cache) return null\n const cached = await this.cache.get(cacheKey)\n if (!cached) return null\n return isAclData(cached) ? cached : null\n }\n\n private async setCache(cacheKey: string, data: AclData, userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<void> {\n if (!this.cache) return\n\n const tags = [\n this.getUserTag(userId),\n 'rbac:all'\n ]\n\n if (scope.tenantId) {\n tags.push(this.getTenantTag(scope.tenantId))\n }\n\n if (scope.organizationId) {\n tags.push(this.getOrganizationTag(scope.organizationId))\n }\n\n await this.cache.set(cacheKey, data, {\n ttl: this.cacheTtlMs,\n tags\n })\n }\n\n /**\n * Invalidates cached ACL data for a specific user across all tenants and organizations.\n * Call this when a user's roles or user-specific ACL is modified.\n * \n * @param userId - The ID of the user whose cache should be invalidated\n */\n async invalidateUserCache(userId: string): Promise<void> {\n this.globalSuperAdminCache.delete(userId)\n // Also drop the directory OrganizationScope cache for this user. That scope's\n // accessible-org set is derived from this user's ACL/role grants, so any\n // permission change that invalidates the RBAC cache must invalidate the\n // resolved scope too. This is the missing `org-scope:user:*` caller required\n // before the cross-request scope TTL can be safely enabled (issue #2259).\n await this.deleteCacheByTags([this.getUserTag(userId), buildOrgScopeUserCacheTag(userId)])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific tenant.\n * Call this when a role's ACL is modified, since roles are tenant-scoped\n * and affect all users in that tenant who have that role.\n * \n * @param tenantId - The ID of the tenant whose cache should be invalidated\n */\n async invalidateTenantCache(tenantId: string): Promise<void> {\n this.globalSuperAdminCache.clear()\n // Role ACL changes invalidate every user in the tenant; the resolved\n // OrganizationScope for those users derives from the same grants, so drop\n // the tenant-tagged scope entries alongside the RBAC ones (issue #2259).\n await this.deleteCacheByTags([this.getTenantTag(tenantId), buildOrgScopeTenantCacheTag(tenantId)], [tenantId])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific organization.\n * Call this when organization-level permissions or visibility changes.\n * \n * @param organizationId - The ID of the organization whose cache should be invalidated\n */\n async invalidateOrganizationCache(organizationId: string): Promise<void> {\n await this.deleteCacheByTags([this.getOrganizationTag(organizationId)])\n }\n\n /**\n * Clears all cached ACL data.\n * Use this for bulk operations or system-wide ACL changes.\n */\n async invalidateAllCache(): Promise<void> {\n this.globalSuperAdminCache.clear()\n await this.deleteCacheByTags(['rbac:all'])\n }\n\n private async deleteCacheByTags(tags: string[], tenantHints?: Array<string | null>): Promise<void> {\n if (!this.cache) return\n const contexts = new Set<string | null>()\n const current = getCurrentCacheTenant()\n contexts.add(current ?? null)\n contexts.add(null)\n if (Array.isArray(tenantHints)) {\n for (const hint of tenantHints) {\n contexts.add(hint ?? null)\n }\n }\n for (const ctx of contexts) {\n if (ctx === current) {\n await this.cache.deleteByTags(tags)\n } else {\n await runWithCacheTenant(ctx, async () => {\n await this.cache!.deleteByTags(tags)\n })\n }\n }\n }\n\n private async isGlobalSuperAdmin(userId: string): Promise<boolean> {\n if (this.globalSuperAdminCache.has(userId)) return this.globalSuperAdminCache.get(userId)!\n const em = this.em.fork()\n const userSuper = await em.findOne(UserAcl, { user: userId as any, isSuperAdmin: true })\n if (userSuper && (userSuper as any).isSuperAdmin) {\n this.globalSuperAdminCache.set(userId, true)\n return true\n }\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const linkList = Array.isArray(links) ? links : []\n if (!linkList.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleIds = Array.from(new Set(linkList.map((link) => {\n const role = link.role as any\n return role?.id ? String(role.id) : null\n }).filter((id): id is string => typeof id === 'string' && id.length > 0)))\n if (!roleIds.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleSuper = await em.findOne(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds as any } } as any)\n const result = !!(roleSuper && (roleSuper as any).isSuperAdmin)\n this.globalSuperAdminCache.set(userId, result)\n return result\n }\n\n /**\n * Loads the Access Control List (ACL) for a user within a given scope.\n * \n * The ACL resolution follows this priority:\n * 1. Per-user ACL (UserAcl) - if exists, use it exclusively\n * 2. Aggregated role ACLs (RoleAcl) - combine permissions from all user's roles\n * \n * Results are cached for performance (default 5 minutes TTL).\n * Cache is automatically invalidated when ACL-related data changes.\n * \n * @param userId - The ID of the user\n * @param scope - The tenant and organization context for ACL evaluation\n * @returns An object containing:\n * - isSuperAdmin: If true, user has unrestricted access to all features\n * - features: Array of feature strings (may include wildcards like 'entities.*')\n * - organizations: Array of organization IDs user can access, or null for all organizations\n * \n * @example\n * const acl = await rbacService.loadAcl('user-123', { tenantId: 'tenant-1', organizationId: 'org-1' })\n * // Returns: { isSuperAdmin: false, features: ['users.view', 'entities.*'], organizations: ['org-1', 'org-2'] }\n */\n async loadAcl(userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<{\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n }> {\n const cacheKey = this.getCacheKey(userId, scope)\n const cached = await this.getFromCache(cacheKey)\n if (cached) return cached\n\n if (!userId.startsWith('api_key:')) {\n if (await this.isGlobalSuperAdmin(userId)) {\n const result = { isSuperAdmin: true, features: ['*'], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n }\n\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const em = this.em.fork()\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = key.organizationId ? [key.organizationId] : null\n if (tenantId && roleIds.length) {\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any)\n for (const acl of racls) {\n isSuper = isSuper || !!acl.isSuperAdmin\n if (Array.isArray(acl.featuresJson)) {\n for (const f of acl.featuresJson) if (!features.includes(f)) features.push(f)\n }\n if (organizations !== null) {\n if (acl.organizationsJson == null) {\n organizations = null\n } else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes('__all__')) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...(organizations || []), ...acl.organizationsJson]))\n }\n }\n }\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Use a forked EntityManager to avoid inheriting an aborted transaction from callers\n const em = this.em.fork()\n const user = await em.findOne(User, { id: userId })\n if (!user) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || user.tenantId || null\n const orgId = scope.organizationId || user.organizationId || null\n\n if (!tenantId) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Per-user ACL first\n const uacl = await em.findOne(UserAcl, { user: userId as any, tenantId })\n if (uacl) {\n const result = {\n isSuperAdmin: !!uacl.isSuperAdmin,\n features: Array.isArray(uacl.featuresJson) ? (uacl.featuresJson as string[]) : [],\n organizations: Array.isArray(uacl.organizationsJson) ? (uacl.organizationsJson as string[]) : null,\n }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Aggregate role ACLs\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any, role: { tenantId } } as any,\n { populate: ['role'] },\n { tenantId, organizationId: orgId },\n )\n const linkList = Array.isArray(links) ? links : []\n const roleIds = linkList.map((l) => (l.role as any)?.id).filter(Boolean)\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = []\n if (roleIds.length) {\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any, {})\n const roleAcls = Array.isArray(racls) ? racls : []\n for (const r of roleAcls) {\n isSuper = isSuper || !!r.isSuperAdmin\n if (Array.isArray(r.featuresJson)) for (const f of r.featuresJson) if (!features.includes(f)) features.push(f)\n if (organizations !== null) {\n if (r.organizationsJson == null) organizations = null\n else if (Array.isArray(r.organizationsJson) && r.organizationsJson.includes('__all__')) organizations = null\n else organizations = Array.from(new Set([...(organizations || []), ...r.organizationsJson]))\n }\n }\n }\n if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes('__all__')) {\n // Out-of-scope org; caller will enforce\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n /**\n * Checks whether any tenant role grants a feature.\n *\n * This supports non-user runtimes such as scheduler workers that execute with\n * tenant scope but without an authenticated user.\n */\n async tenantHasFeature(\n tenantId: string | null | undefined,\n feature: string,\n opts?: { organizationId?: string | null },\n ): Promise<boolean> {\n if (!tenantId || !feature) return false\n\n const em = this.em.fork()\n const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null } as any, {})\n const list = Array.isArray(roleAcls) ? roleAcls : []\n const organizationId = opts?.organizationId ?? null\n\n for (const acl of list) {\n if (!this.roleAclAllowsOrganization(acl, organizationId)) continue\n const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : []\n if (authorizeFeatures([feature], {\n grantedFeatures: grants,\n unrestricted: acl.isSuperAdmin,\n })) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if a user has all required features within a given scope.\n *\n * This is the primary authorization check method used throughout the application.\n * It combines feature checking with organization visibility validation.\n *\n * Authorization logic:\n * 1. No features required \u2192 always returns true\n * 2. User is super admin \u2192 always returns true\n * 3. Organization restriction check: If the user's ACL has a restricted organization list\n * and the requested organization is not in that list \u2192 returns false\n * 4. Feature matching: User must have all required features (supports wildcards)\n *\n * @param userId - The ID of the user\n * @param required - Array of feature strings to check (e.g., ['users.view', 'users.edit'])\n * @param scope - The tenant and organization context for authorization\n * @returns true if the user has all required features and organization access, false otherwise\n *\n * @example\n * // Check if user can view and edit users\n * const canManageUsers = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['users.view', 'users.edit'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n *\n * @example\n * // Check with wildcard features\n * const canAccessEntities = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['entities.records.view'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n * // Returns true if user has 'entities.*', '*', or 'entities.records.view'\n */\n async userHasAllFeatures(userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n /**\n * Returns the user's infrastructure grant list, filtered to enabled modules.\n * The result may contain wildcards; authoritative checks must still go through\n * `authorizeFeatures` or `userHasAllFeatures` so null overrides are enforced.\n */\n async getGrantedFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations &&\n scope.organizationId &&\n !acl.organizations.includes(scope.organizationId) &&\n !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /** Returns concrete active feature IDs for browser capability payloads. */\n async getEffectiveFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n if (!organizationAllowed) return []\n return resolveEffectiveFeatures(acl.isSuperAdmin ? ['*'] : acl.features)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["result", "em", "tenantId", "roleIds", "isSuper", "features", "organizations"]
7
7
  }
@@ -0,0 +1,85 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import {
6
+ getCurrentOpenMercatoEndpointOptions,
7
+ listOpenMercatoApiKeyOptions
8
+ } from "../../lib/openmercato-call-options.js";
9
+ const roleOptionSchema = z.object({
10
+ id: z.string(),
11
+ name: z.string().nullable()
12
+ });
13
+ const endpointOptionSchema = z.object({
14
+ id: z.string(),
15
+ path: z.string(),
16
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
17
+ label: z.string(),
18
+ summary: z.string().nullable(),
19
+ operationId: z.string().nullable()
20
+ });
21
+ const apiKeyOptionSchema = z.object({
22
+ id: z.string(),
23
+ name: z.string(),
24
+ keyPrefix: z.string(),
25
+ organizationId: z.string().nullable(),
26
+ organizationName: z.string().nullable(),
27
+ roles: z.array(roleOptionSchema)
28
+ });
29
+ const optionsResponseSchema = z.object({
30
+ endpoints: z.array(endpointOptionSchema),
31
+ apiKeys: z.array(apiKeyOptionSchema)
32
+ });
33
+ const errorResponseSchema = z.object({
34
+ error: z.string()
35
+ });
36
+ const metadata = {
37
+ GET: { requireAuth: true, requireFeatures: ["business_rules.manage", "api_keys.create"] }
38
+ };
39
+ async function GET(req) {
40
+ const auth = await getAuthFromRequest(req);
41
+ if (!auth) {
42
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
43
+ }
44
+ if (!auth.tenantId) {
45
+ return NextResponse.json({ error: "Tenant context required" }, { status: 400 });
46
+ }
47
+ const container = await createRequestContainer();
48
+ const em = container.resolve("em");
49
+ const [endpoints, apiKeys] = await Promise.all([
50
+ getCurrentOpenMercatoEndpointOptions(),
51
+ listOpenMercatoApiKeyOptions(em, {
52
+ tenantId: auth.tenantId,
53
+ organizationId: auth.orgId ?? null
54
+ })
55
+ ]);
56
+ return NextResponse.json({ endpoints, apiKeys });
57
+ }
58
+ const openApi = {
59
+ tag: "Business Rules",
60
+ summary: "List OpenMercato call action options",
61
+ methods: {
62
+ GET: {
63
+ summary: "List OpenMercato call action options",
64
+ description: "Returns executable Open Mercato API endpoint options and safe API key profile metadata for business-rule actions.",
65
+ responses: [
66
+ {
67
+ status: 200,
68
+ description: "OpenMercato call options",
69
+ schema: optionsResponseSchema
70
+ }
71
+ ],
72
+ errors: [
73
+ { status: 400, description: "Tenant context missing", schema: errorResponseSchema },
74
+ { status: 401, description: "Unauthorized", schema: errorResponseSchema },
75
+ { status: 403, description: "Missing required features", schema: errorResponseSchema }
76
+ ]
77
+ }
78
+ }
79
+ };
80
+ export {
81
+ GET,
82
+ metadata,
83
+ openApi
84
+ };
85
+ //# sourceMappingURL=route.js.map