@open-mercato/cli 0.8.1-develop.7296.1.2111d779db → 0.9.0

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 (217) hide show
  1. package/.turbo/turbo-build.log +8 -2
  2. package/AGENTS.md +2 -0
  3. package/dist/agentic/guides/module-facts.json +7612 -848
  4. package/dist/agentic/guides/module-facts.v2.json +7612 -848
  5. package/dist/agentic/guides/modules/agent_orchestrator/active-extension-bindings.md +1 -1
  6. package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
  7. package/dist/agentic/guides/modules/ai_assistant/encryption.md +13 -0
  8. package/dist/agentic/guides/modules/ai_assistant/exact-override-targets.md +3 -0
  9. package/dist/agentic/guides/modules/ai_assistant/index.md +4 -3
  10. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  11. package/dist/agentic/guides/modules/api_keys/domain-commands.md +12 -0
  12. package/dist/agentic/guides/modules/api_keys/index.md +3 -2
  13. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  14. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  15. package/dist/agentic/guides/modules/auth/index.md +1 -1
  16. package/dist/agentic/guides/modules/availability/acl-features.md +13 -0
  17. package/dist/agentic/guides/modules/availability/backend-pages.md +14 -0
  18. package/dist/agentic/guides/modules/availability/di-registrations-rich.md +11 -0
  19. package/dist/agentic/guides/modules/availability/domain-commands.md +13 -0
  20. package/dist/agentic/guides/modules/availability/entities.md +11 -0
  21. package/dist/agentic/guides/modules/availability/events.md +13 -0
  22. package/dist/agentic/guides/modules/availability/exact-override-targets.md +19 -0
  23. package/dist/agentic/guides/modules/availability/host-extension-points.md +10 -0
  24. package/dist/agentic/guides/modules/availability/index.md +22 -0
  25. package/dist/agentic/guides/modules/availability/owned-contract-module-metadata.md +11 -0
  26. package/dist/agentic/guides/modules/availability/setup.md +11 -0
  27. package/dist/agentic/guides/modules/availability/umes-hosts.md +14 -0
  28. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  29. package/dist/agentic/guides/modules/catalog/active-extension-bindings.md +1 -1
  30. package/dist/agentic/guides/modules/catalog/di-registrations-rich.md +1 -0
  31. package/dist/agentic/guides/modules/catalog/exact-override-targets.md +3 -0
  32. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  33. package/dist/agentic/guides/modules/catalog/workers.md +2 -0
  34. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  35. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  36. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  37. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  38. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  39. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  40. package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
  41. package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
  42. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  43. package/dist/agentic/guides/modules/communication_channels/acl-features.md +2 -1
  44. package/dist/agentic/guides/modules/communication_channels/contribution-resolutions.md +1 -0
  45. package/dist/agentic/guides/modules/communication_channels/di-registrations-rich.md +11 -10
  46. package/dist/agentic/guides/modules/communication_channels/domain-commands.md +1 -0
  47. package/dist/agentic/guides/modules/communication_channels/events.md +2 -1
  48. package/dist/agentic/guides/modules/communication_channels/exact-override-targets.md +12 -10
  49. package/dist/agentic/guides/modules/communication_channels/incoming-installed-contributions.md +1 -0
  50. package/dist/agentic/guides/modules/communication_channels/index.md +2 -2
  51. package/dist/agentic/guides/modules/communication_channels/umes-contributions.md +1 -0
  52. package/dist/agentic/guides/modules/communication_channels/umes-hosts.md +1 -0
  53. package/dist/agentic/guides/modules/configs/index.md +1 -1
  54. package/dist/agentic/guides/modules/content/index.md +1 -1
  55. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  56. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  57. package/dist/agentic/guides/modules/customer_groups/acl-features.md +16 -0
  58. package/dist/agentic/guides/modules/customer_groups/active-extension-bindings.md +13 -0
  59. package/dist/agentic/guides/modules/customer_groups/backend-pages.md +14 -0
  60. package/dist/agentic/guides/modules/customer_groups/cli-commands.md +11 -0
  61. package/dist/agentic/guides/modules/customer_groups/contribution-resolutions.md +13 -0
  62. package/dist/agentic/guides/modules/customer_groups/di-registrations-rich.md +13 -0
  63. package/dist/agentic/guides/modules/customer_groups/di-service-tokens.md +11 -0
  64. package/dist/agentic/guides/modules/customer_groups/domain-commands.md +11 -0
  65. package/dist/agentic/guides/modules/customer_groups/entities.md +13 -0
  66. package/dist/agentic/guides/modules/customer_groups/events.md +17 -0
  67. package/dist/agentic/guides/modules/customer_groups/exact-override-targets.md +27 -0
  68. package/dist/agentic/guides/modules/customer_groups/index.md +26 -0
  69. package/dist/agentic/guides/modules/customer_groups/owned-contract-module-metadata.md +11 -0
  70. package/dist/agentic/guides/modules/customer_groups/setup.md +11 -0
  71. package/dist/agentic/guides/modules/customer_groups/umes-contributions.md +13 -0
  72. package/dist/agentic/guides/modules/customer_groups/umes-hosts.md +21 -0
  73. package/dist/agentic/guides/modules/customers/acl-features.md +2 -1
  74. package/dist/agentic/guides/modules/customers/active-extension-bindings.md +8 -7
  75. package/dist/agentic/guides/modules/customers/contribution-resolutions.md +1 -0
  76. package/dist/agentic/guides/modules/customers/domain-commands.md +1 -0
  77. package/dist/agentic/guides/modules/customers/entities.md +1 -0
  78. package/dist/agentic/guides/modules/customers/events.md +2 -1
  79. package/dist/agentic/guides/modules/customers/exact-override-targets.md +2 -0
  80. package/dist/agentic/guides/modules/customers/index.md +3 -3
  81. package/dist/agentic/guides/modules/customers/umes-contributions.md +1 -0
  82. package/dist/agentic/guides/modules/customers/umes-hosts.md +3 -0
  83. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  84. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  85. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  86. package/dist/agentic/guides/modules/devices/index.md +1 -1
  87. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  88. package/dist/agentic/guides/modules/directory/active-extension-bindings.md +1 -1
  89. package/dist/agentic/guides/modules/directory/index.md +1 -1
  90. package/dist/agentic/guides/modules/documents/index.md +1 -1
  91. package/dist/agentic/guides/modules/entities/active-extension-bindings.md +1 -1
  92. package/dist/agentic/guides/modules/entities/index.md +1 -1
  93. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  94. package/dist/agentic/guides/modules/events/index.md +1 -1
  95. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  96. package/dist/agentic/guides/modules/forms/acl-features.md +16 -0
  97. package/dist/agentic/guides/modules/forms/active-extension-bindings.md +14 -0
  98. package/dist/agentic/guides/modules/forms/backend-pages.md +17 -0
  99. package/dist/agentic/guides/modules/forms/contribution-resolutions.md +21 -0
  100. package/dist/agentic/guides/modules/forms/di-registrations-rich.md +27 -0
  101. package/dist/agentic/guides/modules/forms/di-service-tokens.md +19 -0
  102. package/dist/agentic/guides/modules/forms/domain-commands.md +30 -0
  103. package/dist/agentic/guides/modules/forms/encryption.md +11 -0
  104. package/dist/agentic/guides/modules/forms/entities.md +21 -0
  105. package/dist/agentic/guides/modules/forms/events.md +28 -0
  106. package/dist/agentic/guides/modules/forms/exact-override-targets.md +59 -0
  107. package/dist/agentic/guides/modules/forms/frontend-pages.md +16 -0
  108. package/dist/agentic/guides/modules/forms/index.md +28 -0
  109. package/dist/agentic/guides/modules/forms/owned-contract-module-metadata.md +11 -0
  110. package/dist/agentic/guides/modules/forms/setup.md +11 -0
  111. package/dist/agentic/guides/modules/forms/umes-contributions.md +21 -0
  112. package/dist/agentic/guides/modules/forms/umes-hosts.md +43 -0
  113. package/dist/agentic/guides/modules/forms/workers.md +12 -0
  114. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  115. package/dist/agentic/guides/modules/generators/index.md +1 -1
  116. package/dist/agentic/guides/modules/inbox_ops/active-extension-bindings.md +1 -1
  117. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  118. package/dist/agentic/guides/modules/integrations/di-registrations-rich.md +8 -8
  119. package/dist/agentic/guides/modules/integrations/di-service-tokens.md +4 -4
  120. package/dist/agentic/guides/modules/integrations/exact-override-targets.md +8 -8
  121. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  122. package/dist/agentic/guides/modules/messages/index.md +1 -1
  123. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  124. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  125. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  126. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  127. package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
  128. package/dist/agentic/guides/modules/planner/active-extension-bindings.md +1 -1
  129. package/dist/agentic/guides/modules/planner/index.md +1 -1
  130. package/dist/agentic/guides/modules/portal/index.md +1 -1
  131. package/dist/agentic/guides/modules/progress/index.md +1 -1
  132. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  133. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  134. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  135. package/dist/agentic/guides/modules/resources/active-extension-bindings.md +1 -1
  136. package/dist/agentic/guides/modules/resources/index.md +1 -1
  137. package/dist/agentic/guides/modules/sales/active-extension-bindings.md +1 -1
  138. package/dist/agentic/guides/modules/sales/exact-override-targets.md +4 -4
  139. package/dist/agentic/guides/modules/sales/index.md +1 -1
  140. package/dist/agentic/guides/modules/sales/setup.md +1 -1
  141. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  142. package/dist/agentic/guides/modules/search/index.md +1 -1
  143. package/dist/agentic/guides/modules/security/index.md +1 -1
  144. package/dist/agentic/guides/modules/seeds/index.md +1 -1
  145. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  146. package/dist/agentic/guides/modules/sso/index.md +1 -1
  147. package/dist/agentic/guides/modules/staff/active-extension-bindings.md +1 -1
  148. package/dist/agentic/guides/modules/staff/index.md +1 -1
  149. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  150. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  151. package/dist/agentic/guides/modules/sync_excel/active-extension-bindings.md +11 -0
  152. package/dist/agentic/guides/modules/sync_excel/index.md +3 -2
  153. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  154. package/dist/agentic/guides/modules/telemetry/index.md +1 -1
  155. package/dist/agentic/guides/modules/tillio/index.md +1 -1
  156. package/dist/agentic/guides/modules/translations/index.md +1 -1
  157. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  158. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  159. package/dist/agentic/guides/modules/wms/active-extension-bindings.md +1 -1
  160. package/dist/agentic/guides/modules/wms/contribution-resolutions.md +3 -0
  161. package/dist/agentic/guides/modules/wms/di-registrations-rich.md +8 -8
  162. package/dist/agentic/guides/modules/wms/exact-override-targets.md +11 -8
  163. package/dist/agentic/guides/modules/wms/index.md +3 -3
  164. package/dist/agentic/guides/modules/wms/umes-contributions.md +3 -0
  165. package/dist/agentic/guides/modules/workflows/active-extension-bindings.md +3 -3
  166. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  167. package/dist/agentic/guides/reference-module-facts.json +1 -1
  168. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +73 -1
  169. package/dist/agentic/guides/upstream/manifest.json +2 -2
  170. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.8.0-to-0.9.0/SKILL.md +112 -0
  171. package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +1 -1
  172. package/dist/agentic/shared/ai/skills/tiers.json +2 -1
  173. package/dist/bin.js +2 -2
  174. package/dist/bin.js.map +2 -2
  175. package/dist/lib/db/commands.js +84 -5
  176. package/dist/lib/db/commands.js.map +2 -2
  177. package/dist/lib/db/encryption-backfill-check.js +112 -0
  178. package/dist/lib/db/encryption-backfill-check.js.map +7 -0
  179. package/dist/lib/db/migration-reindex.js +2 -1
  180. package/dist/lib/db/migration-reindex.js.map +2 -2
  181. package/dist/lib/events-single-delivery.js.map +2 -2
  182. package/dist/lib/flush-before-exit.js +19 -0
  183. package/dist/lib/flush-before-exit.js.map +7 -0
  184. package/dist/lib/generate-watch-structure.js +113 -19
  185. package/dist/lib/generate-watch-structure.js.map +3 -3
  186. package/dist/lib/generators/module-registry.js +4 -2
  187. package/dist/lib/generators/module-registry.js.map +2 -2
  188. package/dist/lib/generators/web-research-adapters.js +32 -11
  189. package/dist/lib/generators/web-research-adapters.js.map +2 -2
  190. package/dist/lib/telemetry-init.js +69 -11
  191. package/dist/lib/telemetry-init.js.map +3 -3
  192. package/dist/lib/testing/integration.js +29 -2
  193. package/dist/lib/testing/integration.js.map +2 -2
  194. package/package.json +8 -8
  195. package/src/bin.ts +4 -4
  196. package/src/lib/__tests__/flush-before-exit.test.ts +32 -0
  197. package/src/lib/__tests__/generate-watch-structure.test.ts +261 -3
  198. package/src/lib/__tests__/telemetry-init.test.ts +89 -0
  199. package/src/lib/db/__tests__/commands.test.ts +43 -0
  200. package/src/lib/db/__tests__/dynamic-import-specifier.test.ts +36 -0
  201. package/src/lib/db/__tests__/encryption-backfill-check.test.ts +146 -0
  202. package/src/lib/db/__tests__/migration-reindex.test.ts +48 -3
  203. package/src/lib/db/commands.ts +113 -10
  204. package/src/lib/db/encryption-backfill-check.ts +163 -0
  205. package/src/lib/db/migration-reindex.ts +2 -1
  206. package/src/lib/events-single-delivery.ts +5 -2
  207. package/src/lib/flush-before-exit.ts +39 -0
  208. package/src/lib/generate-watch-structure.ts +134 -19
  209. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +14 -3
  210. package/src/lib/generators/__tests__/module-package-sources.test.ts +2 -2
  211. package/src/lib/generators/__tests__/registry-variant-parity.test.ts +16 -0
  212. package/src/lib/generators/__tests__/web-research-adapters.test.ts +141 -0
  213. package/src/lib/generators/module-registry.ts +2 -0
  214. package/src/lib/generators/web-research-adapters.ts +41 -20
  215. package/src/lib/telemetry-init.ts +68 -11
  216. package/src/lib/testing/__tests__/integration.test.ts +26 -0
  217. package/src/lib/testing/integration.ts +32 -2
@@ -6,13 +6,13 @@
6
6
 
7
7
  | Token | Kind | Lifetime | Injection | Provider | Source |
8
8
  |---|---|---|---|---|---|
9
- | InventoryBalance | value | — | — | — | [di.ts:21](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L21) |
10
- | InventoryLot | value | — | — | — | [di.ts:20](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L20) |
11
- | InventoryMovement | value | — | — | — | [di.ts:23](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L23) |
12
- | InventoryReservation | value | — | — | — | [di.ts:22](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L22) |
13
- | ProductInventoryProfile | value | — | — | — | [di.ts:19](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L19) |
14
- | Warehouse | value | — | — | — | [di.ts:16](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L16) |
15
- | WarehouseLocation | value | — | — | — | [di.ts:18](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L18) |
16
- | WarehouseZone | value | — | — | — | [di.ts:17](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L17) |
9
+ | InventoryBalance | value | — | — | — | [di.ts:23](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L23) |
10
+ | InventoryLot | value | — | — | — | [di.ts:22](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L22) |
11
+ | InventoryMovement | value | — | — | — | [di.ts:25](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L25) |
12
+ | InventoryReservation | value | — | — | — | [di.ts:24](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L24) |
13
+ | ProductInventoryProfile | value | — | — | — | [di.ts:21](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L21) |
14
+ | Warehouse | value | — | — | — | [di.ts:18](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L18) |
15
+ | WarehouseLocation | value | — | — | — | [di.ts:20](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L20) |
16
+ | WarehouseZone | value | — | — | — | [di.ts:19](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L19) |
17
17
 
18
18
  <!-- end module facts section: wms/di-registrations-rich -->
@@ -17,17 +17,20 @@
17
17
  | acl | `overrides.acl.features["wms.receive_inventory"]` | disable-replace | aclFeatures:wms.receive_inventory | [acl.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/acl.ts) |
18
18
  | acl | `overrides.acl.features["wms.view"]` | disable-replace | aclFeatures:wms.view | [acl.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/acl.ts) |
19
19
  | cli | `overrides.cli["verify-balances"]` | disable-replace | cliCommands:verify-balances | [cli.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/cli.ts) |
20
- | di | `overrides.di["InventoryBalance"]` | disable-replace | ownedContracts.di-registration:InventoryBalance | [di.ts:21](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L21) |
21
- | di | `overrides.di["InventoryLot"]` | disable-replace | ownedContracts.di-registration:InventoryLot | [di.ts:20](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L20) |
22
- | di | `overrides.di["InventoryMovement"]` | disable-replace | ownedContracts.di-registration:InventoryMovement | [di.ts:23](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L23) |
23
- | di | `overrides.di["InventoryReservation"]` | disable-replace | ownedContracts.di-registration:InventoryReservation | [di.ts:22](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L22) |
24
- | di | `overrides.di["ProductInventoryProfile"]` | disable-replace | ownedContracts.di-registration:ProductInventoryProfile | [di.ts:19](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L19) |
25
- | di | `overrides.di["Warehouse"]` | disable-replace | ownedContracts.di-registration:Warehouse | [di.ts:16](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L16) |
26
- | di | `overrides.di["WarehouseLocation"]` | disable-replace | ownedContracts.di-registration:WarehouseLocation | [di.ts:18](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L18) |
27
- | di | `overrides.di["WarehouseZone"]` | disable-replace | ownedContracts.di-registration:WarehouseZone | [di.ts:17](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L17) |
20
+ | di | `overrides.di["InventoryBalance"]` | disable-replace | ownedContracts.di-registration:InventoryBalance | [di.ts:23](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L23) |
21
+ | di | `overrides.di["InventoryLot"]` | disable-replace | ownedContracts.di-registration:InventoryLot | [di.ts:22](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L22) |
22
+ | di | `overrides.di["InventoryMovement"]` | disable-replace | ownedContracts.di-registration:InventoryMovement | [di.ts:25](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L25) |
23
+ | di | `overrides.di["InventoryReservation"]` | disable-replace | ownedContracts.di-registration:InventoryReservation | [di.ts:24](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L24) |
24
+ | di | `overrides.di["ProductInventoryProfile"]` | disable-replace | ownedContracts.di-registration:ProductInventoryProfile | [di.ts:21](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L21) |
25
+ | di | `overrides.di["Warehouse"]` | disable-replace | ownedContracts.di-registration:Warehouse | [di.ts:18](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L18) |
26
+ | di | `overrides.di["WarehouseLocation"]` | disable-replace | ownedContracts.di-registration:WarehouseLocation | [di.ts:20](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L20) |
27
+ | di | `overrides.di["WarehouseZone"]` | disable-replace | ownedContracts.di-registration:WarehouseZone | [di.ts:19](../../../../node_modules/@open-mercato/core/src/modules/wms/di.ts#L19) |
28
28
  | enrichers | `overrides.enrichers["wms.catalog-product-inventory"]` | disable-replace | extensionSurfaces.contributions:wms.catalog-product-inventory | [data/enrichers.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/data/enrichers.ts) |
29
29
  | enrichers | `overrides.enrichers["wms.catalog-variant-inventory"]` | disable-replace | extensionSurfaces.contributions:wms.catalog-variant-inventory | [data/enrichers.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/data/enrichers.ts) |
30
30
  | enrichers | `overrides.enrichers["wms.sales-order-inventory"]` | disable-replace | extensionSurfaces.contributions:wms.sales-order-inventory | [data/enrichers.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/data/enrichers.ts) |
31
+ | events | `overrides.events.subscribers["wms:invalidate-availability-cache"]` | disable-replace | extensionSurfaces.contributions:wms:invalidate-availability-cache | [subscribers/invalidate-availability-cache.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache.ts) |
32
+ | events | `overrides.events.subscribers["wms:invalidate-availability-cache-policy"]` | disable-replace | extensionSurfaces.contributions:wms:invalidate-availability-cache-policy | [subscribers/invalidate-availability-cache-policy.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache-policy.ts) |
33
+ | events | `overrides.events.subscribers["wms:invalidate-availability-cache-profile"]` | disable-replace | extensionSurfaces.contributions:wms:invalidate-availability-cache-profile | [subscribers/invalidate-availability-cache-profile.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache-profile.ts) |
31
34
  | events | `overrides.events.subscribers["wms:invalidate-enricher-cache-balance"]` | disable-replace | extensionSurfaces.contributions:wms:invalidate-enricher-cache-balance | [subscribers/invalidate-enricher-cache-balance.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-balance.ts) |
32
35
  | events | `overrides.events.subscribers["wms:invalidate-enricher-cache-inventory"]` | disable-replace | extensionSurfaces.contributions:wms:invalidate-enricher-cache-inventory | [subscribers/invalidate-enricher-cache-inventory.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-inventory.ts) |
33
36
  | events | `overrides.events.subscribers["wms:invalidate-enricher-cache-movement"]` | disable-replace | extensionSurfaces.contributions:wms:invalidate-enricher-cache-movement | [subscribers/invalidate-enricher-cache-movement.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-movement.ts) |
@@ -1,5 +1,5 @@
1
1
  # wms — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7296.1.2111d779db; core 0.8.1-develop.7296.1.2111d779db — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.9.0; core 0.9.0 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/wms
4
4
 
5
5
  ## Sections
@@ -11,13 +11,13 @@ Source root: node_modules/@open-mercato/core/src/modules/wms
11
11
  - [Search entities](search-entities.md) — ~1 KB — Generated search entities facts for wms.
12
12
  - [Host extension points](host-extension-points.md) — ~1 KB — Generated host extension points facts for wms.
13
13
  - [UMES hosts](umes-hosts.md) — ~32 KB — Generated umes hosts facts for wms.
14
- - [UMES contributions](umes-contributions.md) — ~10 KB — Generated umes contributions facts for wms.
14
+ - [UMES contributions](umes-contributions.md) — ~11 KB — Generated umes contributions facts for wms.
15
15
  - [Active extension bindings](active-extension-bindings.md) — ~1 KB — Generated active extension bindings facts for wms.
16
16
  - [Contribution resolutions](contribution-resolutions.md) — ~8 KB — Generated contribution resolutions facts for wms.
17
17
  - [UMES diagnostics](umes-diagnostics.md) — ~1 KB — Generated umes diagnostics facts for wms.
18
18
  - [Notifications](notifications.md) — ~1 KB — Generated notifications facts for wms.
19
19
  - [CLI commands](cli-commands.md) — ~1 KB — Generated cli commands facts for wms.
20
- - [Exact override targets](exact-override-targets.md) — ~15 KB — Generated exact override targets facts for wms.
20
+ - [Exact override targets](exact-override-targets.md) — ~16 KB — Generated exact override targets facts for wms.
21
21
  - [Owned contract — module metadata](owned-contract-module-metadata.md) — ~1 KB — Generated owned contract — module metadata facts for wms.
22
22
  - [Domain commands](domain-commands.md) — ~4 KB — Generated domain commands facts for wms.
23
23
  - [Setup](setup.md) — ~1 KB — Generated setup facts for wms.
@@ -20,6 +20,9 @@
20
20
  | search:wms:product_inventory_profile | specialized-registry | wms:product_inventory_profile | — | registry=search; registryId=wms:product_inventory_profile; specialistRoute=search | fact-ref | [search.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/search.ts) |
21
21
  | search:wms:warehouse | specialized-registry | wms:warehouse | — | registry=search; registryId=wms:warehouse; specialistRoute=search | fact-ref | [search.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/search.ts) |
22
22
  | search:wms:warehouse_location | specialized-registry | wms:warehouse_location | — | registry=search; registryId=wms:warehouse_location; specialistRoute=search | fact-ref | [search.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/search.ts) |
23
+ | wms:invalidate-availability-cache | subscriber | wms.inventory_balance.* | before-or-after | event=wms.inventory_balance.*; persistent=false; subscriberId=wms:invalidate-availability-cache; sync=true | pattern | [subscribers/invalidate-availability-cache.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache.ts) |
24
+ | wms:invalidate-availability-cache-policy | subscriber | availability.policy.* | before-or-after | event=availability.policy.*; persistent=false; subscriberId=wms:invalidate-availability-cache-policy; sync=true | pattern | [subscribers/invalidate-availability-cache-policy.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache-policy.ts) |
25
+ | wms:invalidate-availability-cache-profile | subscriber | wms.inventory_profile.* | before-or-after | event=wms.inventory_profile.*; persistent=false; subscriberId=wms:invalidate-availability-cache-profile; sync=true | pattern | [subscribers/invalidate-availability-cache-profile.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache-profile.ts) |
23
26
  | wms:invalidate-enricher-cache-balance | subscriber | wms.inventory_balance.* | before-or-after | event=wms.inventory_balance.*; persistent=false; subscriberId=wms:invalidate-enricher-cache-balance; sync=true | pattern | [subscribers/invalidate-enricher-cache-balance.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-balance.ts) |
24
27
  | wms:invalidate-enricher-cache-inventory | subscriber | wms.inventory.* | before-or-after | event=wms.inventory.*; persistent=false; subscriberId=wms:invalidate-enricher-cache-inventory; sync=true | pattern | [subscribers/invalidate-enricher-cache-inventory.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-inventory.ts) |
25
28
  | wms:invalidate-enricher-cache-movement | subscriber | wms.inventory_movement.* | before-or-after | event=wms.inventory_movement.*; persistent=false; subscriberId=wms:invalidate-enricher-cache-movement; sync=true | pattern | [subscribers/invalidate-enricher-cache-movement.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-movement.ts) |
@@ -6,9 +6,9 @@
6
6
 
7
7
  | Activation | Kind | Host | Contribution kinds | Phases | Bridge | Source |
8
8
  |---|---|---|---|---|---|---|
9
- | entity:workflows.definition_draft:mutation-guard | mutation-guard | entity:workflows.definition_draft @workflows | mutation-guard | — | — | [api/definitions/[id]/draft/route.ts:224](../../../../node_modules/@open-mercato/core/src/modules/workflows/api/definitions/[id]/draft/route.ts#L224) |
10
- | entity:workflows.definition:mutation-guard | mutation-guard | entity:workflows.definition @workflows | mutation-guard | — | — | [api/definitions/[id]/customize/route.ts:65](../../../../node_modules/@open-mercato/core/src/modules/workflows/api/definitions/[id]/customize/route.ts#L65) |
11
- | entity:workflows.instance:mutation-guard | mutation-guard | entity:workflows.instance @workflows | mutation-guard | — | — | [api/instances/[id]/context/route.ts:104](../../../../node_modules/@open-mercato/core/src/modules/workflows/api/instances/[id]/context/route.ts#L104) |
9
+ | entity:workflows.definition_draft:mutation-guard | mutation-guard | entity:workflows.definition_draft @workflows | mutation-guard | — | — | [api/definitions/[id]/draft/route.ts:227](../../../../node_modules/@open-mercato/core/src/modules/workflows/api/definitions/[id]/draft/route.ts#L227) |
10
+ | entity:workflows.definition:mutation-guard | mutation-guard | entity:workflows.definition @workflows | mutation-guard | — | — | [api/definitions/[id]/customize/route.ts:67](../../../../node_modules/@open-mercato/core/src/modules/workflows/api/definitions/[id]/customize/route.ts#L67) |
11
+ | entity:workflows.instance:mutation-guard | mutation-guard | entity:workflows.instance @workflows | mutation-guard | — | — | [api/instances/[id]/context/route.ts:105](../../../../node_modules/@open-mercato/core/src/modules/workflows/api/instances/[id]/context/route.ts#L105) |
12
12
  | widget-spot:data-table:workflows.tasks.list:row-actions:widget-injection-consumer | widget-injection-consumer | widget-spot:data-table:workflows.tasks.list:row-actions @workflows | widget, data-table, crud-form | — | hosts:tasksTable.rowActions | [extension-points.ts](../../../../node_modules/@open-mercato/core/src/modules/workflows/extension-points.ts) |
13
13
 
14
14
  <!-- end module facts section: workflows/active-extension-bindings -->
@@ -1,5 +1,5 @@
1
1
  # workflows — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7296.1.2111d779db; core 0.8.1-develop.7296.1.2111d779db — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.9.0; core 0.9.0 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/workflows
4
4
 
5
5
  ## Sections
@@ -1185,7 +1185,7 @@
1185
1185
  "facts": {
1186
1186
  "title": "Example Module",
1187
1187
  "description": "Demonstrates pages, APIs, entities and DI.",
1188
- "coreVersion": "0.8.1-develop.7296.1.2111d779db",
1188
+ "coreVersion": "0.9.0",
1189
1189
  "sourcePackage": null,
1190
1190
  "sourceVersion": null,
1191
1191
  "sourceRoot": "src/modules/example",
@@ -102,7 +102,7 @@ These exported types are consumed by module developers. Required fields MUST NOT
102
102
  - `WorkerMeta`: `queue` — MUST NOT remove
103
103
  - `TelemetryProvider` (`@open-mercato/telemetry`): `name`, `supports`, `start`, `shutdown`, `runInSpan`, `activeSpan`, `activeTraceContext`, `inject`, `runInRemoteSpan`, `emitLog`, `recordMetric` — MUST NOT remove. `reportError?()` was added 2026-09-08 as an additive OPTIONAL method (see [spec](.ai/specs/2026-09-08-error-reporting-policy.md)); it **MUST stay optional** — third parties implement this interface and a required method would break every existing provider. The facade calls it as `provider.reportError?.(…)` *in addition to* the span/log/metric path, so a provider that omits it loses nothing.
104
104
  - `ReportErrorContext` (`@open-mercato/telemetry`) and the `reportError` context of `TelemetryRuntime` (`@open-mercato/shared/lib/telemetry/runtime`): `module?` and `attributes?` — MUST NOT remove. `code?: string` was added 2026-09-08 as an additive optional field carrying the enumerated `module.reason` fingerprint the backend groups on; it MUST stay optional so existing callers (the API dispatcher, the CRUD factory) keep compiling and keep emitting exactly what they emit today. `om.errors` gains an `error.code` label only when a caller supplies one — the same attribute name the span and the log record use, so one query works against all three.
105
- - `RefreshCredentialsInput` (communication_channels hub): `channelId`, `credentials`, `scope` — MUST NOT remove. `oauthClient?` was added 2026-05-27 as an additive optional field (see [Spec A](.ai/specs/implemented/2026-05-27-email-integration-inbound-reliability-and-threading.md)). The legacy `credentials._client` read path in the Gmail adapter is **deprecated and slated for removal in the next minor release** — pass OAuth client config via `RefreshCredentialsInput.oauthClient` instead.
105
+ - `RefreshCredentialsInput` (communication_channels hub): `channelId`, `credentials`, `scope` — MUST NOT remove. `oauthClient?` was added 2026-05-27 as an additive optional field (see [Spec A](.ai/specs/implemented/2026-05-27-email-integration-inbound-reliability-and-threading.md)). The legacy `credentials._client` read path in the Gmail adapter was **removed** (see #3828 / UPGRADE_NOTES) — OAuth client config MUST be passed via `RefreshCredentialsInput.oauthClient`.
106
106
  - `OAuthClientConfig` (communication_channels hub): added 2026-05-27 with `clientId` required; optional `clientSecret`, `tenantId`, `scopes`. New optional fields may be added; required `clientId` MUST NOT be removed.
107
107
  - `BackendChromePayload`: `groups`, `settingsSections`, `settingsPathPrefixes`, `profileSections`, `profilePathPrefixes`, `grantedFeatures`, `roles` — MUST NOT remove. `currentOrganization?` (`BackendChromeCurrentOrganization | null`) was added 2026-07-30 as an additive optional field (see [spec](.ai/specs/2026-07-30-backend-chrome-current-organization.md)); it is `null` under an all-organizations selection, when no organization is in scope, and when the lookup fails, so consumers MUST treat `null` as "unknown" rather than "no organization". `brand?` is **unchanged** and remains the branding channel — it populates only when the organization has a `logoUrl`, and `currentOrganization` does not supersede it.
108
108
 
@@ -360,6 +360,29 @@ Files in `apps/mercato/.mercato/generated/` are produced by the CLI generators.
360
360
 
361
361
  ---
362
362
 
363
+ ## Canonical API Interceptor Route Identity (2026-10-04)
364
+
365
+ API dispatch and API-interceptor selection now share the same matched-route identity.
366
+ This closes a policy bypass where a mixed-case or percent-encoded spelling dispatched
367
+ to a handler but did not select its exact `before` interceptor.
368
+
369
+ | Surface | Change | Classification |
370
+ |---------|--------|----------------|
371
+ | Function signature (`findApiRouteManifestMatch`) | New optional fourth parameter `request?: Request`; existing three-argument callers keep the same return value and matching behavior | ✓ ADDITIVE (optional parameter appended) |
372
+ | API route URLs and handler context | No route is added, removed, or renamed; handler `params` and request query semantics are unchanged | ✓ No contract change |
373
+ | Interceptor selection | Static segments use the matched manifest spelling, while matched dynamic/catch-all values stay concrete. Alternate spellings that already reached a route now run the same exact/prefix interceptors as its normal spelling; malformed percent encoding reaches no handler | ⚠️ Intentional security narrowing only (previous policy-bypass requests are denied or intercepted) |
374
+ | Request cloning/reconstruction | Dispatcher identity survives `Request.clone()` and `new Request(request.url, request)`. Unknown, forged, or evicted internal continuity metadata fails closed; unbound direct handlers retain legacy URL-derived matching | ✓ Behavior-preserving for valid dispatches; intentional security narrowing for forged metadata |
375
+ | Handler ordering | Authorization and interceptor `before`/`after` positions are unchanged | ✓ Behavior-preserving for normally spelled requests |
376
+
377
+ **Migration path for existing modules**: none. Keep authored `targetRoute` values.
378
+ Callers that dispatch through the framework catch-all receive canonical binding
379
+ automatically; direct three-argument matcher consumers continue to work unchanged.
380
+ Synthetic dispatchers should pass the exact request they invoke as argument four.
381
+ Request wrappers should retain headers when reconstructing the request, or pass an
382
+ authored route constant directly to the interceptor runner.
383
+
384
+ ---
385
+
363
386
  ## CRUD Foreign-Key Violations Answer 409 (2026-09-07)
364
387
 
365
388
  Deleting a user who had customised their sidebar failed on the `user_sidebar_preferences` / `sidebar_variants` foreign keys and surfaced as a generic `500`. The fix clears those rows in `auth.users.delete`, gives both FKs `ON DELETE CASCADE`, and teaches `makeCrudRoute` to recognise a Postgres foreign-key violation (SQLSTATE 23503). **All changes are additive** and pass the contract-surface checks above:
@@ -472,6 +495,24 @@ Spec: [`.ai/specs/2026-09-08-error-reporting-policy.md`](.ai/specs/2026-09-08-er
472
495
 
473
496
  **Volume note for operators.** Reported error *volume* rises where errors were previously only recorded: an integration that writes 115 error rows now also reports 115 errors, grouped by `error.code` at the backend. This is deliberate — see the spec's §S3 — and the controls are the collector's filtering/sampling and the backend's own quotas, not a framework switch.
474
497
 
498
+ ## Data Sync Retry, Resume and Run Again (2026-09-16)
499
+
500
+ [`.ai/specs/2026-09-16-data-sync-retry-resume-actions.md`](.ai/specs/2026-09-16-data-sync-retry-resume-actions.md) splits the Data Sync dashboard's single overloaded "Retry" button into three named operator actions — **Retry** (labelled **Resume** on a cancelled run), **Retry from the beginning**, and **Run again** — and states, on the run detail page, where a retry would resume. **All changes are additive** and pass the contract-surface checks above:
501
+
502
+ | Surface | Change | Classification |
503
+ |---------|--------|----------------|
504
+ | Type definitions (§2) | New exported types `ResumePoint` (a discriminated union of `none` / `noCommittedBatch` / `resumes`) and `ResumePointRun` | ✓ ADDITIVE (new types, nothing renamed — same shape as the `StartControlMap` addition before it) |
505
+ | Import paths (§4) | New module `data_sync/lib/resume-point.ts` exporting `resolveResumePoint`, `isRetryableRunStatus`, `ResumePoint`, `ResumePointRun` | ✓ ADDITIVE (new path; nothing moved or re-exported) |
506
+ | API route URLs (§7) | **No change.** `POST /api/data_sync/runs/[id]/retry` and `POST /api/data_sync/run` are untouched — no new request field, no new response field, no new status code and no new error code. The UI starts sending the already-accepted `fromBeginning: true` for the first time, and reads `cursor` / `initialCursor` / `batchesCompleted`, all of which `GET /api/data_sync/runs` and `GET /api/data_sync/runs/[id]` have returned since 2026-08-12 | ✓ n/a |
507
+ | Database schema (§8) | No change. No entity, column, migration or `.snapshot-open-mercato.json` update; no new run status — the vestigial `paused` status is left exactly as it was | ✓ n/a |
508
+ | Auto-discovery, function signatures, event IDs, widget spot IDs, DI names, ACL features, notification IDs, CLI commands, generated files | No change | ✓ n/a |
509
+
510
+ **Contract commitments**: the retry endpoint deliberately does **not** enforce `supportsStartControl('fullSync', entityType)` before honouring `fromBeginning: true`. [§ Data Sync Start Control Applicability (2026-09-02)](#data-sync-start-control-applicability-2026-09-02) already commits that the declaration "governs what the dashboard **offers**, never what the run API **accepts**", and `fromBeginning: true` on `retry` requests the identical thing as `fullSync: true` on `run` — a `null` start cursor — so the two siblings MUST answer identically. An adapter-declared restriction hides the from-the-beginning action in the UI and nothing more; a scripted or API client keeps the documented escape hatch. Making either endpoint strict is a breaking change under §7 and needs the deprecation protocol, not a UI spec.
511
+
512
+ `ResumePoint` also has **no `fromBeginning` variant, by design**. `api/runs/[id]/retry.ts` resolves a resumable retry as `previous.cursor ?? resolveStartCursor(...)`, and `resolveStartCursor` reads the shared `sync_cursors` row — state the run row does not carry — so a run that committed no batch of its own may still resume at a cursor an earlier run wrote. `noCommittedBatch` therefore means only "this run committed nothing" and MUST NOT be widened by a caller into a positional claim about where a retry starts. A future additive `retryStartCursor` response field is the only way to close that gap; it is out of scope here.
513
+
514
+ **Migration path for existing adapters and clients**: none. The module is new, every endpoint is unchanged, and an adapter or API client that ignores all of this behaves exactly as before.
515
+
475
516
  ## Customers Quick-Create Injection Spot Bridge (2026-09-16)
476
517
 
477
518
  [`.ai/specs/2026-09-16-customers-quick-create-injection-spot-bridge.md`](.ai/specs/2026-09-16-customers-quick-create-injection-spot-bridge.md) binds the sales document form's Person/Company quick-create dialogs to the customers module's declared `crud-form:customers.person` / `…company` hosts. The dialogs previously had no `injectionSpotId`, so `CrudForm` auto-derived `crud-form:customers.customer_entity` (§6, FROZEN) there instead.
@@ -484,3 +525,34 @@ Spec: [`.ai/specs/2026-09-08-error-reporting-policy.md`](.ai/specs/2026-09-08-er
484
525
  | Type definitions (§2) | New optional `CrudForm` prop `legacyInjectionSpotId?: string` | ✓ ADDITIVE |
485
526
 
486
527
  **Deprecation window.** `legacyInjectionSpotId` is scoped to these two call sites and intended for removal after at least one minor version (Deprecation Protocol step 1), tracked in the spec's Changelog and in `UPGRADE_NOTES.md`. No maintainer waiver was needed — nothing is removed by this change.
528
+
529
+ ## Atomic Auth Command Replay (2026-10-04)
530
+
531
+ [`.ai/specs/2026-07-28-protected-roles-and-audit-seam.md`](.ai/specs/2026-07-28-protected-roles-and-audit-seam.md) closes the auth undo/redo transaction, authorization, and membership-phantom gaps without changing existing command handlers by default.
532
+
533
+ | Surface | Change | Classification |
534
+ |---------|--------|----------------|
535
+ | Type definitions (`CommandHandler`, `CommandRuntimeContext`, `CommandExecuteResult`) | New optional `atomicReplay?: boolean` and `stabilizeReplay(...)` handler capabilities, optional `replayTransactionGuard` request guard, optional caller-owned `transactionLifetime`, and optional `replaySourceFinalized?: boolean` result signal. `TransactionLifetime` plus its observation/completion-registration helpers are new exports; lifetime creation/completion remains owned by `withAtomicFlush` | ✓ ADDITIVE (optional fields and exports; omitted handlers and contexts keep the prior flow) |
536
+ | `ActionLogService` method signatures | `log`, `claimForUndo`, `releaseUndoClaim`, and `markUndone` accept an optional trailing transactional `EntityManager`; new `claimForRedo` method | ✓ ADDITIVE (optional parameters appended and a new method; existing calls retain behavior) |
537
+ | `RbacService` | New `loadAclWithEntityManager`, `userHasAllFeaturesWithEntityManager`, and `getGrantedFeaturesWithEntityManager` methods bypass caches and bind every query to the supplied transaction | ✓ ADDITIVE (new methods; existing cache-backed methods are unchanged) |
538
+ | Auth command replay behavior | Auth user/role handlers opt in so source-log state, domain changes, undo trace or new redo log, and redo source finalization commit or roll back together. Before the request guard or feature interceptors run, `stabilizeReplay` discovers and seals one actor/target/destination footprint and locks API keys, users, roles, tenant/organization hierarchy, and authorization children in a total order using the same transaction | ⚠️ Intentional security hardening. A race that previously could deadlock or replay with stale authority is rejected with the existing domain `409`; successful, authorized replay keeps the same response shape |
539
+ | Action-log actor persistence and self replay | `actor_user_id` remains a UUID; new entries also store the canonical user or `api_key:<uuid>` subject in `context.actorSubject`. API-key list ownership, undo/redo ownership, exact-EM RBAC, locks, and latest replay queries use the canonical subject. Canonical history is selected before the legacy bare-UUID fallback, which additionally requires a coherent live `isApiKey`/`keyId`/`sub` tuple | ✓ Database-compatible additive context metadata; same-UUID user, malformed, or ambiguous ownership cannot shadow canonical key history and fails closed |
540
+ | Auth authorization-state writers | First-party `UserRole`, `UserAcl`, and `RoleAcl` writers in commands, setup, CLI, execution principals, SSO, and agent orchestration now share the canonical parent-lock protocol; SSO membership and grant rows commit together | ⚠️ Intentional concurrency hardening; no request, response, schema, import-path, event, feature, or CLI contract changes |
541
+ | Non-auth command replay | Handlers that omit `atomicReplay` retain the existing undo claim/release compensation and route-level redo finalization | ✓ Behavior-preserving |
542
+ | API routes, response schemas, database schema, event IDs, ACL feature IDs, DI names, CLI commands, generated files | No shape or identifier change | ✓ n/a |
543
+
544
+ **Migration path for existing modules**: none. Third-party commands remain on the established replay lifecycle unless they explicitly set `atomicReplay: true`. An opting-in handler must perform all replay database work through `ctx.transactionalEm`; when authorization depends on mutable domain rows it may add `stabilizeReplay` to acquire its complete footprint before guards and interceptors. The command bus supplies and owns the transaction by default. A caller deliberately composing replay inside an already-active `ctx.transactionalEm` must open that outer transaction with `withAtomicFlush(..., { transaction: true })`, obtain its exact `TransactionLifetime` inside the phase, and pass it as `ctx.transactionLifetime`; otherwise replay fails before mutation. Commit-only hooks and redo-finalization reporting follow the true outer completion. The capability does not claim that legacy non-opted-in action-log and domain writes are transactionally atomic.
545
+
546
+ ---
547
+
548
+ ## Organization Update Preserves Omitted Hierarchy Fields (2026-10-01)
549
+
550
+ `directory.organizations.update` treated an omitted `parentId` as `null` and an omitted `childIds` as `[]`, so a partial update — notably `PUT /api/directory/organization-branding`, which sends only logo fields — detached the organization from its parent and orphaned its children. Omitted hierarchy fields are now preserved:
551
+
552
+ | Surface | Change | Classification |
553
+ |---------|--------|----------------|
554
+ | Command behaviour (`directory.organizations.update`) | `parentId` is written and validated only when present in the input; children are reconciled only when `childIds` is present. Explicit `parentId: null` and `childIds: []` still clear. With `childIds` present and `parentId` omitted, listing the current parent answers `400 Child cannot equal parent` (it answered `400 Cannot assign ancestor as child`) | ⚠️ Behaviour change on a previously-corrupting path. A caller that omitted the fields to clear the hierarchy must send the explicit values. Regression-tested in `updateOrganization.partial-hierarchy.test.ts` and `TC-DIR-018` |
555
+ | API routes (`PUT /api/directory/organizations`, `PUT /api/directory/organization-branding`) | Same URLs, request schema (`organizationUpdateSchema` already declares both fields optional) and response shapes | ✓ No shape change |
556
+ | Database schema, event IDs, ACL features, DI names, CLI commands | No change | ✓ n/a |
557
+
558
+ **Migration path for existing modules**: send `parentId: null` / `childIds: []` where clearing is intended. Trees flattened before the upgrade are not repaired (see UPGRADE_NOTES.md).
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": 1,
3
- "generator": "@open-mercato/cli@0.8.1-develop.7296.1.2111d779db",
3
+ "generator": "@open-mercato/cli@0.9.0",
4
4
  "files": {
5
5
  "AGENTS.md": "9fdaca247f55c64f5966cc103265cfb03233e0532f58f14aff538ae18aa3555d",
6
- "BACKWARD_COMPATIBILITY.md": "7f7d93266be9dbf1a1e154df6d40efd6de4ffeea3a2d7b2822f3081d6395c272"
6
+ "BACKWARD_COMPATIBILITY.md": "853f6b5a0b88f8439d7644d463d5b27c2e917366472a1e1fc3ac4586ef47c859"
7
7
  }
8
8
  }
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: om-auto-upgrade-0.8.0-to-0.9.0
3
+ description: Migrate downstream Open Mercato code from 0.8.0 to 0.9.0 — enable progress before customers in src/modules.ts, and audit catalog bulk-delete job scope, redoInput for secret-bearing commands, thrown CrudHttpError statuses, resolveAttachmentRequestScope, directory organization parentId/childIds omission, SUB_WORKFLOW output ports, accent-insensitive search helpers, OpenAI-compatible preset apiMode, snapshot date revival, Gmail oauthClient, host locale overrides, CrudForm injected field ids, ChannelScope null organizations, duplicate ai_assistant encryption maps, WRONG_KEY encryption errors, the telemetry bootstrap, SSE API-key consumers, empty organization scopes, and the route-identity header; validate the app; and report manual work. Use for "upgrade Open Mercato to 0.9.0", "migrate 0.8.0 to 0.9.0", "apply the 0.9.0 upgrade notes", or "zaktualizuj Open Mercato do 0.9.0".
4
+ ---
5
+
6
+ # Auto upgrade 0.8.0 to 0.9.0
7
+
8
+ Apply the mechanical parts of the Open Mercato `0.8.0 → 0.9.0` upgrade to a downstream app. Treat the matching section of `UPGRADE_NOTES.md` as the source of truth and leave every intent-sensitive change as an explicit manual finding.
9
+
10
+ ## Scope
11
+
12
+ Operate on a standalone app or downstream repository that depends on `@open-mercato/*`. Never modify the framework monorepo, framework-owned `packages/`, dependency pins, lockfiles, generated output, vendored dependencies, or secrets. Run after the user has selected and installed `0.9.0`.
13
+
14
+ ## Arguments
15
+
16
+ - `--path <dir>`: downstream repository root; defaults to the current directory.
17
+ - `--dry-run`: detect, classify, and report without editing files or running mutating commands.
18
+ - `--only <id[,id...]>`: limit work to named checks.
19
+ - `--skip <id[,id...]>`: omit named checks and record the omission in the report.
20
+
21
+ Reject unknown flags and combining `--only` with `--skip`.
22
+
23
+ ## Upgrade checks
24
+
25
+ | ID | Classification | Detect | Action |
26
+ | --- | --- | --- | --- |
27
+ | `catalog-bulk-delete-job-scope` | Detect and report | Enqueues on `CATALOG_PRODUCT_BULK_DELETE_QUEUE` or direct calls to `deleteCatalogProductsWithProgress` from `@open-mercato/core/modules/catalog/lib/bulkDelete` | Report that `scope.tenantId`, `scope.organizationId` and `scope.userId` are now all required — a job missing any of them fails before deleting anything; callers that only use `POST /api/catalog/bulk-delete` need nothing |
28
+ | `command-redo-input-secrets` | Detect and report | App command handlers whose `buildLog` returns `replayable: false`, or whose input carries a `password`/`secret`/`token`/`apiKey` field persisted through `buildLog` | Recommend returning a redacted `redoInput` projection on the log metadata instead of `replayable: false` (which also drops the undo token); keep `replayable: false` only where replay can never be made safe; never rewrite a `buildLog` automatically |
29
+ | `user-create-redo-password-reset` | No code action | N/A — operator procedure | Explain that redoing an `auth.users.create` restores the account without a credential; the operator must send a password reset afterwards |
30
+ | `crud-http-error-status` | Detect and report | Tests or clients that assert a `500` from an app route guard, and API route `catch` blocks that convert every error into a `500` without `isCrudHttpError` from `@open-mercato/shared/lib/crud/errors` | Report that the `/api/[...slug]` dispatcher now answers an escaped `CrudHttpError` with its own status; a handler may `throw forbidden()` / `notFound()` / `conflict()` directly; update assertions that expected `500` |
31
+ | `attachment-request-scope` | Detect and report | Imports of `resolveAttachmentOrganizationId` from `@open-mercato/core/modules/attachments/lib/requestScope` | Report the deprecation and that it now throws `forbidden()` for a denied scope instead of returning `null`; recommend `resolveAttachmentRequestScope(container, auth, request)` and answering `{ denied }` with the route's documented status; never rewrite the call automatically since the return shape changes |
32
+ | `directory-organization-hierarchy-omission` | Detect and report | Callers of `PUT /api/directory/organizations`, `PUT /api/directory/organization-branding`, or the `directory.organizations.update` command that omit `parentId`/`childIds` expecting the hierarchy to be cleared | Report that omitted fields are now left untouched; a caller that relied on omission must send `parentId: null` / `childIds: []`; flag payloads sending `childIds` without `parentId`, which can now return `400 Child cannot equal parent`. Also remind operators to audit the action log for trees already flattened by the old behavior |
33
+ | `subworkflow-output-ports` | Detect and report | Workflow definitions (code or seeded JSON) with a `SUB_WORKFLOW` step whose child declares `definition.io.outputs` | Report that every declared child output port is now validated and coerced before `config.outputMapping`; a required port missing from the child context or an uncoercible value now fails with `OUTPUT_VALIDATION`; require the author to satisfy or relax (`required: false`, broader type) each declared port; never edit a workflow definition automatically |
34
+ | `catalog-unaccent-extensions` | No code action | N/A — database operation | Explain that the migration installs `unaccent` and `pg_trgm`; the migrating role needs `CREATE` on the database (and a managed provider may need the extensions allowlisted); deploy the migration before the new code, otherwise product search fails with `function om_immutable_unaccent(text) does not exist` |
35
+ | `accent-insensitive-contains-pattern` | Detect and report | Calls to the deprecated `buildAccentInsensitivePatternSql` from `@open-mercato/shared/lib/db/accentInsensitiveSearch`, and any hand-written accent-insensitive predicate on `catalog_products` | Recommend `buildAccentInsensitiveContainsPatternSql()` bound to the **raw** search term (it unaccents, escapes, and adds the surrounding `%` itself), dropping any prior `escapeLikePattern`/`%` wrapping; recommend building custom `catalog_products` predicates from the same module so they match the trigram index; never rewrite SQL automatically |
36
+ | `openai-compatible-preset-api-mode` | Detect and report | Calls to `createOpenAICompatibleProvider` from `@open-mercato/ai-assistant/modules/ai_assistant/lib/llm-adapters/openai` with a preset that has no `apiMode` | Report that a preset without `apiMode` now calls `POST {baseURL}/chat/completions`; add `apiMode: 'responses'` only if the backend implements the Responses API and the app relies on it |
37
+ | `snapshot-date-revival` | Detect and report | Calls to `reviveSnapshotSeed` (`@open-mercato/shared/lib/commands/redo`) and `extractUndoPayload` (`@open-mercato/shared/lib/commands/undo`) in app undo handlers that assign snapshot date fields to entities | Report that `reviveSnapshotSeed` now throws `[internal] Invalid <field> snapshot date` for an unparsable date; recommend passing `{ datePaths }` or `{ dateFields }` to `extractUndoPayload` where snapshot dates are assigned to entities |
38
+ | `gmail-oauth-client-required` | Detect and report | Custom callers or test fixtures that invoke `refreshCredentials` on the Gmail adapter without `oauthClient`, or that place a `_client` key on Gmail credentials | Report that the `credentials._client` fallback is removed — a missing `oauthClient` now throws and `_client` is ignored; require passing `oauthClient: { clientId, clientSecret, scopes? }` |
39
+ | `host-locale-overrides-module-keys` | Detect and report | Keys in the app's `src/i18n/<locale>.json` that also exist in an installed `@open-mercato/*` module dictionary with a different value | Report every collision: the host value now wins over the module value; require the user to keep intended overrides and delete stale duplicates; never delete a locale key automatically |
40
+ | `crudform-injected-field-id-reuse` | Detect and report | `crud-form:<entityId>:fields` widgets whose injected field `id` equals a field the host form declares | Report that the injected value now reaches host schema validation and `onSubmit`; if the reuse is deliberate, make the value match the host schema; if accidental and the widget persists the value in `onSave`, rename the injected id |
41
+ | `channel-scope-nullable-organization` | Detect and report | Communication channel adapter implementations whose `fetchHistory`, `applyPushNotification`, `sendReaction`, or `removeReaction` read `input.scope.organizationId` | Report that `scope` is now `ChannelScope` (`{ tenantId: string; organizationId: string \| null }`, exported from `@open-mercato/core/modules/communication_channels/lib/adapter`) and `null` means a tenant-wide channel; typecheck flags passing it where a `string` is required; never pick a fallback organization automatically |
42
+ | `customers-requires-progress` | Automatic when exact; otherwise report | `src/modules.ts` enables `customers` from `@open-mercato/core` and has no `progress` entry | Insert `{ id: 'progress', from: '@open-mercato/core' },` immediately before the exact single-line `customers` entry; otherwise report the line to add. `yarn generate` now fails with `Module "customers" requires: progress` without it |
43
+ | `ai-assistant-duplicate-encryption-maps` | Detect and report | App `encryption.ts` files whose `defaultEncryptionMaps` declare `ai_assistant:ai_chat_message`, `ai_assistant:ai_chat_conversation`, or `ai_assistant:ai_pending_action` | Report that the app now fails to start with `Duplicate default encryption map for "ai_assistant:…"`; require deleting those entries, or moving a deliberately different field set to `overrides.encryption.maps['ai_assistant:…']` in `src/modules.ts`; recommend `yarn mercato entities seed-encryption --tenant <tenantId>` for existing tenants |
44
+ | `encryption-wrong-key-error` | Detect and report | Direct calls to `encryptEntityPayload` or `encryptFields` in app code | Report that a value sealed under a different key now raises `TenantDataEncryptionError` with code `WRONG_KEY` instead of being double-encrypted; flag call sites that swallow errors so the failure reaches an operator |
45
+ | `company-create-form-spot` | No code action | Widgets targeting `crud-form:customers.company` or `crud-form:customers.customer_entity` | Explain that the company create page now publishes `crud-form:customers.company` and still dual-publishes the legacy spot; widgets on the declared host now also render in create mode (no `recordId`) |
46
+ | `telemetry-otlp-startup` | Detect and report | `TELEMETRY_BACKEND` set to `otlp`, `signoz`, or `newrelic` (report name and file only, never the value), and a `src/instrumentation.ts` with a bare `await registerTelemetryForNextjs()` outside `try`/`catch` | Report that a missing optional `@opentelemetry/*` dependency now fails startup with `OtlpDependencyUnavailableError`; recommend running `yarn mercato telemetry init --dry-run` and then `yarn mercato telemetry init`, applying the printed snippet by hand when it reports `manual`; check Docker Compose `.env` values for an enabled backend |
47
+ | `sse-stream-api-key-consumers` | Detect and report | Non-browser clients of `GET /api/events/stream` that send `x-api-key` or `Authorization: ApiKey`, or that assume a stream never closes | Report that API-key callers now get `401` and every stream closes after `OM_EVENTS_SSE_CONNECTION_MAX_AGE_MS` (±15%); require switching server consumers to webhooks and reconnecting non-browser clients |
48
+ | `empty-organization-scope-deny` | Detect and report | App code that widens an empty `filterIds`/`allowedIds` back to a home organization, or that resolves a single organization without `resolveSingleOrganizationIdOrDeny` / `isExplicitlyEmptyOrganizationScope` from `@open-mercato/shared/lib/auth/organizationScope` | Report that an explicitly empty scope now means deny-all everywhere; recommend the shared helpers and letting a thrown `CrudHttpError` propagate; remind operators that users seeing empty lists or `403` need organization visibility granted |
49
+ | `progress-api-organization-scope` | No code action | N/A — runtime behavior | Explain that `/api/progress/*` now follows the selected organization; users expecting other organizations' jobs should switch to **All organizations** |
50
+ | `route-identity-header` | Detect and report | App or client code that sets `x-open-mercato-route-identity`, or builds malformed percent-encoded API paths | Report that the header is internal — a forged value now returns `400` — and that a malformed percent escape returns `404` before the handler runs |
51
+ | `encryption-map-uniqueness-migration` | No code action | N/A — deployment ordering | Explain that `Migration20261004120000_encryption_map_scope_uniqueness` must run (`yarn db:migrate` or the deployment migration step) before the new version serves traffic; until then saving an encryption map fails |
52
+
53
+ ## Workflow
54
+
55
+ ### 1. Gate the target
56
+
57
+ Resolve `--path`, require a regular `package.json`, and confirm at least one dependency or development dependency starts with `@open-mercato/`. Refuse to run when the target has the framework monorepo signature, including its core and shared workspace packages.
58
+
59
+ Inspect installed and pinned Open Mercato versions. Continue when they resolve to `0.9.0`; otherwise warn with the detected versions and require explicit user confirmation before edits. A dry run may continue without confirmation.
60
+
61
+ Exclude `.git/`, `node_modules/`, `.yarn/`, `.next/`, `dist/`, `build/`, `coverage/`, `.mercato/generated/`, generated registries, vendor directories, and framework-owned packages from every scan. The single exception is `host-locale-overrides-module-keys`, which reads installed `@open-mercato/*` module dictionaries under `node_modules/` as a read-only reference and never edits them. Follow symlinks neither while scanning nor editing. Never print environment-variable values or other secret-bearing content.
62
+
63
+ ### 2. Build and show the plan
64
+
65
+ Run every selected detection before editing. Report each match as `{checkId, file, line, classification, proposedAction}`. Distinguish exact automatic matches from detect-and-report candidates, and list every no-code-action reminder even when no file match applies.
66
+
67
+ For `customers-requires-progress`, an automatic match requires a regular `src/modules.ts` containing exactly one single-line object literal with `id: 'customers'` (or the double-quoted equivalent) and `from: '@open-mercato/core'`, and no `progress` module id anywhere in the file. A customers entry spread across lines, built conditionally, pushed at runtime, or loaded from another file is a detect-and-report candidate. If `progress` is already present but listed after `customers`, report it — order does not affect the generator check, so do not move it.
68
+
69
+ With `--dry-run`, print the complete plan, all no-code-action reminders, and unresolved manual work, then stop without edits, package-manager commands, generation, tests, or builds.
70
+
71
+ ### 3. Apply bounded edits
72
+
73
+ Ask for confirmation of the displayed plan. Apply one minimal, idempotent edit per exact match:
74
+
75
+ - Insert `{ id: 'progress', from: '@open-mercato/core' },` on its own line immediately before the exact `customers` entry in `src/modules.ts`, copying that line's indentation, quote style, and trailing-comma convention.
76
+
77
+ Preserve file encoding, line endings, and unrelated formatting. Re-scan after editing: `src/modules.ts` must contain exactly one `progress` entry, while every manual candidate remains listed. Never perform repository-wide string replacement, and never run `yarn mercato telemetry init` without the user's explicit go-ahead (it can also edit `package.json` and `.env`).
78
+
79
+ ### 4. Verify
80
+
81
+ Use the package manager and scripts declared by the downstream app; do not assume monorepo-only commands exist. Run, in order when present:
82
+
83
+ 1. the configured generation script (this is what proves the `customers` → `progress` dependency is satisfied);
84
+ 2. the configured typecheck script (this surfaces `ChannelScope` null-organization mismatches);
85
+ 3. the smallest affected test script, otherwise the configured test script;
86
+ 4. the configured build script.
87
+
88
+ Stop at the first new failure caused by an automatic edit, revert only that edit, and move the match to manual follow-up. Preserve and report pre-existing failures rather than rewriting unrelated code or weakening checks.
89
+
90
+ ### 5. Report
91
+
92
+ Report:
93
+
94
+ - the target path and detected Open Mercato versions;
95
+ - the complete pre-edit plan and user confirmation;
96
+ - every edited file grouped by automatic check ID;
97
+ - every detect-and-report finding, with exact file and line;
98
+ - every no-code-action reminder, no-match check, and skipped check;
99
+ - validation commands and outcomes;
100
+ - unresolved operational work: granting the migrating role `CREATE` for `unaccent`/`pg_trgm` and migrating before deploying (catalog search and the encryption-map uniqueness index), `yarn mercato entities seed-encryption` for the new `ai_assistant` maps, the telemetry bootstrap refresh and optional-dependency check for an enabled OTLP backend, password resets after redoing a user create, re-parenting organization trees already flattened by the old `directory.organizations.update`, moving API-key SSE consumers to webhooks, and granting organization visibility to users with an empty scope.
101
+
102
+ If no code changes were required, still report that all twenty-five upgrade categories ran. Recommend reviewing the complete `0.8.0 → 0.9.0` section of `UPGRADE_NOTES.md` before deployment.
103
+
104
+ ## Rules
105
+
106
+ - Every automatic edit must be exact, bounded, minimal, and idempotent.
107
+ - Never change dependency versions, lockfiles, generated output, vendor files, framework-owned packages, or secrets.
108
+ - Never rewrite a command's `buildLog`, a workflow definition, an organization-scope resolver, SQL search predicates, or an adapter's scope handling automatically — every such match in this window is intent-sensitive.
109
+ - Never delete a locale key or an encryption-map entry automatically — report the exact entries instead.
110
+ - Never display `TELEMETRY_BACKEND`, OTLP endpoint/header, or any other environment value; report only the variable name, file, and line.
111
+ - Never weaken typecheck, tests, or build to make the upgrade appear green.
112
+ - Always show the edit plan before mutation and the exact changed-file list afterward.
@@ -6,5 +6,5 @@ Load this reference when records contain PII, credentials, addresses, contact in
6
6
  2. In module `encryption.ts`, import `ModuleEncryptionMap` from `@open-mercato/shared/modules/encryption`, declare `defaultEncryptionMaps: ModuleEncryptionMap[] = [{ entityId: '<module>:<entity>', fields: [{ field: '<database_field>' }] }]`, then `export default defaultEncryptionMaps` for generated registry compatibility. The entries are field-rule objects, not string names. Use a sibling `hashField` only for deterministic equality lookup. Let `TenantDataEncryptionService` populate it during encrypted writes, and query it with `lookupHashCandidates(value)` from `@open-mercato/shared/lib/encryption/aes`; use `hashForLookup(value)` from the same import only when the installed write contract explicitly requires a single keyed value. Never use raw SHA-256 for low-entropy PII such as email or phone values.
7
7
  3. Import `findWithDecryption`, `findOneWithDecryption`, or `findAndCountWithDecryption` from `@open-mercato/shared/lib/encryption/find` and make a concrete call in every implemented direct sensitive-record read path; an unused import or encryption map alone is not a decrypted read. For `makeCrudRoute`, its `entityId` + `fields` factory QueryEngine owns list decryption and `list` has no `findAndCount` override key—do not insert a decryption helper as an unsupported option. Put trusted tenant/organization constraints in each direct helper query `where` **and** pass `{ tenantId, organizationId }` as the fifth-argument decryption scope. The scope selects keys; it does not authorize or scope the ORM query. Use a null/global scope only when the installed contract explicitly permits it. Audit detail/export/search/worker/CLI and other direct ORM paths.
8
8
  4. Keep secrets out of responses, logs, errors, events, snapshots, cache keys, search documents, vector sources, and test artifacts. Exclude encrypted source values from `search.ts` field policies and indexes; index only an explicitly approved hash-only sibling for exact equality. Never sort or fuzzy-filter ciphertext.
9
- 5. Seed/update encryption configuration through the supported command; never hand-roll KMS/AES. For every new or changed map, use an isolated initialized test tenant to reconcile the map, read back its registration, insert a fixture through the real write path, and assert the sensitive database columns are ciphertext before claiming runtime coverage.
9
+ 5. Seed/update encryption configuration through the supported command; never hand-roll KMS/AES. For every new or changed map, use an isolated initialized test tenant to reconcile the map, read back its registration, insert a fixture through the real write path, and assert the sensitive database columns are ciphertext before claiming runtime coverage. A fresh test tenant does not prove existing tenants are covered: maps are seeded only when a tenant is created, and nothing re-seeds tenants that already exist. When you add a map, or a field to an existing map, in a module that may already be deployed, ship a backfill migration in the same module: `this.addSql(buildEncryptionMapBackfillSql({ entityId, fields }))` from `@open-mercato/shared/lib/encryption/migration-backfill`. It inserts the map for every existing (tenant, organization) scope that already has active maps (`NOT EXISTS` guard) and appends missing fields to existing maps. Write the entity id and fields literally in the migration and leave `down()` empty. `yarn db:generate` warns when the local database shows an unbackfilled field. Plaintext rows written before the backfill are encrypted by `yarn mercato entities rotate-encryption-key --tenant <id>` without `--old-key`.
10
10
  6. Test authorized decryption, cross-scope denial, redaction, missing keys, export/search behavior, and cleanup/retention.
@@ -171,7 +171,8 @@
171
171
  "om-auto-upgrade-0.4.10-to-0.5.0",
172
172
  "om-auto-upgrade-0.6.6-to-0.6.7",
173
173
  "om-auto-upgrade-0.6.7-to-0.7.0",
174
- "om-auto-upgrade-0.7.0-to-0.8.0"
174
+ "om-auto-upgrade-0.7.0-to-0.8.0",
175
+ "om-auto-upgrade-0.8.0-to-0.9.0"
175
176
  ]
176
177
  }
177
178
  }
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { isTelemetryBackendEnabled } from "@open-mercato/shared/lib/telemetry/runtime";
3
3
  import { resolveCliBootstrapMode } from "./lib/cli-bootstrap-mode.js";
4
- import { flushTelemetry } from "./lib/flush-telemetry.js";
4
+ import { flushBeforeExit } from "./lib/flush-before-exit.js";
5
5
  function assertNode24Runtime() {
6
6
  const detectedNodeVersion = process.versions.node;
7
7
  const majorVersion = Number.parseInt(detectedNodeVersion.split(".")[0] ?? "0", 10);
@@ -72,7 +72,7 @@ async function main() {
72
72
  }
73
73
  const { run } = await import("./mercato.js");
74
74
  const code = await run(process.argv);
75
- await flushTelemetry();
75
+ await flushBeforeExit();
76
76
  process.exit(code ?? 0);
77
77
  }
78
78
  main().catch((error) => {
package/dist/bin.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/bin.ts"],
4
- "sourcesContent": ["/**\n * CLI binary entry point for @open-mercato/cli package.\n *\n * Called from within a Next.js app directory as: yarn mercato <command>\n * Uses dynamic app resolution to find generated files at .mercato/generated/\n */\nimport { isTelemetryBackendEnabled } from '@open-mercato/shared/lib/telemetry/runtime'\nimport { resolveCliBootstrapMode, type CliBootstrapMode } from './lib/cli-bootstrap-mode.js'\nimport { flushTelemetry } from './lib/flush-telemetry.js'\n// `run` is imported dynamically inside `main()` so telemetry can initialize\n// before the mercato entry (and its Postgres driver) loads \u2014 see main().\n\nfunction assertNode24Runtime(): void {\n const detectedNodeVersion = process.versions.node\n const majorVersion = Number.parseInt(detectedNodeVersion.split('.')[0] ?? '0', 10)\n if (majorVersion >= 24) {\n return\n }\n throw new Error(\n [\n 'Unsupported Node.js runtime.',\n `Cause: Detected Node ${detectedNodeVersion}, but Open Mercato requires Node 24.x.`,\n 'What to do: switch your shell to Node 24 (for example `nvm use 24`), run `yarn install`, then retry.',\n ].join(' '),\n )\n}\n\nasync function tryBootstrap(mode: Exclude<CliBootstrapMode, 'none'>): Promise<boolean> {\n try {\n // Use the CLI resolver to find the app directory (handles monorepo detection)\n const { createResolver } = await import('./lib/resolver.js')\n const resolver = createResolver()\n const appDir = resolver.getAppDir()\n\n if (mode === 'dev-supervisor') {\n const {\n canUseLightweightDevSupervisor,\n loadDevSupervisorManifest,\n registerDevSupervisorManifest,\n } = await import(\n './lib/dev-supervisor-manifest.js'\n )\n const manifest = loadDevSupervisorManifest(appDir)\n if (canUseLightweightDevSupervisor(manifest)) {\n registerDevSupervisorManifest(manifest)\n return true\n }\n }\n\n const { bootstrapFromAppRoot } = await import('@open-mercato/shared/lib/bootstrap/dynamicLoader')\n const { registerCliModules } = await import('./mercato.js')\n const data = await bootstrapFromAppRoot(appDir)\n // Register CLI modules directly to avoid module resolution issues\n registerCliModules(data.modules)\n return true\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n // Check if the error is about missing generated files\n if (\n message.includes('dev-supervisor.generated.json') ||\n (\n message.includes('Cannot find module') &&\n (message.includes('/generated/') || message.includes('.generated') || message.includes('.mercato'))\n )\n ) {\n return false\n }\n // Re-throw other errors\n throw err\n }\n}\n\nasync function main(): Promise<void> {\n assertNode24Runtime()\n const bootstrapMode = resolveCliBootstrapMode(process.argv)\n\n if (bootstrapMode !== 'none') {\n // Load the app's `.env` BEFORE initTelemetry(): `run()` only dotenv-loads it\n // later (ensureEnvLoaded), which is too late \u2014 TELEMETRY_BACKEND set only in\n // `.env` would silently resolve to `noop` for worker/scheduler processes.\n // The loader touches only the resolver + dotenv (no `pg`), preserving the\n // instrumentation load-order guarantee below.\n const { loadAppEnv } = await import('./lib/load-env.js')\n await loadAppEnv()\n\n // Initialize telemetry BEFORE bootstrapping the app graph. Bootstrap and the\n // per-command handlers load MikroORM's Postgres driver \u2192 `pg`, and the\n // OpenTelemetry pg/undici auto-instrumentation only records spans for a\n // driver required AFTER the SDK has started. Registering here \u2014 ahead of any\n // app module \u2014 is what lets long-running worker/scheduler processes emit DB\n // spans (not just the bullmq-otel add/process envelope). The package itself\n // is not imported unless an explicit supported backend is selected.\n if (isTelemetryBackendEnabled()) {\n const { initTelemetry } = await import('@open-mercato/telemetry')\n await initTelemetry()\n }\n\n const bootstrapSucceeded = await tryBootstrap(bootstrapMode)\n if (!bootstrapSucceeded) {\n console.error('\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557')\n console.error('\u2551 Generated files not found! \u2551')\n console.error('\u2551 \u2551')\n console.error('\u2551 The CLI requires generated files to discover modules. \u2551')\n console.error('\u2551 Please run the following command first: \u2551')\n console.error('\u2551 \u2551')\n console.error('\u2551 yarn mercato generate \u2551')\n console.error('\u2551 \u2551')\n console.error('\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D')\n process.exit(1)\n }\n }\n\n // Dynamic import (not a top-level static import) so the mercato entry \u2014 and the\n // Postgres driver it pulls in \u2014 loads only after initTelemetry() above.\n const { run } = await import('./mercato.js')\n const code = await run(process.argv)\n // Flush spans/logs for commands that return (workers block forever and flush via\n // their own shutdown handler instead).\n await flushTelemetry()\n process.exit(code ?? 0)\n}\n\nmain().catch((error: unknown) => {\n if (error instanceof Error) {\n console.error(error.message)\n } else {\n console.error(error)\n }\n process.exit(1)\n})\n"],
5
- "mappings": "AAMA,SAAS,iCAAiC;AAC1C,SAAS,+BAAsD;AAC/D,SAAS,sBAAsB;AAI/B,SAAS,sBAA4B;AACnC,QAAM,sBAAsB,QAAQ,SAAS;AAC7C,QAAM,eAAe,OAAO,SAAS,oBAAoB,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACjF,MAAI,gBAAgB,IAAI;AACtB;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR;AAAA,MACE;AAAA,MACA,wBAAwB,mBAAmB;AAAA,MAC3C;AAAA,IACF,EAAE,KAAK,GAAG;AAAA,EACZ;AACF;AAEA,eAAe,aAAa,MAA2D;AACrF,MAAI;AAEF,UAAM,EAAE,eAAe,IAAI,MAAM,OAAO,mBAAmB;AAC3D,UAAM,WAAW,eAAe;AAChC,UAAM,SAAS,SAAS,UAAU;AAElC,QAAI,SAAS,kBAAkB;AAC7B,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,MACF,IAAI,MAAM,OACR,kCACF;AACA,YAAM,WAAW,0BAA0B,MAAM;AACjD,UAAI,+BAA+B,QAAQ,GAAG;AAC5C,sCAA8B,QAAQ;AACtC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,kDAAkD;AAChG,UAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,cAAc;AAC1D,UAAM,OAAO,MAAM,qBAAqB,MAAM;AAE9C,uBAAmB,KAAK,OAAO;AAC/B,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE/D,QACE,QAAQ,SAAS,+BAA+B,KAE9C,QAAQ,SAAS,oBAAoB,MACpC,QAAQ,SAAS,aAAa,KAAK,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,UAAU,IAEnG;AACA,aAAO;AAAA,IACT;AAEA,UAAM;AAAA,EACR;AACF;AAEA,eAAe,OAAsB;AACnC,sBAAoB;AACpB,QAAM,gBAAgB,wBAAwB,QAAQ,IAAI;AAE1D,MAAI,kBAAkB,QAAQ;AAM5B,UAAM,EAAE,WAAW,IAAI,MAAM,OAAO,mBAAmB;AACvD,UAAM,WAAW;AASjB,QAAI,0BAA0B,GAAG;AAC/B,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,yBAAyB;AAChE,YAAM,cAAc;AAAA,IACtB;AAEA,UAAM,qBAAqB,MAAM,aAAa,aAAa;AAC3D,QAAI,CAAC,oBAAoB;AACvB,cAAQ,MAAM,gaAAuE;AACrF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,gFAAsE;AACpF,cAAQ,MAAM,gFAAsE;AACpF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,gFAAsE;AACpF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,gaAAuE;AACrF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAIA,QAAM,EAAE,IAAI,IAAI,MAAM,OAAO,cAAc;AAC3C,QAAM,OAAO,MAAM,IAAI,QAAQ,IAAI;AAGnC,QAAM,eAAe;AACrB,UAAQ,KAAK,QAAQ,CAAC;AACxB;AAEA,KAAK,EAAE,MAAM,CAAC,UAAmB;AAC/B,MAAI,iBAAiB,OAAO;AAC1B,YAAQ,MAAM,MAAM,OAAO;AAAA,EAC7B,OAAO;AACL,YAAQ,MAAM,KAAK;AAAA,EACrB;AACA,UAAQ,KAAK,CAAC;AAChB,CAAC;",
4
+ "sourcesContent": ["/**\n * CLI binary entry point for @open-mercato/cli package.\n *\n * Called from within a Next.js app directory as: yarn mercato <command>\n * Uses dynamic app resolution to find generated files at .mercato/generated/\n */\nimport { isTelemetryBackendEnabled } from '@open-mercato/shared/lib/telemetry/runtime'\nimport { resolveCliBootstrapMode, type CliBootstrapMode } from './lib/cli-bootstrap-mode.js'\nimport { flushBeforeExit } from './lib/flush-before-exit.js'\n// `run` is imported dynamically inside `main()` so telemetry can initialize\n// before the mercato entry (and its Postgres driver) loads \u2014 see main().\n\nfunction assertNode24Runtime(): void {\n const detectedNodeVersion = process.versions.node\n const majorVersion = Number.parseInt(detectedNodeVersion.split('.')[0] ?? '0', 10)\n if (majorVersion >= 24) {\n return\n }\n throw new Error(\n [\n 'Unsupported Node.js runtime.',\n `Cause: Detected Node ${detectedNodeVersion}, but Open Mercato requires Node 24.x.`,\n 'What to do: switch your shell to Node 24 (for example `nvm use 24`), run `yarn install`, then retry.',\n ].join(' '),\n )\n}\n\nasync function tryBootstrap(mode: Exclude<CliBootstrapMode, 'none'>): Promise<boolean> {\n try {\n // Use the CLI resolver to find the app directory (handles monorepo detection)\n const { createResolver } = await import('./lib/resolver.js')\n const resolver = createResolver()\n const appDir = resolver.getAppDir()\n\n if (mode === 'dev-supervisor') {\n const {\n canUseLightweightDevSupervisor,\n loadDevSupervisorManifest,\n registerDevSupervisorManifest,\n } = await import(\n './lib/dev-supervisor-manifest.js'\n )\n const manifest = loadDevSupervisorManifest(appDir)\n if (canUseLightweightDevSupervisor(manifest)) {\n registerDevSupervisorManifest(manifest)\n return true\n }\n }\n\n const { bootstrapFromAppRoot } = await import('@open-mercato/shared/lib/bootstrap/dynamicLoader')\n const { registerCliModules } = await import('./mercato.js')\n const data = await bootstrapFromAppRoot(appDir)\n // Register CLI modules directly to avoid module resolution issues\n registerCliModules(data.modules)\n return true\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n // Check if the error is about missing generated files\n if (\n message.includes('dev-supervisor.generated.json') ||\n (\n message.includes('Cannot find module') &&\n (message.includes('/generated/') || message.includes('.generated') || message.includes('.mercato'))\n )\n ) {\n return false\n }\n // Re-throw other errors\n throw err\n }\n}\n\nasync function main(): Promise<void> {\n assertNode24Runtime()\n const bootstrapMode = resolveCliBootstrapMode(process.argv)\n\n if (bootstrapMode !== 'none') {\n // Load the app's `.env` BEFORE initTelemetry(): `run()` only dotenv-loads it\n // later (ensureEnvLoaded), which is too late \u2014 TELEMETRY_BACKEND set only in\n // `.env` would silently resolve to `noop` for worker/scheduler processes.\n // The loader touches only the resolver + dotenv (no `pg`), preserving the\n // instrumentation load-order guarantee below.\n const { loadAppEnv } = await import('./lib/load-env.js')\n await loadAppEnv()\n\n // Initialize telemetry BEFORE bootstrapping the app graph. Bootstrap and the\n // per-command handlers load MikroORM's Postgres driver \u2192 `pg`, and the\n // OpenTelemetry pg/undici auto-instrumentation only records spans for a\n // driver required AFTER the SDK has started. Registering here \u2014 ahead of any\n // app module \u2014 is what lets long-running worker/scheduler processes emit DB\n // spans (not just the bullmq-otel add/process envelope). The package itself\n // is not imported unless an explicit supported backend is selected.\n if (isTelemetryBackendEnabled()) {\n const { initTelemetry } = await import('@open-mercato/telemetry')\n await initTelemetry()\n }\n\n const bootstrapSucceeded = await tryBootstrap(bootstrapMode)\n if (!bootstrapSucceeded) {\n console.error('\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557')\n console.error('\u2551 Generated files not found! \u2551')\n console.error('\u2551 \u2551')\n console.error('\u2551 The CLI requires generated files to discover modules. \u2551')\n console.error('\u2551 Please run the following command first: \u2551')\n console.error('\u2551 \u2551')\n console.error('\u2551 yarn mercato generate \u2551')\n console.error('\u2551 \u2551')\n console.error('\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D')\n process.exit(1)\n }\n }\n\n // Dynamic import (not a top-level static import) so the mercato entry \u2014 and the\n // Postgres driver it pulls in \u2014 loads only after initTelemetry() above.\n const { run } = await import('./mercato.js')\n const code = await run(process.argv)\n // Flush the coalesced browser broadcasts, then spans/logs, for commands that\n // return (workers block forever and flush via their own shutdown handler instead).\n await flushBeforeExit()\n process.exit(code ?? 0)\n}\n\nmain().catch((error: unknown) => {\n if (error instanceof Error) {\n console.error(error.message)\n } else {\n console.error(error)\n }\n process.exit(1)\n})\n"],
5
+ "mappings": "AAMA,SAAS,iCAAiC;AAC1C,SAAS,+BAAsD;AAC/D,SAAS,uBAAuB;AAIhC,SAAS,sBAA4B;AACnC,QAAM,sBAAsB,QAAQ,SAAS;AAC7C,QAAM,eAAe,OAAO,SAAS,oBAAoB,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACjF,MAAI,gBAAgB,IAAI;AACtB;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR;AAAA,MACE;AAAA,MACA,wBAAwB,mBAAmB;AAAA,MAC3C;AAAA,IACF,EAAE,KAAK,GAAG;AAAA,EACZ;AACF;AAEA,eAAe,aAAa,MAA2D;AACrF,MAAI;AAEF,UAAM,EAAE,eAAe,IAAI,MAAM,OAAO,mBAAmB;AAC3D,UAAM,WAAW,eAAe;AAChC,UAAM,SAAS,SAAS,UAAU;AAElC,QAAI,SAAS,kBAAkB;AAC7B,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,MACF,IAAI,MAAM,OACR,kCACF;AACA,YAAM,WAAW,0BAA0B,MAAM;AACjD,UAAI,+BAA+B,QAAQ,GAAG;AAC5C,sCAA8B,QAAQ;AACtC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,kDAAkD;AAChG,UAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,cAAc;AAC1D,UAAM,OAAO,MAAM,qBAAqB,MAAM;AAE9C,uBAAmB,KAAK,OAAO;AAC/B,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE/D,QACE,QAAQ,SAAS,+BAA+B,KAE9C,QAAQ,SAAS,oBAAoB,MACpC,QAAQ,SAAS,aAAa,KAAK,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,UAAU,IAEnG;AACA,aAAO;AAAA,IACT;AAEA,UAAM;AAAA,EACR;AACF;AAEA,eAAe,OAAsB;AACnC,sBAAoB;AACpB,QAAM,gBAAgB,wBAAwB,QAAQ,IAAI;AAE1D,MAAI,kBAAkB,QAAQ;AAM5B,UAAM,EAAE,WAAW,IAAI,MAAM,OAAO,mBAAmB;AACvD,UAAM,WAAW;AASjB,QAAI,0BAA0B,GAAG;AAC/B,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,yBAAyB;AAChE,YAAM,cAAc;AAAA,IACtB;AAEA,UAAM,qBAAqB,MAAM,aAAa,aAAa;AAC3D,QAAI,CAAC,oBAAoB;AACvB,cAAQ,MAAM,gaAAuE;AACrF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,gFAAsE;AACpF,cAAQ,MAAM,gFAAsE;AACpF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,gFAAsE;AACpF,cAAQ,MAAM,iFAAuE;AACrF,cAAQ,MAAM,gaAAuE;AACrF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAIA,QAAM,EAAE,IAAI,IAAI,MAAM,OAAO,cAAc;AAC3C,QAAM,OAAO,MAAM,IAAI,QAAQ,IAAI;AAGnC,QAAM,gBAAgB;AACtB,UAAQ,KAAK,QAAQ,CAAC;AACxB;AAEA,KAAK,EAAE,MAAM,CAAC,UAAmB;AAC/B,MAAI,iBAAiB,OAAO;AAC1B,YAAQ,MAAM,MAAM,OAAO;AAAA,EAC7B,OAAO;AACL,YAAQ,MAAM,KAAK;AAAA,EACrB;AACA,UAAQ,KAAK,CAAC;AAChB,CAAC;",
6
6
  "names": []
7
7
  }