@open-mercato/cli 0.8.1-develop.7228.1.b7ea09d2d3 → 0.8.1-develop.7238.1.3abe669ea5

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 (102) hide show
  1. package/.turbo/turbo-build.log +4 -2
  2. package/dist/agentic/guides/module-facts.json +835 -160
  3. package/dist/agentic/guides/module-facts.v2.json +835 -160
  4. package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
  5. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  6. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  7. package/dist/agentic/guides/modules/api_keys/index.md +1 -1
  8. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  9. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  10. package/dist/agentic/guides/modules/auth/index.md +1 -1
  11. package/dist/agentic/guides/modules/availability/acl-features.md +13 -0
  12. package/dist/agentic/guides/modules/availability/backend-pages.md +14 -0
  13. package/dist/agentic/guides/modules/availability/di-registrations-rich.md +11 -0
  14. package/dist/agentic/guides/modules/availability/domain-commands.md +13 -0
  15. package/dist/agentic/guides/modules/availability/entities.md +11 -0
  16. package/dist/agentic/guides/modules/availability/events.md +13 -0
  17. package/dist/agentic/guides/modules/availability/exact-override-targets.md +19 -0
  18. package/dist/agentic/guides/modules/availability/host-extension-points.md +10 -0
  19. package/dist/agentic/guides/modules/availability/index.md +22 -0
  20. package/dist/agentic/guides/modules/availability/owned-contract-module-metadata.md +11 -0
  21. package/dist/agentic/guides/modules/availability/setup.md +11 -0
  22. package/dist/agentic/guides/modules/availability/umes-hosts.md +14 -0
  23. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  24. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  25. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  26. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  27. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  28. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  29. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  30. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  31. package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
  32. package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
  33. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  34. package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
  35. package/dist/agentic/guides/modules/configs/index.md +1 -1
  36. package/dist/agentic/guides/modules/content/index.md +1 -1
  37. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  38. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  39. package/dist/agentic/guides/modules/customers/index.md +1 -1
  40. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  41. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  42. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  43. package/dist/agentic/guides/modules/devices/index.md +1 -1
  44. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  45. package/dist/agentic/guides/modules/directory/index.md +1 -1
  46. package/dist/agentic/guides/modules/documents/index.md +1 -1
  47. package/dist/agentic/guides/modules/entities/index.md +1 -1
  48. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  49. package/dist/agentic/guides/modules/events/index.md +1 -1
  50. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  51. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  52. package/dist/agentic/guides/modules/generators/index.md +1 -1
  53. package/dist/agentic/guides/modules/inbox_ops/exact-override-targets.md +3 -3
  54. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  55. package/dist/agentic/guides/modules/inbox_ops/setup.md +1 -1
  56. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  57. package/dist/agentic/guides/modules/messages/index.md +1 -1
  58. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  59. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  60. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  61. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  62. package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
  63. package/dist/agentic/guides/modules/planner/index.md +1 -1
  64. package/dist/agentic/guides/modules/portal/index.md +1 -1
  65. package/dist/agentic/guides/modules/progress/index.md +1 -1
  66. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  67. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  68. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  69. package/dist/agentic/guides/modules/resources/index.md +1 -1
  70. package/dist/agentic/guides/modules/sales/index.md +1 -1
  71. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  72. package/dist/agentic/guides/modules/search/index.md +1 -1
  73. package/dist/agentic/guides/modules/security/index.md +1 -1
  74. package/dist/agentic/guides/modules/seeds/index.md +1 -1
  75. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  76. package/dist/agentic/guides/modules/sso/index.md +1 -1
  77. package/dist/agentic/guides/modules/staff/index.md +1 -1
  78. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  79. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  80. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  81. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  82. package/dist/agentic/guides/modules/tillio/index.md +1 -1
  83. package/dist/agentic/guides/modules/translations/index.md +1 -1
  84. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  85. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  86. package/dist/agentic/guides/modules/wms/contribution-resolutions.md +1 -0
  87. package/dist/agentic/guides/modules/wms/di-registrations-rich.md +8 -8
  88. package/dist/agentic/guides/modules/wms/exact-override-targets.md +9 -8
  89. package/dist/agentic/guides/modules/wms/index.md +2 -2
  90. package/dist/agentic/guides/modules/wms/umes-contributions.md +1 -0
  91. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  92. package/dist/agentic/guides/reference-module-facts.json +1 -1
  93. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +29 -0
  94. package/dist/agentic/guides/upstream/manifest.json +2 -2
  95. package/dist/bin.js +3 -5
  96. package/dist/bin.js.map +2 -2
  97. package/dist/lib/flush-telemetry.js +13 -0
  98. package/dist/lib/flush-telemetry.js.map +7 -0
  99. package/package.json +6 -6
  100. package/src/bin.ts +3 -5
  101. package/src/lib/__tests__/flush-telemetry.test.ts +36 -0
  102. package/src/lib/flush-telemetry.ts +16 -0
@@ -1,5 +1,5 @@
1
1
  # planner — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/planner
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # portal — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/portal
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # progress — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/progress
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # push_notifications — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/push_notifications
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # query_index — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/query_index
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # record_locks — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/enterprise 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/enterprise 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/enterprise/src/modules/record_locks
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # resources — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/resources
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # sales — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/sales
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # scheduler — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/scheduler 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/scheduler 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/scheduler/src/modules/scheduler
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # search — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/search 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/search 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/search/src/modules/search
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # security — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/enterprise 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/enterprise 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/enterprise/src/modules/security
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # seeds — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/seeds
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # shipping_carriers — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/shipping_carriers
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # sso — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/enterprise 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/enterprise 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/enterprise/src/modules/sso
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # staff — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/staff
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # storage_s3 — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/storage-s3 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/storage-s3 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/storage-s3/src/modules/storage_s3
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # sync_akeneo — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/sync-akeneo 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/sync-akeneo 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/sync-akeneo/src/modules/sync_akeneo
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # sync_excel — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/sync_excel
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # system_status_overlays — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/enterprise 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/enterprise 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/enterprise/src/modules/system_status_overlays
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # tillio — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/tillio 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/tillio 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/tillio/src/modules/tillio
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # translations — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/translations
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # warranty_claims — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/warranty_claims
4
4
 
5
5
  ## Sections
@@ -1,5 +1,5 @@
1
1
  # webhooks — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/webhooks 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/webhooks 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/webhooks/src/modules/webhooks
4
4
 
5
5
  ## Sections
@@ -12,6 +12,7 @@
12
12
  | search:wms:product_inventory_profile | module:wms:product_inventory_profile @wms | capability-only | — | [search.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/search.ts) |
13
13
  | search:wms:warehouse_location | module:wms:warehouse_location @wms | capability-only | — | [search.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/search.ts) |
14
14
  | search:wms:warehouse | module:wms:warehouse @wms | capability-only | — | [search.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/search.ts) |
15
+ | wms:invalidate-availability-cache | wildcard:wms.inventory_balance.* | wildcard | — | [subscribers/invalidate-availability-cache.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-availability-cache.ts) |
15
16
  | wms:invalidate-enricher-cache-balance | wildcard:wms.inventory_balance.* | wildcard | — | [subscribers/invalidate-enricher-cache-balance.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-balance.ts) |
16
17
  | wms:invalidate-enricher-cache-inventory | wildcard:wms.inventory.* | wildcard | — | [subscribers/invalidate-enricher-cache-inventory.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-inventory.ts) |
17
18
  | wms:invalidate-enricher-cache-movement | wildcard:wms.inventory_movement.* | wildcard | — | [subscribers/invalidate-enricher-cache-movement.ts](../../../../node_modules/@open-mercato/core/src/modules/wms/subscribers/invalidate-enricher-cache-movement.ts) |
@@ -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,18 @@
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) |
31
32
  | 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
33
  | 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
34
  | 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.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — R1 staleness stamp -->
3
3
  Source root: node_modules/@open-mercato/core/src/modules/wms
4
4
 
5
5
  ## Sections
@@ -11,7 +11,7 @@ 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.
@@ -20,6 +20,7 @@
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) |
23
24
  | 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
25
  | 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
26
  | 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) |
@@ -1,5 +1,5 @@
1
1
  # workflows — module facts (generated, do not edit)
2
- <!-- generated from @open-mercato/core 0.8.1-develop.7228.1.b7ea09d2d3; core 0.8.1-develop.7228.1.b7ea09d2d3 — R1 staleness stamp -->
2
+ <!-- generated from @open-mercato/core 0.8.1-develop.7238.1.3abe669ea5; core 0.8.1-develop.7238.1.3abe669ea5 — 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.7228.1.b7ea09d2d3",
1188
+ "coreVersion": "0.8.1-develop.7238.1.3abe669ea5",
1189
1189
  "sourcePackage": null,
1190
1190
  "sourceVersion": null,
1191
1191
  "sourceRoot": "src/modules/example",
@@ -375,6 +375,22 @@ Deleting a user who had customised their sidebar failed on the `user_sidebar_pre
375
375
 
376
376
  ---
377
377
 
378
+ ## Encrypt Path Rejects Wrong-Key Ciphertext (2026-09-11)
379
+
380
+ `TenantDataEncryptionService.encryptFields` treats "already encrypted" as "decrypts under the current DEK" — a deliberate anti-forgery choice ([#2720](https://github.com/open-mercato/open-mercato/issues/2720)). Real ciphertext sealed under a *different* key failed that check too and was encrypted a second time, producing a nested envelope that no read path can undo, plus a lookup hash computed over ciphertext ([#5951](https://github.com/open-mercato/open-mercato/issues/5951)). That write is now rejected:
381
+
382
+ | Surface | Change | Classification |
383
+ |---------|--------|----------------|
384
+ | Import path / exports (`@open-mercato/shared/lib/encryption/aes`) | New export `isEncryptedPayloadShape(value)` — a key-free structural check (`<iv>:<ct>:<tag>:v1` with a 12-byte IV, 16-byte tag and non-empty ciphertext). Explicitly NOT an "is this encrypted" oracle; the shape is forgeable | ✓ ADDITIVE (new export, nothing removed or renamed) |
385
+ | Function behaviour (`encryptEntityPayload` / `encryptFields`) | A field holding a structurally well-formed envelope that does not decrypt under the current DEK now raises `TenantDataEncryptionError` with code `WRONG_KEY`, where it previously returned a payload containing a nested envelope. Signature, return type and every other input keep their byte-identical historical behaviour | ⚠️ Behaviour change on one previously-corrupting path. `WRONG_KEY` was already declared in `TenantDataEncryptionErrorCode` and emitted nowhere, so no existing handler changes meaning. Regression-tested in `tenantDataEncryptionService.test.ts` |
386
+ | Encryption-at-rest guarantee (#2720) | Unchanged. Nothing is ever stored verbatim: a forgery whose shape is not length-valid (the check is length-based, not content-based) still fails the structural check and is encrypted as ordinary plaintext, and a length-valid one is rejected rather than persisted | ✓ Preserved (pinned by the retained `#2720` test cases) |
387
+ | CLI behaviour (`mercato entities rotate-encryption-key`, `… backfill-system-encryption`) | A row whose ciphertext opens under neither `--old-key` nor the current tenant key is reported and skipped instead of rewritten; the backfill no longer passes already-encrypted columns to the encrypt path. Rows that rotated or backfilled successfully before are unaffected | ✓ Behaviour-preserving for every row that succeeded before; a row that was previously corrupted is now skipped instead — `rotate-encryption-key --old-key` reports it in the run summary, while `backfill-system-encryption` and `rotate-encryption-key` without `--old-key` skip it silently (see UPGRADE_NOTES.md) |
388
+ | DB schema, API routes, event IDs, ACL features, DI names | No change | ✓ n/a |
389
+
390
+ **Migration path for existing modules**: no action required. Operationally, a write touching a record whose encrypted field is sealed under a stale key now fails loudly until the rotation is finished (`mercato entities rotate-encryption-key --old-key …`) or the sealing DEK is restored — a deliberate trade of availability for integrity, since the previous outcome was silent, undetectable corruption. This change does not repair envelopes that were already nested before the upgrade.
391
+
392
+ ---
393
+
378
394
  ## Module Registry Registration Listeners (2026-08-12)
379
395
 
380
396
  [`.ai/specs/2026-08-12-module-registry-registration-listeners.md`](.ai/specs/2026-08-12-module-registry-registration-listeners.md) adds a public subscription to the module registry so a cache derived from the module list can drop what it built from an incomplete one ([#5103](https://github.com/open-mercato/open-mercato/issues/5103)). **All changes are additive** and pass the contract-surface checks above:
@@ -454,3 +470,16 @@ Spec: [`.ai/specs/2026-09-08-error-reporting-policy.md`](.ai/specs/2026-09-08-er
454
470
  **Operator note — terminal queue failures.** Not a contract break, but visible in an alert rule: on the **local** strategy a job's final attempt previously emitted both `queue.job_failed` and `queue.job_exhausted`; it now emits only `queue.job_exhausted`, matching the `async` strategy. An alert thresholding on `queue.job_failed` alone stops seeing terminal failures — page on `queue.job_exhausted`.
455
471
 
456
472
  **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.
473
+
474
+ ## Customers Quick-Create Injection Spot Bridge (2026-09-16)
475
+
476
+ [`.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.
477
+
478
+ | Surface | Change | Classification |
479
+ |---------|--------|----------------|
480
+ | Widget Injection Spot IDs (§6) | `CrudForm` gains an additive `legacyInjectionSpotId?: string` prop. When set, its header/body/field widgets are dual-published alongside the primary `injectionSpotId`'s — `crud-form:customers.customer_entity` stays live on these two dialogs via the bridge, so nothing that already targets it stops rendering | ✓ ADDITIVE (bridge, not a removal — see Deprecation Protocol steps 1–3) |
481
+ | Widget Injection Spot IDs (§6) | The two dialogs now also publish `crud-form:customers.person` / `…company` (previously published only by the person/company detail pages) | ✓ ADDITIVE ("MAY add new spot IDs to new or existing pages") |
482
+ | Context passed to widgets at `crud-form:customers.person` / `…company` | These hosts' widgets now also mount with `operation: 'create'` and no `recordId` on the two quick-create dialogs, for the first time — previously always `operation: 'update'` with a concrete `recordId` | Disclosed in [`UPGRADE_NOTES.md`](UPGRADE_NOTES.md) "Action for module authors"; not itself a contract surface change (§6 permits "new optional context fields", and `operation`/`recordId` were always part of the injection context shape) |
483
+ | Type definitions (§2) | New optional `CrudForm` prop `legacyInjectionSpotId?: string` | ✓ ADDITIVE |
484
+
485
+ **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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": 1,
3
- "generator": "@open-mercato/cli@0.8.1-develop.7228.1.b7ea09d2d3",
3
+ "generator": "@open-mercato/cli@0.8.1-develop.7238.1.3abe669ea5",
4
4
  "files": {
5
5
  "AGENTS.md": "9fdaca247f55c64f5966cc103265cfb03233e0532f58f14aff538ae18aa3555d",
6
- "BACKWARD_COMPATIBILITY.md": "89a54c0b08f043967f284052d2e1d9f16e406e4a70dd68078749831334e3dcc2"
6
+ "BACKWARD_COMPATIBILITY.md": "b2f4286c289e203b5b22a4c2eb44ffe94b1b92cdb384815b311ce456399983a0"
7
7
  }
8
8
  }
package/dist/bin.js CHANGED
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- getTelemetryRuntime,
4
- isTelemetryBackendEnabled
5
- } from "@open-mercato/shared/lib/telemetry/runtime";
2
+ import { isTelemetryBackendEnabled } from "@open-mercato/shared/lib/telemetry/runtime";
6
3
  import { resolveCliBootstrapMode } from "./lib/cli-bootstrap-mode.js";
4
+ import { flushTelemetry } from "./lib/flush-telemetry.js";
7
5
  function assertNode24Runtime() {
8
6
  const detectedNodeVersion = process.versions.node;
9
7
  const majorVersion = Number.parseInt(detectedNodeVersion.split(".")[0] ?? "0", 10);
@@ -74,7 +72,7 @@ async function main() {
74
72
  }
75
73
  const { run } = await import("./mercato.js");
76
74
  const code = await run(process.argv);
77
- await getTelemetryRuntime()?.shutdown();
75
+ await flushTelemetry();
78
76
  process.exit(code ?? 0);
79
77
  }
80
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 {\n getTelemetryRuntime,\n isTelemetryBackendEnabled,\n} from '@open-mercato/shared/lib/telemetry/runtime'\nimport { resolveCliBootstrapMode, type CliBootstrapMode } from './lib/cli-bootstrap-mode.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 getTelemetryRuntime()?.shutdown()\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;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,+BAAsD;AAI/D,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,oBAAoB,GAAG,SAAS;AACtC,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 { 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;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,13 @@
1
+ import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
2
+ async function flushTelemetry(runtime = getTelemetryRuntime()) {
3
+ try {
4
+ await runtime?.shutdown();
5
+ } catch (error) {
6
+ const reason = error instanceof Error ? error.message : String(error);
7
+ console.warn(`[telemetry] Flush on exit failed; telemetry from this run may be lost: ${reason}`);
8
+ }
9
+ }
10
+ export {
11
+ flushTelemetry
12
+ };
13
+ //# sourceMappingURL=flush-telemetry.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/flush-telemetry.ts"],
4
+ "sourcesContent": ["import { getTelemetryRuntime, type TelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\n\n/**\n * Flushes telemetry before the CLI exits. Export is best-effort: an unreachable or\n * overloaded collector degrades to a warning and never changes the command's exit code.\n */\nexport async function flushTelemetry(\n runtime: TelemetryRuntime | undefined = getTelemetryRuntime(),\n): Promise<void> {\n try {\n await runtime?.shutdown()\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n console.warn(`[telemetry] Flush on exit failed; telemetry from this run may be lost: ${reason}`)\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,2BAAkD;AAM3D,eAAsB,eACpB,UAAwC,oBAAoB,GAC7C;AACf,MAAI;AACF,UAAM,SAAS,SAAS;AAAA,EAC1B,SAAS,OAAO;AACd,UAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,YAAQ,KAAK,0EAA0E,MAAM,EAAE;AAAA,EACjG;AACF;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.8.1-develop.7228.1.b7ea09d2d3",
3
+ "version": "0.8.1-develop.7238.1.3abe669ea5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,9 +60,9 @@
60
60
  "@mikro-orm/decorators": "^7.1.14",
61
61
  "@mikro-orm/migrations": "^7.1.14",
62
62
  "@mikro-orm/postgresql": "^7.1.14",
63
- "@open-mercato/queue": "0.8.1-develop.7228.1.b7ea09d2d3",
64
- "@open-mercato/shared": "0.8.1-develop.7228.1.b7ea09d2d3",
65
- "@open-mercato/telemetry": "0.8.1-develop.7228.1.b7ea09d2d3",
63
+ "@open-mercato/queue": "0.8.1-develop.7238.1.3abe669ea5",
64
+ "@open-mercato/shared": "0.8.1-develop.7238.1.3abe669ea5",
65
+ "@open-mercato/telemetry": "0.8.1-develop.7238.1.3abe669ea5",
66
66
  "cross-spawn": "^7.0.6",
67
67
  "pg": "8.23.0",
68
68
  "semver": "^7.8.5",
@@ -73,10 +73,10 @@
73
73
  "typescript-js": "npm:typescript@6.0.3"
74
74
  },
75
75
  "peerDependencies": {
76
- "@open-mercato/shared": "0.8.1-develop.7228.1.b7ea09d2d3"
76
+ "@open-mercato/shared": "0.8.1-develop.7238.1.3abe669ea5"
77
77
  },
78
78
  "devDependencies": {
79
- "@open-mercato/shared": "0.8.1-develop.7228.1.b7ea09d2d3",
79
+ "@open-mercato/shared": "0.8.1-develop.7238.1.3abe669ea5",
80
80
  "@types/jest": "^30.0.0",
81
81
  "jest": "^30.4.2",
82
82
  "ts-jest": "^29.4.12"
package/src/bin.ts CHANGED
@@ -4,11 +4,9 @@
4
4
  * Called from within a Next.js app directory as: yarn mercato <command>
5
5
  * Uses dynamic app resolution to find generated files at .mercato/generated/
6
6
  */
7
- import {
8
- getTelemetryRuntime,
9
- isTelemetryBackendEnabled,
10
- } from '@open-mercato/shared/lib/telemetry/runtime'
7
+ import { isTelemetryBackendEnabled } from '@open-mercato/shared/lib/telemetry/runtime'
11
8
  import { resolveCliBootstrapMode, type CliBootstrapMode } from './lib/cli-bootstrap-mode.js'
9
+ import { flushTelemetry } from './lib/flush-telemetry.js'
12
10
  // `run` is imported dynamically inside `main()` so telemetry can initialize
13
11
  // before the mercato entry (and its Postgres driver) loads — see main().
14
12
 
@@ -118,7 +116,7 @@ async function main(): Promise<void> {
118
116
  const code = await run(process.argv)
119
117
  // Flush spans/logs for commands that return (workers block forever and flush via
120
118
  // their own shutdown handler instead).
121
- await getTelemetryRuntime()?.shutdown()
119
+ await flushTelemetry()
122
120
  process.exit(code ?? 0)
123
121
  }
124
122
 
@@ -0,0 +1,36 @@
1
+ import type { TelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
2
+ import { flushTelemetry } from '../flush-telemetry'
3
+
4
+ function runtimeWithShutdown(shutdown: () => Promise<void>): TelemetryRuntime {
5
+ return { shutdown } as unknown as TelemetryRuntime
6
+ }
7
+
8
+ describe('flushTelemetry', () => {
9
+ let warn: jest.SpyInstance
10
+
11
+ beforeEach(() => {
12
+ warn = jest.spyOn(console, 'warn').mockImplementation(() => {})
13
+ })
14
+
15
+ afterEach(() => {
16
+ warn.mockRestore()
17
+ })
18
+
19
+ it('shuts the runtime down', async () => {
20
+ const shutdown = jest.fn().mockResolvedValue(undefined)
21
+ await flushTelemetry(runtimeWithShutdown(shutdown))
22
+ expect(shutdown).toHaveBeenCalledTimes(1)
23
+ expect(warn).not.toHaveBeenCalled()
24
+ })
25
+
26
+ it('resolves with a warning when the exporter rejects on shutdown', async () => {
27
+ const shutdown = jest.fn().mockRejectedValue(new Error('Export failed with retryable status'))
28
+ await expect(flushTelemetry(runtimeWithShutdown(shutdown))).resolves.toBeUndefined()
29
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining('Export failed with retryable status'))
30
+ })
31
+
32
+ it('is a no-op without a telemetry runtime', async () => {
33
+ await expect(flushTelemetry(undefined)).resolves.toBeUndefined()
34
+ expect(warn).not.toHaveBeenCalled()
35
+ })
36
+ })
@@ -0,0 +1,16 @@
1
+ import { getTelemetryRuntime, type TelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
2
+
3
+ /**
4
+ * Flushes telemetry before the CLI exits. Export is best-effort: an unreachable or
5
+ * overloaded collector degrades to a warning and never changes the command's exit code.
6
+ */
7
+ export async function flushTelemetry(
8
+ runtime: TelemetryRuntime | undefined = getTelemetryRuntime(),
9
+ ): Promise<void> {
10
+ try {
11
+ await runtime?.shutdown()
12
+ } catch (error) {
13
+ const reason = error instanceof Error ? error.message : String(error)
14
+ console.warn(`[telemetry] Flush on exit failed; telemetry from this run may be lost: ${reason}`)
15
+ }
16
+ }