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

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 (241) hide show
  1. package/dist/generated/entities.ids.generated.js +0 -1
  2. package/dist/generated/entities.ids.generated.js.map +2 -2
  3. package/dist/generated/entity-fields-registry.js +0 -2
  4. package/dist/generated/entity-fields-registry.js.map +2 -2
  5. package/dist/modules/api_keys/setup.js +11 -0
  6. package/dist/modules/api_keys/setup.js.map +7 -0
  7. package/dist/modules/attachments/components/AttachmentLibrary.js +1 -1
  8. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  9. package/dist/modules/attachments/lib/assignmentDetails.js +31 -17
  10. package/dist/modules/attachments/lib/assignmentDetails.js.map +2 -2
  11. package/dist/modules/attachments/lib/partitions.js +3 -3
  12. package/dist/modules/attachments/lib/partitions.js.map +2 -2
  13. package/dist/modules/attachments/setup.js +11 -0
  14. package/dist/modules/attachments/setup.js.map +7 -0
  15. package/dist/modules/audit_logs/setup.js +12 -0
  16. package/dist/modules/audit_logs/setup.js.map +7 -0
  17. package/dist/modules/auth/lib/setup-app.js +29 -159
  18. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  19. package/dist/modules/auth/setup.js +11 -0
  20. package/dist/modules/auth/setup.js.map +7 -0
  21. package/dist/modules/business_rules/data/validators.js +0 -34
  22. package/dist/modules/business_rules/data/validators.js.map +2 -2
  23. package/dist/modules/business_rules/index.js +1 -21
  24. package/dist/modules/business_rules/index.js.map +2 -2
  25. package/dist/modules/business_rules/lib/rule-engine.js +1 -182
  26. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  27. package/dist/modules/business_rules/setup.js +11 -0
  28. package/dist/modules/business_rules/setup.js.map +7 -0
  29. package/dist/modules/catalog/setup.js +22 -0
  30. package/dist/modules/catalog/setup.js.map +7 -0
  31. package/dist/modules/configs/lib/upgrade-actions.js +65 -15
  32. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  33. package/dist/modules/configs/setup.js +16 -0
  34. package/dist/modules/configs/setup.js.map +7 -0
  35. package/dist/modules/currencies/setup.js +16 -0
  36. package/dist/modules/currencies/setup.js.map +7 -0
  37. package/dist/modules/customers/setup.js +36 -0
  38. package/dist/modules/customers/setup.js.map +7 -0
  39. package/dist/modules/dashboards/setup.js +12 -0
  40. package/dist/modules/dashboards/setup.js.map +7 -0
  41. package/dist/modules/dictionaries/setup.js +12 -0
  42. package/dist/modules/dictionaries/setup.js.map +7 -0
  43. package/dist/modules/directory/setup.js +12 -0
  44. package/dist/modules/directory/setup.js.map +7 -0
  45. package/dist/modules/entities/setup.js +11 -0
  46. package/dist/modules/entities/setup.js.map +7 -0
  47. package/dist/modules/feature_toggles/setup.js +11 -0
  48. package/dist/modules/feature_toggles/setup.js.map +7 -0
  49. package/dist/modules/perspectives/setup.js +12 -0
  50. package/dist/modules/perspectives/setup.js.map +7 -0
  51. package/dist/modules/planner/setup.js +21 -0
  52. package/dist/modules/planner/setup.js.map +7 -0
  53. package/dist/modules/query_index/setup.js +11 -0
  54. package/dist/modules/query_index/setup.js.map +7 -0
  55. package/dist/modules/resources/setup.js +21 -0
  56. package/dist/modules/resources/setup.js.map +7 -0
  57. package/dist/modules/sales/acl.js +0 -1
  58. package/dist/modules/sales/acl.js.map +2 -2
  59. package/dist/modules/sales/backend/sales/documents/[id]/page.js +0 -12
  60. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  61. package/dist/modules/sales/commands/documents.js +0 -62
  62. package/dist/modules/sales/commands/documents.js.map +2 -2
  63. package/dist/modules/sales/lib/dictionaries.js +0 -3
  64. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  65. package/dist/modules/sales/setup.js +99 -0
  66. package/dist/modules/sales/setup.js.map +7 -0
  67. package/dist/modules/staff/setup.js +27 -0
  68. package/dist/modules/staff/setup.js.map +7 -0
  69. package/dist/modules/workflows/acl.js +0 -2
  70. package/dist/modules/workflows/acl.js.map +2 -2
  71. package/dist/modules/workflows/api/instances/route.js +6 -18
  72. package/dist/modules/workflows/api/instances/route.js.map +2 -2
  73. package/dist/modules/workflows/api/tasks/route.js +1 -6
  74. package/dist/modules/workflows/api/tasks/route.js.map +2 -2
  75. package/dist/modules/workflows/backend/definitions/[id]/page.js +1 -9
  76. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  77. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
  78. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
  79. package/dist/modules/workflows/backend/definitions/create/page.js +15 -24
  80. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  81. package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
  82. package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
  83. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +132 -150
  84. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  85. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
  86. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
  87. package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
  88. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  89. package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
  90. package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
  91. package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
  92. package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
  93. package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
  94. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  95. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
  96. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
  97. package/dist/modules/workflows/backend/tasks/page.js +6 -5
  98. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  99. package/dist/modules/workflows/cli.js +3 -81
  100. package/dist/modules/workflows/cli.js.map +3 -3
  101. package/dist/modules/workflows/data/entities.js +1 -64
  102. package/dist/modules/workflows/data/entities.js.map +2 -2
  103. package/dist/modules/workflows/data/validators.js +0 -115
  104. package/dist/modules/workflows/data/validators.js.map +2 -2
  105. package/dist/modules/workflows/examples/checkout-demo-definition.json +5 -1
  106. package/dist/modules/workflows/lib/activity-executor.js +13 -75
  107. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  108. package/dist/modules/workflows/lib/graph-utils.js +2 -71
  109. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  110. package/dist/modules/workflows/lib/seeds.js +7 -36
  111. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  112. package/dist/modules/workflows/lib/start-validator.js +23 -33
  113. package/dist/modules/workflows/lib/start-validator.js.map +2 -2
  114. package/dist/modules/workflows/lib/transition-handler.js +45 -157
  115. package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
  116. package/dist/modules/workflows/migrations/Migration20251207131955.js +76 -72
  117. package/dist/modules/workflows/migrations/Migration20251207131955.js.map +2 -2
  118. package/dist/modules/workflows/setup.js +16 -0
  119. package/dist/modules/workflows/setup.js.map +7 -0
  120. package/generated/entities.ids.generated.ts +0 -1
  121. package/generated/entity-fields-registry.ts +0 -2
  122. package/package.json +2 -2
  123. package/src/__tests__/module-decoupling.test.ts +356 -0
  124. package/src/modules/api_keys/setup.ts +9 -0
  125. package/src/modules/attachments/components/AttachmentLibrary.tsx +2 -2
  126. package/src/modules/attachments/lib/assignmentDetails.ts +32 -16
  127. package/src/modules/attachments/lib/partitions.ts +3 -3
  128. package/src/modules/attachments/setup.ts +9 -0
  129. package/src/modules/audit_logs/setup.ts +10 -0
  130. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +30 -0
  131. package/src/modules/auth/lib/setup-app.ts +40 -177
  132. package/src/modules/auth/setup.ts +9 -0
  133. package/src/modules/business_rules/data/validators.ts +0 -40
  134. package/src/modules/business_rules/index.ts +0 -25
  135. package/src/modules/business_rules/lib/rule-engine.ts +1 -281
  136. package/src/modules/business_rules/setup.ts +9 -0
  137. package/src/modules/catalog/setup.ts +22 -0
  138. package/src/modules/configs/lib/upgrade-actions.ts +78 -17
  139. package/src/modules/configs/setup.ts +14 -0
  140. package/src/modules/currencies/setup.ts +15 -0
  141. package/src/modules/customers/setup.ts +36 -0
  142. package/src/modules/dashboards/setup.ts +10 -0
  143. package/src/modules/dictionaries/setup.ts +10 -0
  144. package/src/modules/directory/setup.ts +10 -0
  145. package/src/modules/entities/setup.ts +9 -0
  146. package/src/modules/feature_toggles/setup.ts +9 -0
  147. package/src/modules/perspectives/setup.ts +10 -0
  148. package/src/modules/planner/setup.ts +21 -0
  149. package/src/modules/query_index/setup.ts +9 -0
  150. package/src/modules/resources/setup.ts +21 -0
  151. package/src/modules/sales/acl.ts +0 -1
  152. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +0 -16
  153. package/src/modules/sales/commands/documents.ts +1 -74
  154. package/src/modules/sales/lib/dictionaries.ts +0 -3
  155. package/src/modules/sales/setup.ts +108 -0
  156. package/src/modules/staff/setup.ts +27 -0
  157. package/src/modules/workflows/acl.ts +0 -2
  158. package/src/modules/workflows/api/__tests__/instances.route.test.ts +2 -5
  159. package/src/modules/workflows/api/instances/route.ts +7 -21
  160. package/src/modules/workflows/api/tasks/route.ts +1 -7
  161. package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
  162. package/src/modules/workflows/backend/definitions/[id]/page.tsx +0 -9
  163. package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
  164. package/src/modules/workflows/backend/definitions/create/page.tsx +0 -9
  165. package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
  166. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +3 -21
  167. package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
  168. package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
  169. package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
  170. package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
  171. package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
  172. package/src/modules/workflows/backend/tasks/page.tsx +6 -5
  173. package/src/modules/workflows/cli.ts +0 -111
  174. package/src/modules/workflows/data/entities.ts +0 -124
  175. package/src/modules/workflows/data/validators.ts +0 -138
  176. package/src/modules/workflows/examples/checkout-demo-definition.json +5 -1
  177. package/src/modules/workflows/i18n/en.json +0 -71
  178. package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +36 -43
  179. package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +90 -170
  180. package/src/modules/workflows/lib/activity-executor.ts +16 -129
  181. package/src/modules/workflows/lib/graph-utils.ts +2 -117
  182. package/src/modules/workflows/lib/seeds.ts +12 -50
  183. package/src/modules/workflows/lib/start-validator.ts +28 -38
  184. package/src/modules/workflows/lib/transition-handler.ts +55 -208
  185. package/src/modules/workflows/migrations/Migration20251207131955.ts +77 -143
  186. package/src/modules/workflows/setup.ts +15 -0
  187. package/dist/generated/entities/workflow_event_trigger/index.js +0 -33
  188. package/dist/generated/entities/workflow_event_trigger/index.js.map +0 -7
  189. package/dist/modules/auth/events.js +0 -30
  190. package/dist/modules/auth/events.js.map +0 -7
  191. package/dist/modules/business_rules/api/execute/[ruleId]/route.js +0 -145
  192. package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +0 -7
  193. package/dist/modules/catalog/events.js +0 -34
  194. package/dist/modules/catalog/events.js.map +0 -7
  195. package/dist/modules/customers/events.js +0 -49
  196. package/dist/modules/customers/events.js.map +0 -7
  197. package/dist/modules/directory/events.js +0 -23
  198. package/dist/modules/directory/events.js.map +0 -7
  199. package/dist/modules/sales/events.js +0 -63
  200. package/dist/modules/sales/events.js.map +0 -7
  201. package/dist/modules/sales/lib/frontend/documentDataEvents.js +0 -25
  202. package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +0 -7
  203. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +0 -481
  204. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +0 -7
  205. package/dist/modules/workflows/components/EventTriggersEditor.js +0 -553
  206. package/dist/modules/workflows/components/EventTriggersEditor.js.map +0 -7
  207. package/dist/modules/workflows/events.js +0 -38
  208. package/dist/modules/workflows/events.js.map +0 -7
  209. package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
  210. package/dist/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  211. package/dist/modules/workflows/lib/event-trigger-service.js +0 -308
  212. package/dist/modules/workflows/lib/event-trigger-service.js.map +0 -7
  213. package/dist/modules/workflows/migrations/Migration20260123143500.js +0 -36
  214. package/dist/modules/workflows/migrations/Migration20260123143500.js.map +0 -7
  215. package/dist/modules/workflows/subscribers/event-trigger.js +0 -78
  216. package/dist/modules/workflows/subscribers/event-trigger.js.map +0 -7
  217. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +0 -323
  218. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +0 -7
  219. package/dist/modules/workflows/widgets/injection/order-approval/widget.js +0 -17
  220. package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +0 -7
  221. package/dist/modules/workflows/widgets/injection-table.js +0 -19
  222. package/dist/modules/workflows/widgets/injection-table.js.map +0 -7
  223. package/generated/entities/workflow_event_trigger/index.ts +0 -15
  224. package/src/modules/auth/events.ts +0 -39
  225. package/src/modules/business_rules/api/execute/[ruleId]/route.ts +0 -163
  226. package/src/modules/catalog/events.ts +0 -45
  227. package/src/modules/customers/events.ts +0 -63
  228. package/src/modules/directory/events.ts +0 -31
  229. package/src/modules/sales/events.ts +0 -82
  230. package/src/modules/sales/lib/frontend/documentDataEvents.ts +0 -28
  231. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +0 -581
  232. package/src/modules/workflows/components/EventTriggersEditor.tsx +0 -664
  233. package/src/modules/workflows/events.ts +0 -49
  234. package/src/modules/workflows/examples/order-approval-definition.json +0 -257
  235. package/src/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  236. package/src/modules/workflows/lib/event-trigger-service.ts +0 -557
  237. package/src/modules/workflows/migrations/Migration20260123143500.ts +0 -38
  238. package/src/modules/workflows/subscribers/event-trigger.ts +0 -109
  239. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +0 -446
  240. package/src/modules/workflows/widgets/injection/order-approval/widget.ts +0 -16
  241. package/src/modules/workflows/widgets/injection-table.ts +0 -21
@@ -0,0 +1,16 @@
1
+ import { seedExampleWorkflows } from "./lib/seeds.js";
2
+ const setup = {
3
+ seedDefaults: async (ctx) => {
4
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId };
5
+ await seedExampleWorkflows(ctx.em, scope);
6
+ },
7
+ defaultRoleFeatures: {
8
+ admin: ["workflows.*"]
9
+ }
10
+ };
11
+ var setup_default = setup;
12
+ export {
13
+ setup_default as default,
14
+ setup
15
+ };
16
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/workflows/setup.ts"],
4
+ "sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { seedExampleWorkflows } from './lib/seeds'\n\nexport const setup: ModuleSetupConfig = {\n seedDefaults: async (ctx) => {\n const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n await seedExampleWorkflows(ctx.em, scope)\n },\n\n defaultRoleFeatures: {\n admin: ['workflows.*'],\n },\n}\n\nexport default setup\n"],
5
+ "mappings": "AACA,SAAS,4BAA4B;AAE9B,MAAM,QAA2B;AAAA,EACtC,cAAc,OAAO,QAAQ;AAC3B,UAAM,QAAQ,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AAC3E,UAAM,qBAAqB,IAAI,IAAI,KAAK;AAAA,EAC1C;AAAA,EAEA,qBAAqB;AAAA,IACnB,OAAO,CAAC,aAAa;AAAA,EACvB;AACF;AAEA,IAAO,gBAAQ;",
6
+ "names": []
7
+ }
@@ -154,7 +154,6 @@ export const E = {
154
154
  "user_task": "workflows:user_task",
155
155
  "workflow_definition": "workflows:workflow_definition",
156
156
  "workflow_event": "workflows:workflow_event",
157
- "workflow_event_trigger": "workflows:workflow_event_trigger",
158
157
  "workflow_instance": "workflows:workflow_instance"
159
158
  },
160
159
  "currencies": {
@@ -116,7 +116,6 @@ import * as user_sidebar_preference from './entities/user_sidebar_preference/ind
116
116
  import * as user_task from './entities/user_task/index'
117
117
  import * as workflow_definition from './entities/workflow_definition/index'
118
118
  import * as workflow_event from './entities/workflow_event/index'
119
- import * as workflow_event_trigger from './entities/workflow_event_trigger/index'
120
119
  import * as workflow_instance from './entities/workflow_instance/index'
121
120
 
122
121
  export const entityFieldsRegistry: Record<string, Record<string, string>> = {
@@ -236,7 +235,6 @@ export const entityFieldsRegistry: Record<string, Record<string, string>> = {
236
235
  user_task,
237
236
  workflow_definition,
238
237
  workflow_event,
239
- workflow_event_trigger,
240
238
  workflow_instance
241
239
  }
242
240
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.4.2-canary-ed15f2e753",
3
+ "version": "0.4.2-canary-f075c3eb92",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -207,7 +207,7 @@
207
207
  }
208
208
  },
209
209
  "dependencies": {
210
- "@open-mercato/shared": "0.4.2-canary-ed15f2e753",
210
+ "@open-mercato/shared": "0.4.2-canary-f075c3eb92",
211
211
  "@xyflow/react": "^12.6.0",
212
212
  "date-fns": "^4.1.0",
213
213
  "date-fns-tz": "^3.2.0"
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Module Decoupling Tests
3
+ *
4
+ * Verifies that the application remains functional when optional modules
5
+ * (catalog, sales, api_keys) are disabled — removed from the generated
6
+ * module registry and entity IDs.
7
+ */
8
+
9
+ // Build a reduced entity IDs registry excluding catalog, sales, api_keys
10
+ const reducedE = {
11
+ dashboards: {
12
+ dashboard_layout: 'dashboards:dashboard_layout',
13
+ dashboard_role_widgets: 'dashboards:dashboard_role_widgets',
14
+ dashboard_user_widgets: 'dashboards:dashboard_user_widgets',
15
+ },
16
+ auth: {
17
+ password_reset: 'auth:password_reset',
18
+ role: 'auth:role',
19
+ role_acl: 'auth:role_acl',
20
+ role_sidebar_preference: 'auth:role_sidebar_preference',
21
+ session: 'auth:session',
22
+ user: 'auth:user',
23
+ user_acl: 'auth:user_acl',
24
+ user_role: 'auth:user_role',
25
+ user_sidebar_preference: 'auth:user_sidebar_preference',
26
+ },
27
+ directory: {
28
+ organization: 'directory:organization',
29
+ tenant: 'directory:tenant',
30
+ },
31
+ customers: {
32
+ customer_activity: 'customers:customer_activity',
33
+ customer_address: 'customers:customer_address',
34
+ customer_comment: 'customers:customer_comment',
35
+ customer_company_profile: 'customers:customer_company_profile',
36
+ customer_deal: 'customers:customer_deal',
37
+ customer_deal_company_link: 'customers:customer_deal_company_link',
38
+ customer_deal_person_link: 'customers:customer_deal_person_link',
39
+ customer_dictionary_entry: 'customers:customer_dictionary_entry',
40
+ customer_entity: 'customers:customer_entity',
41
+ customer_person_profile: 'customers:customer_person_profile',
42
+ customer_settings: 'customers:customer_settings',
43
+ customer_tag: 'customers:customer_tag',
44
+ customer_tag_assignment: 'customers:customer_tag_assignment',
45
+ customer_todo_link: 'customers:customer_todo_link',
46
+ },
47
+ entities: {
48
+ custom_entity: 'entities:custom_entity',
49
+ custom_entity_storage: 'entities:custom_entity_storage',
50
+ custom_field_def: 'entities:custom_field_def',
51
+ custom_field_entity_config: 'entities:custom_field_entity_config',
52
+ custom_field_value: 'entities:custom_field_value',
53
+ encryption_map: 'entities:encryption_map',
54
+ },
55
+ attachments: {
56
+ attachment: 'attachments:attachment',
57
+ attachment_partition: 'attachments:attachment_partition',
58
+ },
59
+ } as const
60
+
61
+ const reducedM = {
62
+ dashboards: 'dashboards',
63
+ auth: 'auth',
64
+ directory: 'directory',
65
+ customers: 'customers',
66
+ entities: 'entities',
67
+ attachments: 'attachments',
68
+ } as const
69
+
70
+ // Mock generated entity IDs to exclude catalog, sales, api_keys
71
+ jest.mock('#generated/entities.ids.generated', () => ({
72
+ E: reducedE,
73
+ M: reducedM,
74
+ }))
75
+
76
+ // Mock cache dependency used by upgrade-actions
77
+ jest.mock('@open-mercato/cache', () => ({
78
+ runWithCacheTenant: jest.fn((_: unknown, fn: () => unknown) => fn()),
79
+ }))
80
+ jest.mock('@open-mercato/shared/lib/crud/cache-stats', () => ({
81
+ collectCrudCacheStats: jest.fn().mockResolvedValue({ segments: [] }),
82
+ purgeCrudCacheSegment: jest.fn(),
83
+ }))
84
+ jest.mock('@open-mercato/shared/lib/crud/cache', () => ({
85
+ isCrudCacheEnabled: jest.fn().mockReturnValue(false),
86
+ resolveCrudCache: jest.fn(),
87
+ }))
88
+
89
+ import { registerEntityIds, getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'
90
+ import { registerModules } from '@open-mercato/shared/lib/modules/registry'
91
+ import type { Module } from '@open-mercato/shared/modules/registry'
92
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
93
+
94
+ // Build module list that mirrors enabled modules without catalog/sales/api_keys
95
+ function buildReducedModules(): Module[] {
96
+ const moduleSetups: Record<string, ModuleSetupConfig> = {
97
+ dashboards: {
98
+ defaultRoleFeatures: {
99
+ admin: ['dashboards.*', 'dashboards.admin.assign-widgets'],
100
+ employee: ['dashboards.view', 'dashboards.configure'],
101
+ },
102
+ },
103
+ auth: {
104
+ defaultRoleFeatures: { admin: ['auth.*'] },
105
+ },
106
+ directory: {
107
+ defaultRoleFeatures: {
108
+ superadmin: ['directory.tenants.*'],
109
+ admin: ['directory.organizations.view', 'directory.organizations.manage'],
110
+ },
111
+ },
112
+ customers: {
113
+ defaultRoleFeatures: {
114
+ admin: [
115
+ 'customers.*',
116
+ 'customers.people.view',
117
+ 'customers.people.manage',
118
+ 'customers.companies.view',
119
+ 'customers.companies.manage',
120
+ 'customers.deals.view',
121
+ 'customers.deals.manage',
122
+ ],
123
+ employee: [
124
+ 'customers.*',
125
+ 'customers.people.view',
126
+ 'customers.people.manage',
127
+ 'customers.companies.view',
128
+ 'customers.companies.manage',
129
+ ],
130
+ },
131
+ },
132
+ entities: {
133
+ defaultRoleFeatures: { admin: ['entities.*'] },
134
+ },
135
+ attachments: {
136
+ defaultRoleFeatures: { admin: ['attachments.*', 'attachments.view', 'attachments.manage'] },
137
+ },
138
+ audit_logs: {
139
+ defaultRoleFeatures: { admin: ['audit_logs.*'], employee: ['audit_logs.undo_self'] },
140
+ },
141
+ dictionaries: {
142
+ defaultRoleFeatures: { admin: ['dictionaries.view', 'dictionaries.manage'], employee: ['dictionaries.view'] },
143
+ },
144
+ perspectives: {
145
+ defaultRoleFeatures: { admin: ['perspectives.use', 'perspectives.role_defaults'], employee: ['perspectives.use'] },
146
+ },
147
+ configs: {
148
+ defaultRoleFeatures: { admin: ['configs.system_status.view', 'configs.cache.view', 'configs.cache.manage', 'configs.manage'] },
149
+ },
150
+ query_index: {
151
+ defaultRoleFeatures: { admin: ['query_index.*'] },
152
+ },
153
+ feature_toggles: {
154
+ defaultRoleFeatures: { admin: ['feature_toggles.*'] },
155
+ },
156
+ business_rules: {
157
+ defaultRoleFeatures: { admin: ['business_rules.*'] },
158
+ },
159
+ workflows: {
160
+ defaultRoleFeatures: { admin: ['workflows.*'] },
161
+ },
162
+ currencies: {
163
+ defaultRoleFeatures: { admin: ['currencies.*'] },
164
+ },
165
+ staff: {
166
+ defaultRoleFeatures: {
167
+ admin: ['staff.*', 'staff.leave_requests.manage'],
168
+ employee: [
169
+ 'staff.leave_requests.send',
170
+ 'staff.my_availability.view',
171
+ 'staff.my_availability.manage',
172
+ 'staff.my_leave_requests.view',
173
+ 'staff.my_leave_requests.send',
174
+ ],
175
+ },
176
+ },
177
+ resources: {
178
+ defaultRoleFeatures: { admin: ['resources.*'] },
179
+ },
180
+ planner: {
181
+ defaultRoleFeatures: { admin: ['planner.*'], employee: ['planner.view'] },
182
+ },
183
+ search: {
184
+ defaultRoleFeatures: { admin: ['search.*', 'vector.*'], employee: ['vector.*'] },
185
+ },
186
+ }
187
+
188
+ return Object.entries(moduleSetups).map(([id, setup]) => ({
189
+ id,
190
+ setup,
191
+ }))
192
+ }
193
+
194
+ const reducedModules = buildReducedModules()
195
+
196
+ beforeAll(() => {
197
+ registerEntityIds(reducedE as any)
198
+ registerModules(reducedModules)
199
+ })
200
+
201
+ describe('Module Decoupling', () => {
202
+ describe('1. Entity IDs registry excludes disabled modules', () => {
203
+ it('getEntityIds() has no catalog, sales, or api_keys keys', () => {
204
+ const entityIds = getEntityIds()
205
+ expect(entityIds).not.toHaveProperty('catalog')
206
+ expect(entityIds).not.toHaveProperty('sales')
207
+ expect(entityIds).not.toHaveProperty('api_keys')
208
+ })
209
+
210
+ it('still contains core modules', () => {
211
+ const entityIds = getEntityIds()
212
+ expect(entityIds).toHaveProperty('auth')
213
+ expect(entityIds).toHaveProperty('attachments')
214
+ expect(entityIds).toHaveProperty('customers')
215
+ expect(entityIds).toHaveProperty('dashboards')
216
+ expect(entityIds).toHaveProperty('directory')
217
+ expect(entityIds).toHaveProperty('entities')
218
+ })
219
+ })
220
+
221
+ describe('2. attachments/partitions.ts — resolveDefaultPartitionCode', () => {
222
+ it('returns privateAttachments for null, undefined, arbitrary strings, and catalog entity IDs', async () => {
223
+ const { resolveDefaultPartitionCode } = await import(
224
+ '@open-mercato/core/modules/attachments/lib/partitions'
225
+ )
226
+
227
+ expect(resolveDefaultPartitionCode(null)).toBe('privateAttachments')
228
+ expect(resolveDefaultPartitionCode(undefined)).toBe('privateAttachments')
229
+ expect(resolveDefaultPartitionCode('some-entity')).toBe('privateAttachments')
230
+ // When catalog is disabled, the literal string also falls through
231
+ expect(resolveDefaultPartitionCode('catalog:catalog_product')).toBe('privateAttachments')
232
+ })
233
+ })
234
+
235
+ describe('3. attachments/assignmentDetails.ts — resolveAssignmentEnrichments', () => {
236
+ it('does not crash with empty assignments and null queryEngine', async () => {
237
+ const { resolveAssignmentEnrichments } = await import(
238
+ '@open-mercato/core/modules/attachments/lib/assignmentDetails'
239
+ )
240
+
241
+ const result = await resolveAssignmentEnrichments([], {
242
+ queryEngine: null,
243
+ tenantId: 'tenant-1',
244
+ organizationId: 'org-1',
245
+ })
246
+ expect(result).toBeInstanceOf(Map)
247
+ expect(result.size).toBe(0)
248
+ })
249
+
250
+ it('does not crash with assignments referencing catalog entity IDs', async () => {
251
+ const { resolveAssignmentEnrichments } = await import(
252
+ '@open-mercato/core/modules/attachments/lib/assignmentDetails'
253
+ )
254
+
255
+ const result = await resolveAssignmentEnrichments(
256
+ [{ type: 'catalog:catalog_product', id: 'some-uuid' }],
257
+ {
258
+ queryEngine: null,
259
+ tenantId: 'tenant-1',
260
+ organizationId: 'org-1',
261
+ },
262
+ )
263
+ expect(result).toBeInstanceOf(Map)
264
+ expect(result.size).toBe(0)
265
+ })
266
+ })
267
+
268
+ describe('4. Role feature merging', () => {
269
+ it('admin features contain enabled module features', () => {
270
+ const adminFeatures: string[] = []
271
+ for (const mod of reducedModules) {
272
+ const roleFeatures = mod.setup?.defaultRoleFeatures
273
+ if (roleFeatures?.admin) adminFeatures.push(...roleFeatures.admin)
274
+ }
275
+
276
+ expect(adminFeatures).toContain('auth.*')
277
+ expect(adminFeatures).toContain('attachments.*')
278
+ expect(adminFeatures).toContain('dashboards.*')
279
+ expect(adminFeatures).toContain('customers.*')
280
+ expect(adminFeatures).toContain('entities.*')
281
+ expect(adminFeatures).toContain('query_index.*')
282
+ expect(adminFeatures).toContain('configs.manage')
283
+ expect(adminFeatures).toContain('directory.organizations.manage')
284
+ })
285
+
286
+ it('admin features do NOT contain disabled module features', () => {
287
+ const adminFeatures: string[] = []
288
+ for (const mod of reducedModules) {
289
+ const roleFeatures = mod.setup?.defaultRoleFeatures
290
+ if (roleFeatures?.admin) adminFeatures.push(...roleFeatures.admin)
291
+ }
292
+
293
+ expect(adminFeatures).not.toContain('catalog.*')
294
+ expect(adminFeatures).not.toContain('sales.*')
295
+ expect(adminFeatures).not.toContain('api_keys.*')
296
+ })
297
+
298
+ it('employee features similarly exclude disabled module features', () => {
299
+ const employeeFeatures: string[] = []
300
+ for (const mod of reducedModules) {
301
+ const roleFeatures = mod.setup?.defaultRoleFeatures
302
+ if (roleFeatures?.employee) employeeFeatures.push(...roleFeatures.employee)
303
+ }
304
+
305
+ expect(employeeFeatures).not.toContain('catalog.*')
306
+ expect(employeeFeatures).not.toContain('sales.*')
307
+ expect(employeeFeatures).not.toContain('api_keys.*')
308
+
309
+ // Enabled modules' employee features are present
310
+ expect(employeeFeatures).toContain('customers.*')
311
+ expect(employeeFeatures).toContain('dashboards.view')
312
+ expect(employeeFeatures).toContain('audit_logs.undo_self')
313
+ expect(employeeFeatures).toContain('vector.*')
314
+ })
315
+
316
+ it('superadmin features come from enabled modules only', () => {
317
+ const superadminFeatures: string[] = []
318
+ for (const mod of reducedModules) {
319
+ const roleFeatures = mod.setup?.defaultRoleFeatures
320
+ if (roleFeatures?.superadmin) superadminFeatures.push(...roleFeatures.superadmin)
321
+ }
322
+
323
+ expect(superadminFeatures).toContain('directory.tenants.*')
324
+ expect(superadminFeatures).not.toContain('catalog.*')
325
+ expect(superadminFeatures).not.toContain('sales.*')
326
+ })
327
+ })
328
+
329
+ describe('5. configs/upgrade-actions.ts loads without crashing', () => {
330
+ it('imports and exposes upgradeActions array and compareVersions function', async () => {
331
+ const mod = await import(
332
+ '@open-mercato/core/modules/configs/lib/upgrade-actions'
333
+ )
334
+
335
+ expect(Array.isArray(mod.upgradeActions)).toBe(true)
336
+ expect(typeof mod.compareVersions).toBe('function')
337
+ })
338
+
339
+ it('upgradeActions array is defined and non-empty', async () => {
340
+ const mod = await import(
341
+ '@open-mercato/core/modules/configs/lib/upgrade-actions'
342
+ )
343
+
344
+ expect(mod.upgradeActions.length).toBeGreaterThan(0)
345
+ })
346
+
347
+ it('actionsUpToVersion returns actions without crashing', async () => {
348
+ const mod = await import(
349
+ '@open-mercato/core/modules/configs/lib/upgrade-actions'
350
+ )
351
+
352
+ const actions = mod.actionsUpToVersion('99.99.99')
353
+ expect(Array.isArray(actions)).toBe(true)
354
+ })
355
+ })
356
+ })
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['api_keys.*'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -893,8 +893,8 @@ export function AttachmentLibrary() {
893
893
  {assignments.map((assignment) => {
894
894
  const label = assignment.label?.trim() || assignment.id
895
895
  const hideType =
896
- assignment.type === E.catalog.catalog_product ||
897
- assignment.type === E.catalog.catalog_product_variant
896
+ assignment.type === (E as any).catalog?.catalog_product ||
897
+ assignment.type === (E as any).catalog?.catalog_product_variant
898
898
  const content = hideType ? label : `${assignment.type}: ${label}`
899
899
  return assignment.href ? (
900
900
  <a
@@ -15,12 +15,16 @@ let _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null
15
15
  function getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {
16
16
  if (_entityLinkSpecsCache) return _entityLinkSpecsCache
17
17
  const E = getEntityIds() as any
18
- _entityLinkSpecsCache = {
19
- [E.catalog.catalog_product]: {
18
+ const specs: Record<string, AssignmentLinkSpec> = {}
19
+
20
+ if (E.catalog?.catalog_product) {
21
+ specs[E.catalog.catalog_product] = {
20
22
  labelFields: ['title', 'sku', 'handle'],
21
23
  buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),
22
- },
23
- [E.catalog.catalog_product_variant]: {
24
+ }
25
+ }
26
+ if (E.catalog?.catalog_product_variant) {
27
+ specs[E.catalog.catalog_product_variant] = {
24
28
  labelFields: ['name', 'sku'],
25
29
  extraFields: ['product_id'],
26
30
  buildHref: (record) => {
@@ -28,8 +32,10 @@ function getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {
28
32
  if (!productId) return null
29
33
  return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`
30
34
  },
31
- },
32
- [E.customers.customer_entity]: {
35
+ }
36
+ }
37
+ if (E.customers?.customer_entity) {
38
+ specs[E.customers.customer_entity] = {
33
39
  labelFields: ['display_name'],
34
40
  extraFields: ['kind'],
35
41
  buildHref: (record) => {
@@ -38,32 +44,42 @@ function getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {
38
44
  if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)
39
45
  return null
40
46
  },
41
- },
42
- [E.customers.customer_person_profile]: {
47
+ }
48
+ }
49
+ if (E.customers?.customer_person_profile) {
50
+ specs[E.customers.customer_person_profile] = {
43
51
  labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],
44
52
  extraFields: ['entity_id', 'first_name', 'last_name'],
45
53
  buildHref: (record) => {
46
54
  const entityId = readRecordValue(record, 'entity_id')
47
55
  return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null
48
56
  },
49
- },
50
- [E.customers.customer_company_profile]: {
57
+ }
58
+ }
59
+ if (E.customers?.customer_company_profile) {
60
+ specs[E.customers.customer_company_profile] = {
51
61
  labelFields: ['brand_name', 'display_name', 'legal_name'],
52
62
  extraFields: ['entity_id'],
53
63
  buildHref: (record) => {
54
64
  const entityId = readRecordValue(record, 'entity_id')
55
65
  return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null
56
66
  },
57
- },
58
- [E.customers.customer_deal]: {
67
+ }
68
+ }
69
+ if (E.customers?.customer_deal) {
70
+ specs[E.customers.customer_deal] = {
59
71
  labelFields: ['title'],
60
72
  buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),
61
- },
62
- [E.sales.sales_channel]: {
73
+ }
74
+ }
75
+ if (E.sales?.sales_channel) {
76
+ specs[E.sales.sales_channel] = {
63
77
  labelFields: ['name', 'title'],
64
78
  buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),
65
- },
79
+ }
66
80
  }
81
+
82
+ _entityLinkSpecsCache = specs
67
83
  return _entityLinkSpecsCache
68
84
  }
69
85
 
@@ -161,7 +177,7 @@ function isUuid(value: string | null | undefined): boolean {
161
177
 
162
178
  function filterIdsForEntity(entityId: string, ids: string[]): string[] {
163
179
  const E = getEntityIds() as any
164
- if (entityId === E.catalog.catalog_product_variant || entityId === E.catalog.catalog_product) {
180
+ if (entityId === E.catalog?.catalog_product_variant || entityId === E.catalog?.catalog_product) {
165
181
  return ids.filter((id) => isUuid(id))
166
182
  }
167
183
  return ids
@@ -26,9 +26,9 @@ export const DEFAULT_ATTACHMENT_PARTITIONS: AttachmentPartitionSeed[] = [
26
26
  },
27
27
  ]
28
28
 
29
- const PRODUCT_MEDIA_ENTITY_IDS = new Set<string>([
30
- E.catalog.catalog_product,
31
- ])
29
+ const PRODUCT_MEDIA_ENTITY_IDS = new Set<string>(
30
+ [(E as any).catalog?.catalog_product].filter(Boolean) as string[]
31
+ )
32
32
 
33
33
  const FALLBACK_PARTITION = 'privateAttachments'
34
34
 
@@ -0,0 +1,9 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['attachments.*', 'attachments.view', 'attachments.manage'],
6
+ },
7
+ }
8
+
9
+ export default setup
@@ -0,0 +1,10 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ admin: ['audit_logs.*'],
6
+ employee: ['audit_logs.undo_self'],
7
+ },
8
+ }
9
+
10
+ export default setup
@@ -1,6 +1,36 @@
1
1
  /** @jest-environment node */
2
+ import { registerModules } from '@open-mercato/shared/lib/modules/registry'
3
+ import type { Module } from '@open-mercato/shared/modules/registry'
2
4
  import cli from '@open-mercato/core/modules/auth/cli'
3
5
 
6
+ // Register modules so that ensureDefaultRoleAcls can read defaultRoleFeatures
7
+ const testModules: Module[] = [
8
+ { id: 'auth', setup: { defaultRoleFeatures: { admin: ['auth.*'] } } },
9
+ { id: 'entities', setup: { defaultRoleFeatures: { admin: ['entities.*'] } } },
10
+ { id: 'attachments', setup: { defaultRoleFeatures: { admin: ['attachments.*', 'attachments.view', 'attachments.manage'] } } },
11
+ { id: 'query_index', setup: { defaultRoleFeatures: { admin: ['query_index.*'] } } },
12
+ { id: 'configs', setup: { defaultRoleFeatures: { admin: ['configs.system_status.view', 'configs.cache.view', 'configs.cache.manage', 'configs.manage'] } } },
13
+ { id: 'directory', setup: { defaultRoleFeatures: { superadmin: ['directory.tenants.*'], admin: ['directory.organizations.view', 'directory.organizations.manage'] } } },
14
+ { id: 'customers', setup: { defaultRoleFeatures: { admin: ['customers.*', 'customers.people.view', 'customers.people.manage', 'customers.companies.view', 'customers.companies.manage', 'customers.deals.view', 'customers.deals.manage'], employee: ['customers.*', 'customers.people.view', 'customers.people.manage', 'customers.companies.view', 'customers.companies.manage'] } } },
15
+ { id: 'catalog', setup: { defaultRoleFeatures: { admin: ['catalog.*', 'catalog.variants.manage', 'catalog.pricing.manage'], employee: ['catalog.*', 'catalog.variants.manage', 'catalog.pricing.manage'] } } },
16
+ { id: 'sales', setup: { defaultRoleFeatures: { admin: ['sales.*'], employee: ['sales.*'] } } },
17
+ { id: 'dictionaries', setup: { defaultRoleFeatures: { admin: ['dictionaries.view', 'dictionaries.manage'], employee: ['dictionaries.view'] } } },
18
+ { id: 'audit_logs', setup: { defaultRoleFeatures: { admin: ['audit_logs.*'], employee: ['audit_logs.undo_self'] } } },
19
+ { id: 'dashboards', setup: { defaultRoleFeatures: { admin: ['dashboards.*', 'dashboards.admin.assign-widgets'], employee: ['dashboards.view', 'dashboards.configure'] } } },
20
+ { id: 'api_keys', setup: { defaultRoleFeatures: { admin: ['api_keys.*'] } } },
21
+ { id: 'perspectives', setup: { defaultRoleFeatures: { admin: ['perspectives.use', 'perspectives.role_defaults'], employee: ['perspectives.use'] } } },
22
+ { id: 'feature_toggles', setup: { defaultRoleFeatures: { admin: ['feature_toggles.*'] } } },
23
+ { id: 'business_rules', setup: { defaultRoleFeatures: { admin: ['business_rules.*'] } } },
24
+ { id: 'workflows', setup: { defaultRoleFeatures: { admin: ['workflows.*'] } } },
25
+ { id: 'search', setup: { defaultRoleFeatures: { admin: ['search.*', 'vector.*'], employee: ['vector.*'] } } },
26
+ { id: 'currencies', setup: { defaultRoleFeatures: { admin: ['currencies.*'] } } },
27
+ { id: 'planner', setup: { defaultRoleFeatures: { admin: ['planner.*'], employee: ['planner.view'] } } },
28
+ { id: 'resources', setup: { defaultRoleFeatures: { admin: ['resources.*'] } } },
29
+ { id: 'staff', setup: { defaultRoleFeatures: { admin: ['staff.*', 'staff.leave_requests.manage'], employee: ['staff.leave_requests.send', 'staff.my_availability.view', 'staff.my_availability.manage', 'staff.my_leave_requests.view', 'staff.my_leave_requests.send'] } } },
30
+ { id: 'example', setup: { defaultRoleFeatures: { admin: ['example.*'], employee: ['example.*', 'example.widgets.*'] } } },
31
+ ]
32
+ registerModules(testModules)
33
+
4
34
  // Mock DI container and EM
5
35
  const persistAndFlush = jest.fn()
6
36
  const findOne = jest.fn()