@open-mercato/cli 0.6.7-develop.6862.1.c11a64ce0a → 0.6.7

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 (278) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/build.mjs +7 -24
  3. package/dist/agentic/claude-code/hooks/entity-migration-check.ts +88 -32
  4. package/dist/agentic/codex/enforcement-rules.md +16 -2
  5. package/dist/agentic/cursor/hooks/entity-migration-check.mjs +50 -19
  6. package/dist/agentic/cursor/rules/entity-guard.mdc +21 -9
  7. package/dist/agentic/cursor/rules/generated-guard.mdc +5 -3
  8. package/dist/agentic/cursor/rules/open-mercato.mdc +29 -3
  9. package/dist/agentic/guides/cache.md +45 -0
  10. package/dist/agentic/guides/core.md +453 -0
  11. package/dist/agentic/guides/events.md +117 -0
  12. package/dist/agentic/guides/module-facts.json +3833 -115419
  13. package/dist/agentic/guides/module-system.md +127 -12
  14. package/dist/agentic/guides/modules/ai_assistant.md +28 -227
  15. package/dist/agentic/guides/modules/api_docs.md +2 -58
  16. package/dist/agentic/guides/modules/api_keys.md +7 -92
  17. package/dist/agentic/guides/modules/attachments.md +14 -119
  18. package/dist/agentic/guides/modules/audit_logs.md +10 -131
  19. package/dist/agentic/guides/modules/auth.md +33 -276
  20. package/dist/agentic/guides/modules/business_rules.md +14 -149
  21. package/dist/agentic/guides/modules/catalog.md +43 -475
  22. package/dist/agentic/guides/modules/channel_gmail.md +3 -82
  23. package/dist/agentic/guides/modules/channel_imap.md +3 -82
  24. package/dist/agentic/guides/modules/checkout.md +27 -299
  25. package/dist/agentic/guides/modules/communication_channels.md +33 -315
  26. package/dist/agentic/guides/modules/configs.md +8 -104
  27. package/dist/agentic/guides/modules/content.md +2 -57
  28. package/dist/agentic/guides/modules/currencies.md +17 -152
  29. package/dist/agentic/guides/modules/customer_accounts.md +45 -387
  30. package/dist/agentic/guides/modules/customers.md +85 -746
  31. package/dist/agentic/guides/modules/dashboards.md +10 -155
  32. package/dist/agentic/guides/modules/data_sync.md +16 -149
  33. package/dist/agentic/guides/modules/dictionaries.md +12 -107
  34. package/dist/agentic/guides/modules/directory.md +15 -148
  35. package/dist/agentic/guides/modules/entities.md +13 -145
  36. package/dist/agentic/guides/modules/events.md +2 -59
  37. package/dist/agentic/guides/modules/feature_toggles.md +9 -119
  38. package/dist/agentic/guides/modules/gateway_stripe.md +4 -92
  39. package/dist/agentic/guides/modules/generators.md +2 -45
  40. package/dist/agentic/guides/modules/inbox_ops.md +27 -207
  41. package/dist/agentic/guides/modules/integrations.md +16 -146
  42. package/dist/agentic/guides/modules/messages.md +24 -223
  43. package/dist/agentic/guides/modules/notifications.md +8 -96
  44. package/dist/agentic/guides/modules/onboarding.md +6 -77
  45. package/dist/agentic/guides/modules/payment_gateways.md +21 -164
  46. package/dist/agentic/guides/modules/perspectives.md +7 -77
  47. package/dist/agentic/guides/modules/planner.md +18 -136
  48. package/dist/agentic/guides/modules/portal.md +2 -93
  49. package/dist/agentic/guides/modules/progress.md +14 -104
  50. package/dist/agentic/guides/modules/query_index.md +15 -154
  51. package/dist/agentic/guides/modules/record_locks.md +21 -206
  52. package/dist/agentic/guides/modules/resources.md +30 -197
  53. package/dist/agentic/guides/modules/sales.md +84 -678
  54. package/dist/agentic/guides/modules/scheduler.md +14 -133
  55. package/dist/agentic/guides/modules/search.md +6 -170
  56. package/dist/agentic/guides/modules/security.md +35 -294
  57. package/dist/agentic/guides/modules/shipping_carriers.md +18 -134
  58. package/dist/agentic/guides/modules/sso.md +26 -151
  59. package/dist/agentic/guides/modules/staff.md +57 -369
  60. package/dist/agentic/guides/modules/storage_s3.md +5 -95
  61. package/dist/agentic/guides/modules/sync_akeneo.md +3 -85
  62. package/dist/agentic/guides/modules/sync_excel.md +6 -75
  63. package/dist/agentic/guides/modules/system_status_overlays.md +2 -60
  64. package/dist/agentic/guides/modules/translations.md +10 -104
  65. package/dist/agentic/guides/modules/webhooks.md +24 -203
  66. package/dist/agentic/guides/modules/wms.md +46 -441
  67. package/dist/agentic/guides/modules/workflows.md +43 -302
  68. package/dist/agentic/guides/queue.md +53 -0
  69. package/dist/agentic/guides/search.md +115 -0
  70. package/dist/agentic/guides/shared.md +108 -0
  71. package/dist/agentic/guides/ui.md +347 -0
  72. package/dist/agentic/shared/AGENTS.md.template +311 -124
  73. package/dist/agentic/shared/ai/agentic.config.json +0 -2
  74. package/dist/agentic/shared/ai/lessons.md +3 -26
  75. package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +27 -0
  76. package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +27 -0
  77. package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +0 -4
  78. package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +241 -20
  79. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +260 -0
  80. package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +601 -16
  81. package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +146 -0
  82. package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +310 -14
  83. package/dist/agentic/shared/ai/skills/om-help/SKILL.md +97 -15
  84. package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +84 -0
  85. package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +193 -0
  86. package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +152 -33
  87. package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +708 -24
  88. package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +34 -0
  89. package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +762 -0
  90. package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +820 -20
  91. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +50 -0
  92. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +97 -0
  93. package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +843 -19
  94. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +271 -0
  95. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +63 -15
  96. package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +467 -16
  97. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +101 -0
  98. package/dist/agentic/shared/ai/skills/tiers.json +21 -143
  99. package/dist/agentic/shared/ai/skills/tiers.schema.json +40 -52
  100. package/dist/agentic/shared/ai/specs/README.md +3 -4
  101. package/dist/agentic/shared/ai/specs/SPEC-000-template.md +10 -226
  102. package/dist/agentic/shared/ai/trackers/github.md +4 -108
  103. package/dist/agentic/shared/scripts/install-skills.sh +694 -4
  104. package/dist/bin.js +1 -13
  105. package/dist/bin.js.map +2 -2
  106. package/dist/lib/__integration__/TC-INT-008.spec.js +8 -88
  107. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  108. package/dist/lib/agentic-init.js +3 -13
  109. package/dist/lib/agentic-init.js.map +2 -2
  110. package/dist/lib/agentic-setup.js +186 -418
  111. package/dist/lib/agentic-setup.js.map +2 -2
  112. package/dist/lib/generators/extensions/injection-widgets.js +0 -20
  113. package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
  114. package/dist/lib/generators/module-facts-discovery.js +7 -41
  115. package/dist/lib/generators/module-facts-discovery.js.map +2 -2
  116. package/dist/lib/generators/module-facts.js +45 -1387
  117. package/dist/lib/generators/module-facts.js.map +3 -3
  118. package/dist/lib/generators/module-registry.js +5 -11
  119. package/dist/lib/generators/module-registry.js.map +2 -2
  120. package/dist/lib/resolver.js +0 -2
  121. package/dist/lib/resolver.js.map +2 -2
  122. package/dist/lib/testing/integration.js +0 -5
  123. package/dist/lib/testing/integration.js.map +2 -2
  124. package/dist/mercato.js +1 -23
  125. package/dist/mercato.js.map +2 -2
  126. package/package.json +11 -13
  127. package/src/bin.ts +1 -33
  128. package/src/lib/__integration__/TC-INT-008.spec.ts +9 -107
  129. package/src/lib/__tests__/agentic-init.test.ts +5 -41
  130. package/src/lib/agentic-init.ts +3 -15
  131. package/src/lib/agentic-setup.ts +224 -530
  132. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +2 -88
  133. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +0 -1
  134. package/src/lib/generators/__tests__/module-facts.discovery.test.ts +10 -54
  135. package/src/lib/generators/__tests__/module-subset.test.ts +0 -18
  136. package/src/lib/generators/extensions/injection-widgets.ts +0 -51
  137. package/src/lib/generators/module-facts-discovery.ts +7 -58
  138. package/src/lib/generators/module-facts.ts +46 -1851
  139. package/src/lib/generators/module-registry.ts +6 -16
  140. package/src/lib/resolver.ts +0 -3
  141. package/src/lib/testing/__tests__/integration.test.ts +0 -4
  142. package/src/lib/testing/integration.ts +0 -5
  143. package/src/mercato.ts +1 -26
  144. package/dist/agentic/guides/ai-workflows.md +0 -76
  145. package/dist/agentic/guides/architecture.md +0 -107
  146. package/dist/agentic/guides/backend-ui.md +0 -80
  147. package/dist/agentic/guides/contracts.md +0 -92
  148. package/dist/agentic/guides/extensions.md +0 -121
  149. package/dist/agentic/guides/framework-extension-points.md +0 -36
  150. package/dist/agentic/guides/integrations.md +0 -81
  151. package/dist/agentic/guides/modules/design_system.md +0 -102
  152. package/dist/agentic/guides/spec-delivery.md +0 -22
  153. package/dist/agentic/guides/testing-debugging.md +0 -80
  154. package/dist/agentic/guides/upstream/AGENTS.md +0 -298
  155. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +0 -316
  156. package/dist/agentic/guides/upstream/manifest.json +0 -8
  157. package/dist/agentic/shared/ai/harness/README.md +0 -50
  158. package/dist/agentic/shared/ai/harness/RELEASE.md +0 -57
  159. package/dist/agentic/shared/ai/harness/cases.json +0 -13680
  160. package/dist/agentic/shared/ai/harness/cases.schema.json +0 -133
  161. package/dist/agentic/shared/ai/harness/fixtures/index.json +0 -49
  162. package/dist/agentic/shared/ai/harness/fixtures/seeds.json +0 -162
  163. package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +0 -21
  164. package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +0 -96
  165. package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +0 -172
  166. package/dist/agentic/shared/ai/harness/release-matrix.json +0 -158
  167. package/dist/agentic/shared/ai/harness/release-result.schema.json +0 -219
  168. package/dist/agentic/shared/ai/harness/result.schema.json +0 -76
  169. package/dist/agentic/shared/ai/harness/routing-response.schema.json +0 -12
  170. package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +0 -73
  171. package/dist/agentic/shared/ai/harness/validators.json +0 -78
  172. package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +0 -2121
  173. package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +0 -1096
  174. package/dist/agentic/shared/ai/lessons/_template.md +0 -16
  175. package/dist/agentic/shared/ai/review-checklist.md +0 -36
  176. package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +0 -21
  177. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +0 -98
  178. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +0 -16
  179. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +0 -53
  180. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +0 -13
  181. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +0 -11
  182. package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +0 -30
  183. package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +0 -12
  184. package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +0 -13
  185. package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +0 -14
  186. package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +0 -28
  187. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +0 -12
  188. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +0 -22
  189. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +0 -12
  190. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +0 -19
  191. package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +0 -19
  192. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +0 -13
  193. package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +0 -14
  194. package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +0 -10
  195. package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +0 -17
  196. package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +0 -29
  197. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +0 -100
  198. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +0 -16
  199. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +0 -17
  200. package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +0 -25
  201. package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +0 -11
  202. package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +0 -13
  203. package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +0 -18
  204. package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +0 -20
  205. package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +0 -33
  206. package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +0 -40
  207. package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +0 -27
  208. package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +0 -24
  209. package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +0 -16
  210. package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +0 -14
  211. package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +0 -15
  212. package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +0 -12
  213. package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +0 -34
  214. package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +0 -4
  215. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +0 -11
  216. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +0 -31
  217. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +0 -39
  218. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +0 -43
  219. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +0 -11
  220. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +0 -19
  221. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +0 -172
  222. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +0 -12
  223. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +0 -83
  224. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +0 -21
  225. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +0 -11
  226. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +0 -22
  227. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +0 -13
  228. package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +0 -41
  229. package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +0 -19
  230. package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +0 -44
  231. package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +0 -39
  232. package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +0 -20
  233. package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +0 -57
  234. package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +0 -11
  235. package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +0 -486
  236. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +0 -18
  237. package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +0 -27
  238. package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +0 -13
  239. package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +0 -41
  240. package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +0 -11
  241. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +0 -15
  242. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +0 -16
  243. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +0 -14
  244. package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +0 -187
  245. package/dist/agentic/shared/scripts/check-lessons.mjs +0 -178
  246. package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +0 -2958
  247. package/dist/agentic/shared/scripts/execution-sandbox.mjs +0 -329
  248. package/dist/agentic/shared/scripts/framework-context.mjs +0 -888
  249. package/dist/agentic/shared/scripts/install-skills.mjs +0 -1029
  250. package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +0 -222
  251. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +0 -1774
  252. package/dist/lib/generators/module-extension-facts.js +0 -1840
  253. package/dist/lib/generators/module-extension-facts.js.map +0 -7
  254. package/dist/lib/generators/module-fact-sources.js +0 -70
  255. package/dist/lib/generators/module-fact-sources.js.map +0 -7
  256. package/dist/lib/generators/module-override-targets.js +0 -688
  257. package/dist/lib/generators/module-override-targets.js.map +0 -7
  258. package/dist/lib/load-env.js +0 -24
  259. package/dist/lib/load-env.js.map +0 -7
  260. package/dist/lib/telemetry-init.js +0 -358
  261. package/dist/lib/telemetry-init.js.map +0 -7
  262. package/src/lib/__tests__/agentic-setup.ownership.test.ts +0 -386
  263. package/src/lib/__tests__/injection-widget-id-validation.test.ts +0 -184
  264. package/src/lib/__tests__/load-env.test.ts +0 -65
  265. package/src/lib/__tests__/telemetry-init.test.ts +0 -298
  266. package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +0 -92
  267. package/src/lib/generators/__tests__/module-extension-activations.test.ts +0 -762
  268. package/src/lib/generators/__tests__/module-extension-facts.test.ts +0 -404
  269. package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +0 -108
  270. package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +0 -561
  271. package/src/lib/generators/__tests__/module-facts.source-links.test.ts +0 -119
  272. package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +0 -149
  273. package/src/lib/generators/__tests__/module-override-targets.test.ts +0 -304
  274. package/src/lib/generators/module-extension-facts.ts +0 -2365
  275. package/src/lib/generators/module-fact-sources.ts +0 -108
  276. package/src/lib/generators/module-override-targets.ts +0 -863
  277. package/src/lib/load-env.ts +0 -30
  278. package/src/lib/telemetry-init.ts +0 -461
@@ -1,1840 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import ts from "typescript-js";
4
- import {
5
- CRUD_FORM_EXTENSION_SURFACES,
6
- CRUD_FORM_LIFECYCLE_PHASES,
7
- DATA_TABLE_EXTENSION_SURFACES
8
- } from "@open-mercato/shared/modules/widgets/extension-points";
9
- import { extractCommandIdsFromSource } from "./module-registry.js";
10
- import { scanModuleDir, SCAN_CONFIGS } from "./scanner.js";
11
- let activeExtractionCache = null;
12
- function withModuleExtensionFactExtractionCache(operation) {
13
- if (activeExtractionCache) return operation();
14
- activeExtractionCache = {
15
- sourceFiles: /* @__PURE__ */ new Map(),
16
- sourceFilesBelow: /* @__PURE__ */ new Map(),
17
- apiExtensionHostIds: /* @__PURE__ */ new Map()
18
- };
19
- try {
20
- return operation();
21
- } finally {
22
- activeExtractionCache = null;
23
- }
24
- }
25
- const FRAMEWORK_PREFIXES = [
26
- "dashboard:",
27
- "menu:",
28
- "notification:",
29
- "integration:",
30
- "integrations.detail:",
31
- "system-status:",
32
- "topbar:"
33
- ];
34
- const FRAMEWORK_HOSTS = [
35
- frameworkHost("framework.backend.sidebar", "menu:backend.sidebar", "menu", ["menu-item"]),
36
- frameworkHost("framework.settings.sidebar", "menu:settings.sidebar", "menu", ["menu-item"]),
37
- frameworkHost("framework.profile.sidebar", "menu:profile.sidebar", "menu", ["menu-item"]),
38
- frameworkHost("framework.portal.sidebar", "menu:portal.sidebar", "menu", ["menu-item"]),
39
- frameworkHost("framework.dashboard", "dashboard:*", "dashboard", ["registry-contribution"]),
40
- frameworkHost("framework.notifications", "notification:*", "notification", ["registry-contribution"]),
41
- frameworkHost("framework.integration-detail", "integrations.detail:{integrationId}", "integration", ["render-widget"]),
42
- frameworkHost("framework.integration-detail-fallback", "integrations.detail:tabs", "integration", ["render-widget"]),
43
- frameworkHost("framework.backend-mutation", "backend-mutation:global", "generic", ["headless-widget"]),
44
- frameworkHost("framework.crud-form-wildcard", "crud-form:*", "crud-form", ["field-widget", "lifecycle-handler"])
45
- ];
46
- function frameworkHost(key, id, family, capabilities) {
47
- return {
48
- key,
49
- id,
50
- resolution: id.includes("*") || id.includes("{") ? "pattern" : "framework",
51
- family,
52
- ownerModule: "framework",
53
- capabilities,
54
- bound: true,
55
- stability: "frozen",
56
- source: { kind: "framework", path: "packages/ui/src", symbol: key }
57
- };
58
- }
59
- function frameworkOverrideHost(key, mode) {
60
- return {
61
- key: `framework.module-override.${key}`,
62
- id: `module-override:${key}`,
63
- resolution: "framework",
64
- family: "module-override",
65
- ownerModule: "framework",
66
- capabilities: ["module-override"],
67
- operations: [mode],
68
- bound: true,
69
- stability: "stable",
70
- source: {
71
- kind: "framework",
72
- path: "packages/shared/src/modules/overrides.ts",
73
- symbol: `ModuleOverrides.${key}`
74
- }
75
- };
76
- }
77
- const FRAMEWORK_OVERRIDE_HOSTS = [
78
- frameworkOverrideHost("ai.agents", "disable-replace"),
79
- frameworkOverrideHost("ai.tools", "disable-replace"),
80
- frameworkOverrideHost("ai.extensions", "additive"),
81
- frameworkOverrideHost("routes.api", "disable-replace"),
82
- frameworkOverrideHost("routes.pages", "disable-replace"),
83
- frameworkOverrideHost("events.subscribers", "disable-replace"),
84
- frameworkOverrideHost("workers", "disable-replace"),
85
- frameworkOverrideHost("widgets.injection", "disable-replace"),
86
- frameworkOverrideHost("widgets.components", "disable-replace"),
87
- frameworkOverrideHost("widgets.dashboard", "disable-replace"),
88
- frameworkOverrideHost("notifications.types", "disable-replace"),
89
- frameworkOverrideHost("notifications.handlers", "disable-replace"),
90
- frameworkOverrideHost("interceptors", "disable-replace"),
91
- frameworkOverrideHost("commandInterceptors", "disable-replace"),
92
- frameworkOverrideHost("enrichers", "disable-replace"),
93
- frameworkOverrideHost("guards", "disable-replace"),
94
- frameworkOverrideHost("cli", "disable-replace"),
95
- frameworkOverrideHost("setup", "replace"),
96
- frameworkOverrideHost("acl.features", "disable-replace"),
97
- frameworkOverrideHost("di", "disable-replace"),
98
- frameworkOverrideHost("encryption.maps", "disable-replace"),
99
- frameworkOverrideHost("nav.groupOrder", "additive")
100
- ];
101
- function allFrameworkHosts() {
102
- return [...FRAMEWORK_HOSTS, ...FRAMEWORK_OVERRIDE_HOSTS];
103
- }
104
- function sourceFile(filePath) {
105
- const cached = activeExtractionCache?.sourceFiles.get(filePath);
106
- if (cached !== void 0) return cached;
107
- if (!fs.existsSync(filePath)) return null;
108
- const scriptKind = filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
109
- const parsed = ts.createSourceFile(filePath, fs.readFileSync(filePath, "utf8"), ts.ScriptTarget.ES2020, true, scriptKind);
110
- activeExtractionCache?.sourceFiles.set(filePath, parsed);
111
- return parsed;
112
- }
113
- function unwrap(expression) {
114
- let current = expression;
115
- while (ts.isAsExpression(current) || ts.isTypeAssertionExpression(current) || ts.isParenthesizedExpression(current) || ts.isSatisfiesExpression(current)) {
116
- current = current.expression;
117
- }
118
- return current;
119
- }
120
- function propertyName(node) {
121
- if (ts.isIdentifier(node) || ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) return node.text;
122
- return null;
123
- }
124
- function buildStaticContext(file) {
125
- const initializers = /* @__PURE__ */ new Map();
126
- const visit = (node) => {
127
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
128
- initializers.set(node.name.text, node.initializer);
129
- }
130
- if (ts.isFunctionDeclaration(node) && node.name && node.body) {
131
- initializers.set(node.name.text, node);
132
- }
133
- node.forEachChild(visit);
134
- };
135
- file.forEachChild(visit);
136
- return { initializers, sourceFile: file, resolving: /* @__PURE__ */ new Set() };
137
- }
138
- function entityRegistryValue(expression) {
139
- const parts = [];
140
- let current = expression;
141
- while (ts.isPropertyAccessExpression(current)) {
142
- parts.unshift(current.name.text);
143
- current = current.expression;
144
- }
145
- return ts.isIdentifier(current) && current.text === "E" && parts.length === 2 ? `${parts[0]}:${parts[1]}` : null;
146
- }
147
- function staticTemplate(expression, context) {
148
- let value = expression.head.text;
149
- for (const span of expression.templateSpans) {
150
- const substitution = staticValue(span.expression, context);
151
- if (typeof substitution !== "string" && typeof substitution !== "number") return null;
152
- value += `${substitution}${span.literal.text}`;
153
- }
154
- return value;
155
- }
156
- function staticObject(expression, context) {
157
- const result = {};
158
- for (const property of expression.properties) {
159
- if (ts.isPropertyAssignment(property)) {
160
- const name = propertyName(property.name);
161
- if (!name) continue;
162
- const value = staticValue(property.initializer, context);
163
- if (value !== void 0) result[name] = value;
164
- continue;
165
- }
166
- if (ts.isShorthandPropertyAssignment(property)) {
167
- const value = staticValue(property.name, context);
168
- if (value !== void 0) result[property.name.text] = value;
169
- continue;
170
- }
171
- if (ts.isMethodDeclaration(property)) {
172
- const name = propertyName(property.name);
173
- if (name) result[name] = true;
174
- continue;
175
- }
176
- if (ts.isSpreadAssignment(property)) {
177
- const value = staticValue(property.expression, context);
178
- if (isStaticObject(value)) Object.assign(result, value);
179
- }
180
- }
181
- return result;
182
- }
183
- function staticValue(expression, context) {
184
- const current = unwrap(expression);
185
- if (ts.isStringLiteralLike(current) || ts.isNumericLiteral(current)) return current.text;
186
- if (current.kind === ts.SyntaxKind.TrueKeyword) return true;
187
- if (current.kind === ts.SyntaxKind.FalseKeyword) return false;
188
- if (current.kind === ts.SyntaxKind.NullKeyword) return null;
189
- if (ts.isNoSubstitutionTemplateLiteral(current)) return current.text;
190
- if (ts.isTemplateExpression(current)) return staticTemplate(current, context) ?? void 0;
191
- if (ts.isArrayLiteralExpression(current)) {
192
- return current.elements.flatMap((element) => {
193
- if (ts.isSpreadElement(element)) {
194
- const spread = staticValue(element.expression, context);
195
- return Array.isArray(spread) ? spread : [];
196
- }
197
- const value = staticValue(element, context);
198
- return value === void 0 ? [] : [value];
199
- });
200
- }
201
- if (ts.isObjectLiteralExpression(current)) return staticObject(current, context);
202
- if (ts.isPropertyAccessExpression(current)) {
203
- return entityRegistryValue(current) ?? void 0;
204
- }
205
- if (ts.isIdentifier(current)) {
206
- if (context.resolving.has(current.text)) return void 0;
207
- const initializer = context.initializers.get(current.text);
208
- if (!initializer) return void 0;
209
- context.resolving.add(current.text);
210
- const value = ts.isFunctionDeclaration(initializer) ? void 0 : staticValue(initializer, context);
211
- context.resolving.delete(current.text);
212
- return value;
213
- }
214
- if (ts.isCallExpression(current)) {
215
- if (ts.isIdentifier(current.expression)) {
216
- const callable = context.initializers.get(current.expression.text);
217
- if (callable && (ts.isArrowFunction(callable) || ts.isFunctionExpression(callable) || ts.isFunctionDeclaration(callable))) {
218
- const initializers = new Map(context.initializers);
219
- callable.parameters.forEach((parameter, index) => {
220
- if (ts.isIdentifier(parameter.name) && current.arguments[index]) {
221
- initializers.set(parameter.name.text, current.arguments[index]);
222
- }
223
- });
224
- const childContext = {
225
- initializers,
226
- sourceFile: context.sourceFile,
227
- resolving: new Set(context.resolving)
228
- };
229
- if (callable.body && ts.isExpression(callable.body)) return staticValue(callable.body, childContext);
230
- const returnStatement = callable.body?.statements.find(ts.isReturnStatement);
231
- if (returnStatement?.expression) return staticValue(returnStatement.expression, childContext);
232
- }
233
- }
234
- const firstArgument = current.arguments[0];
235
- if (firstArgument) {
236
- const value = staticValue(firstArgument, context);
237
- if (!isStaticObject(value) || !ts.isIdentifier(current.expression)) return value;
238
- if (current.expression.text === "dataTableExtensionHost") return { family: "data-table", ...value };
239
- if (current.expression.text === "crudFormExtensionHost") return { family: "crud-form", ...value };
240
- if (current.expression.text === "componentExtensionHost") return { family: "component-handle", ...value };
241
- return value;
242
- }
243
- }
244
- if (ts.isConditionalExpression(current)) {
245
- const left = staticValue(current.whenTrue, context);
246
- const right = staticValue(current.whenFalse, context);
247
- return left !== void 0 && JSON.stringify(left) === JSON.stringify(right) ? left : void 0;
248
- }
249
- return void 0;
250
- }
251
- function isStaticObject(value) {
252
- return !!value && typeof value === "object" && !Array.isArray(value);
253
- }
254
- function strings(value) {
255
- return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
256
- }
257
- function stringValue(value) {
258
- return typeof value === "string" ? value : void 0;
259
- }
260
- function numberValue(value) {
261
- if (typeof value === "number") return value;
262
- if (typeof value === "string" && /^\d+$/.test(value)) return Number(value);
263
- return void 0;
264
- }
265
- function booleanValue(value) {
266
- return typeof value === "boolean" ? value : void 0;
267
- }
268
- function portablePath(moduleRoot, sourceRoot, filePath) {
269
- return path.posix.join(sourceRoot, path.relative(moduleRoot, filePath).split(path.sep).join("/"));
270
- }
271
- function conventionPath(moduleRoot, relativePath) {
272
- const direct = path.join(moduleRoot, relativePath);
273
- if (fs.existsSync(direct)) return direct;
274
- if (relativePath.endsWith(".ts")) {
275
- const tsx = `${direct.slice(0, -3)}.tsx`;
276
- if (fs.existsSync(tsx)) return tsx;
277
- }
278
- return null;
279
- }
280
- function readConventionObjectArray(filePath, exportName) {
281
- const file = sourceFile(filePath);
282
- if (!file) return [];
283
- const context = buildStaticContext(file);
284
- const initializer = context.initializers.get(exportName);
285
- if (!initializer || ts.isFunctionDeclaration(initializer)) return [];
286
- const value = staticValue(initializer, context);
287
- return Array.isArray(value) ? value.filter(isStaticObject) : [];
288
- }
289
- function readRootObject(filePath, variableName) {
290
- const file = sourceFile(filePath);
291
- if (!file) return null;
292
- const context = buildStaticContext(file);
293
- const initializer = context.initializers.get(variableName);
294
- if (!initializer || ts.isFunctionDeclaration(initializer)) return null;
295
- const value = staticValue(initializer, context);
296
- return isStaticObject(value) ? value : null;
297
- }
298
- function readCallObjectArguments(filePath, calleeNames) {
299
- const file = sourceFile(filePath);
300
- if (!file) return [];
301
- const context = buildStaticContext(file);
302
- const result = [];
303
- const visit = (node) => {
304
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && calleeNames.has(node.expression.text)) {
305
- const firstArgument = node.arguments[0];
306
- const value = firstArgument ? staticValue(firstArgument, context) : void 0;
307
- if (isStaticObject(value)) result.push({ callee: node.expression.text, value });
308
- }
309
- node.forEachChild(visit);
310
- };
311
- file.forEachChild(visit);
312
- return result;
313
- }
314
- function sortHosts(hosts) {
315
- const sourceKey = (host) => host.source.kind === "fact-ref" ? `${host.source.factSection}:${host.source.factKey}` : `${host.source.path}:${host.source.symbol}`;
316
- return hosts.sort((left, right) => left.family.localeCompare(right.family) || left.id.localeCompare(right.id) || sourceKey(left).localeCompare(sourceKey(right)) || left.key.localeCompare(right.key));
317
- }
318
- function sortContributions(contributions) {
319
- const targetKey = (contribution) => contribution.targets.map((entry) => entry.id).join("\0");
320
- const sourceKey = (contribution) => `${contribution.source.path}:${contribution.source.symbol ?? ""}`;
321
- return contributions.sort((left, right) => left.kind.localeCompare(right.kind) || left.id.localeCompare(right.id) || targetKey(left).localeCompare(targetKey(right)) || sourceKey(left).localeCompare(sourceKey(right)));
322
- }
323
- function target(id, resolution = "unresolved") {
324
- return { id, resolution };
325
- }
326
- function factTarget(id, factSection, factKey = id) {
327
- return { id, resolution: "fact-ref", factRef: { factSection, factKey } };
328
- }
329
- function openTarget(id) {
330
- return target(id);
331
- }
332
- function declarationSource(sourceRoot, symbol) {
333
- return { kind: "declaration", path: path.posix.join(sourceRoot, "extension-points.ts"), symbol };
334
- }
335
- function hasDeclarationBinding(moduleRoot, hostKey, declaration) {
336
- const relativeSource = stringValue(declaration.source);
337
- if (!relativeSource) return false;
338
- const bindingFile = sourceFile(path.join(moduleRoot, relativeSource));
339
- if (!bindingFile) return false;
340
- const escapedHostKey = hostKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
341
- const bindingPattern = new RegExp(
342
- `extensionPoints\\s*\\.\\s*hosts(?:\\s*\\.\\s*${escapedHostKey}|\\s*\\[\\s*['"]${escapedHostKey}['"]\\s*\\])`
343
- );
344
- if (bindingPattern.test(bindingFile.text)) return true;
345
- return declaration.family === "integration" && typeof declaration.pattern === "string" && /resolveIntegrationDetailWidgetSpotId\s*\(/.test(bindingFile.text);
346
- }
347
- function baseHost(options) {
348
- const { declaration } = options;
349
- const aliases = strings(declaration.aliases);
350
- const fallbacks = strings(declaration.fallbacks);
351
- const fact = {
352
- key: options.key,
353
- id: options.id,
354
- resolution: options.resolution ?? (options.id.includes("{") || options.id.includes("*") ? "pattern" : "exact"),
355
- family: options.family,
356
- ownerModule: options.moduleId,
357
- capabilities: options.capabilities,
358
- bound: options.bound ?? true,
359
- stability: "frozen",
360
- source: declarationSource(options.sourceRoot, `extensionPoints.hosts.${options.key.split(".")[0]}`)
361
- };
362
- const contextContract = stringValue(declaration.contextContract);
363
- const dataContract = stringValue(declaration.dataContract);
364
- const scopeContract = stringValue(declaration.scopeContract);
365
- const runtimeContract = stringValue(declaration.runtimeContract);
366
- const activation = stringValue(declaration.activation);
367
- if (contextContract) fact.contextContract = contextContract;
368
- if (dataContract) fact.dataContract = dataContract;
369
- if (scopeContract) fact.scopeContract = scopeContract;
370
- if (runtimeContract) fact.runtimeContract = runtimeContract;
371
- if (activation) fact.activation = activation;
372
- if (aliases.length > 0) fact.aliases = aliases;
373
- if (fallbacks.length > 0) fact.fallbacks = fallbacks;
374
- return fact;
375
- }
376
- function extractDeclaredHosts(options) {
377
- const filePath = conventionPath(options.moduleRoot, "extension-points.ts");
378
- if (!filePath) return { hosts: [], unresolved: [] };
379
- const declaration = readRootObject(filePath, "extensionPoints");
380
- const hostsObject = declaration && isStaticObject(declaration.hosts) ? declaration.hosts : null;
381
- if (!hostsObject) {
382
- return {
383
- hosts: [],
384
- unresolved: [{
385
- key: `${options.moduleId}.extension-points`,
386
- source: { path: portablePath(options.moduleRoot, options.sourceRoot, filePath), symbol: "extensionPoints" },
387
- reason: "unclassified-binding"
388
- }]
389
- };
390
- }
391
- const hosts = [];
392
- const unresolved = [];
393
- for (const hostKey of Object.keys(hostsObject).sort((left, right) => left.localeCompare(right))) {
394
- const host = hostsObject[hostKey];
395
- if (!isStaticObject(host)) continue;
396
- const family = stringValue(host.family);
397
- if (!family) continue;
398
- const declarationBound = hasDeclarationBinding(options.moduleRoot, hostKey, host);
399
- if (!declarationBound) {
400
- unresolved.push({
401
- key: `${options.moduleId}.${hostKey}`,
402
- source: {
403
- path: stringValue(host.source) ?? portablePath(options.moduleRoot, options.sourceRoot, filePath),
404
- symbol: `extensionPoints.hosts.${hostKey}`
405
- },
406
- reason: "unbound-declaration"
407
- });
408
- }
409
- if (family === "data-table") {
410
- const tableId = stringValue(host.tableId);
411
- if (!tableId) continue;
412
- const baseSpotId = stringValue(host.baseSpotId) ?? `data-table:${tableId}`;
413
- for (const surface of DATA_TABLE_EXTENSION_SURFACES) {
414
- const usesBase = ["header", "footer", "toolbar", "searchTrailing", "emptyState"].includes(surface.key);
415
- const id2 = surface.key === "replacement" ? `data-table:${tableId}` : `${usesBase ? baseSpotId : `data-table:${tableId}`}:${surface.suffix}`;
416
- hosts.push(baseHost({
417
- key: `${hostKey}.${surface.key}`,
418
- id: id2,
419
- moduleId: options.moduleId,
420
- family,
421
- capabilities: [...surface.capabilities],
422
- sourceRoot: options.sourceRoot,
423
- declaration: host,
424
- bound: surface.bound && declarationBound
425
- }));
426
- }
427
- continue;
428
- }
429
- if (family === "crud-form") {
430
- const entityId = stringValue(host.entityId);
431
- if (!entityId) continue;
432
- const spotId = stringValue(host.spotId) ?? `crud-form:${entityId}`;
433
- for (const surface of CRUD_FORM_EXTENSION_SURFACES) {
434
- const id2 = surface.suffix ? `${spotId}:${surface.suffix}` : spotId;
435
- const fact2 = baseHost({
436
- key: `${hostKey}.${surface.key}`,
437
- id: id2,
438
- moduleId: options.moduleId,
439
- family,
440
- capabilities: [...surface.capabilities],
441
- sourceRoot: options.sourceRoot,
442
- declaration: host,
443
- bound: surface.bound && declarationBound
444
- });
445
- if (surface.key === "base") fact2.phases = [...CRUD_FORM_LIFECYCLE_PHASES];
446
- hosts.push(fact2);
447
- }
448
- continue;
449
- }
450
- const id = stringValue(host.spotId) ?? stringValue(host.pattern) ?? stringValue(host.componentId);
451
- if (!id) {
452
- unresolved.push({
453
- key: `${options.moduleId}.${hostKey}`,
454
- source: { path: portablePath(options.moduleRoot, options.sourceRoot, filePath), symbol: hostKey },
455
- reason: "dynamic-without-pattern"
456
- });
457
- continue;
458
- }
459
- const capabilities = family === "component-handle" ? ["component-replacement"] : strings(host.supported);
460
- const fact = baseHost({
461
- key: hostKey,
462
- id,
463
- moduleId: options.moduleId,
464
- family,
465
- capabilities,
466
- sourceRoot: options.sourceRoot,
467
- declaration: host,
468
- bound: declarationBound
469
- });
470
- if (isStaticObject(host.parameters)) {
471
- fact.patternParameters = Object.fromEntries(Object.entries(host.parameters).flatMap(([key, value]) => {
472
- if (!isStaticObject(value) || typeof value.source !== "string") return [];
473
- return [[key, {
474
- source: value.source,
475
- ...typeof value.pattern === "string" ? { pattern: value.pattern } : {}
476
- }]];
477
- }));
478
- }
479
- hosts.push(fact);
480
- }
481
- return { hosts: sortHosts(hosts), unresolved };
482
- }
483
- function factRefHost(options) {
484
- return {
485
- key: options.key,
486
- id: options.id,
487
- resolution: "fact-ref",
488
- family: options.family,
489
- ownerModule: options.moduleId,
490
- capabilities: options.capabilities,
491
- ...options.phases ? { phases: options.phases } : {},
492
- ...options.activation ? { activation: options.activation } : {},
493
- ...options.scopeContract ? { scopeContract: options.scopeContract } : {},
494
- bound: true,
495
- stability: "stable",
496
- source: { kind: "fact-ref", factSection: options.factSection, factKey: options.factKey ?? options.id }
497
- };
498
- }
499
- function sourceFilesBelow(directory) {
500
- const cached = activeExtractionCache?.sourceFilesBelow.get(directory);
501
- if (cached) return cached;
502
- if (!fs.existsSync(directory)) return [];
503
- const files = [];
504
- const visit = (current) => {
505
- for (const entry of fs.readdirSync(current, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
506
- const entryPath = path.join(current, entry.name);
507
- if (entry.isDirectory()) {
508
- if (entry.name !== "__tests__" && entry.name !== "__integration__") visit(entryPath);
509
- continue;
510
- }
511
- if (entry.isFile() && /\.(?:ts|tsx)$/.test(entry.name) && !/\.(?:test|spec)\./.test(entry.name)) files.push(entryPath);
512
- }
513
- };
514
- visit(directory);
515
- activeExtractionCache?.sourceFilesBelow.set(directory, files);
516
- return files;
517
- }
518
- function apiRouteId(moduleId, moduleRoot, filePath) {
519
- const relative = path.relative(path.join(moduleRoot, "api"), filePath).split(path.sep).join("/");
520
- if (relative === "interceptors.ts" || relative === "openapi.ts") return null;
521
- const withoutExtension = relative.replace(/\.tsx?$/, "");
522
- const suffix = withoutExtension.endsWith("/route") ? withoutExtension.slice(0, -6) : withoutExtension;
523
- return suffix && !suffix.includes("__tests__") ? `${moduleId.replace(/_/g, "-")}/${suffix}` : null;
524
- }
525
- function apiExtensionHostIds(moduleId, moduleRoot) {
526
- const cacheKey = `${moduleId}\0${moduleRoot}`;
527
- const cached = activeExtractionCache?.apiExtensionHostIds.get(cacheKey);
528
- if (cached) return cached;
529
- const entityIds = /* @__PURE__ */ new Set();
530
- const entitySourceFiles = {};
531
- const commandIds = /* @__PURE__ */ new Set();
532
- const routeIds = /* @__PURE__ */ new Set();
533
- for (const filePath of sourceFilesBelow(path.join(moduleRoot, "api"))) {
534
- const routeId = apiRouteId(moduleId, moduleRoot, filePath);
535
- if (routeId) routeIds.add(routeId);
536
- const file = sourceFile(filePath);
537
- if (!file) continue;
538
- const context = buildStaticContext(file);
539
- const visit = (node) => {
540
- if (ts.isPropertyAssignment(node)) {
541
- const name = propertyName(node.name);
542
- if (name === "commandId") {
543
- const id = stringValue(staticValue(node.initializer, context));
544
- if (id) commandIds.add(id);
545
- }
546
- if (name === "enrichers") {
547
- const config = staticValue(node.initializer, context);
548
- const entityId = isStaticObject(config) ? stringValue(config.entityId) : void 0;
549
- if (entityId) {
550
- entityIds.add(entityId);
551
- if (!entitySourceFiles[entityId]) entitySourceFiles[entityId] = filePath;
552
- }
553
- }
554
- }
555
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "validateCrudMutationGuard") {
556
- const input = node.arguments[1] ? staticValue(node.arguments[1], context) : void 0;
557
- const entityId = isStaticObject(input) ? stringValue(input.resourceKind) : void 0;
558
- if (entityId) {
559
- entityIds.add(entityId);
560
- if (!entitySourceFiles[entityId]) entitySourceFiles[entityId] = filePath;
561
- }
562
- }
563
- node.forEachChild(visit);
564
- };
565
- file.forEachChild(visit);
566
- }
567
- const result = {
568
- entityIds: [...entityIds].sort((left, right) => left.localeCompare(right)),
569
- entitySourceFiles,
570
- commandIds: [...commandIds].sort((left, right) => left.localeCompare(right)),
571
- routeIds: [...routeIds].sort((left, right) => left.localeCompare(right))
572
- };
573
- activeExtractionCache?.apiExtensionHostIds.set(cacheKey, result);
574
- return result;
575
- }
576
- function moduleCommandIds(moduleRoot, apiCommandIds) {
577
- const commandIds = new Set(apiCommandIds);
578
- for (const filePath of sourceFilesBelow(path.join(moduleRoot, "commands"))) {
579
- if (path.basename(filePath).replace(/\.(?:ts|tsx)$/, "") === "interceptors") continue;
580
- for (const id of extractCommandIdsFromSource(filePath)) commandIds.add(id);
581
- }
582
- return [...commandIds].sort((left, right) => left.localeCompare(right));
583
- }
584
- function extractKnownApiRouteIds(moduleId, moduleRoot) {
585
- return apiExtensionHostIds(moduleId, moduleRoot).routeIds;
586
- }
587
- function extractKnownCommandIds(moduleId, moduleRoot) {
588
- const apiHosts = apiExtensionHostIds(moduleId, moduleRoot);
589
- return moduleCommandIds(moduleRoot, apiHosts.commandIds);
590
- }
591
- const HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
592
- const API_INTERCEPTOR_BRIDGE_CALLS = {
593
- runApiInterceptorsBefore: "before",
594
- runApiInterceptorsAfter: "after"
595
- };
596
- function isHttpMethodName(value) {
597
- return HTTP_METHODS.includes(value);
598
- }
599
- function exportedHttpMethods(file) {
600
- const methods = /* @__PURE__ */ new Set();
601
- const consider = (name) => {
602
- if (name && isHttpMethodName(name)) methods.add(name);
603
- };
604
- const considerBindingName = (name) => {
605
- if (ts.isIdentifier(name)) {
606
- consider(name.text);
607
- return;
608
- }
609
- for (const element of name.elements) {
610
- if (ts.isBindingElement(element)) considerBindingName(element.name);
611
- }
612
- };
613
- const visit = (node) => {
614
- if (ts.isVariableStatement(node) && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
615
- for (const declaration of node.declarationList.declarations) {
616
- considerBindingName(declaration.name);
617
- }
618
- }
619
- if (ts.isFunctionDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
620
- consider(node.name.text);
621
- }
622
- if (ts.isExportDeclaration(node) && node.exportClause && ts.isNamedExports(node.exportClause)) {
623
- for (const element of node.exportClause.elements) consider(element.name.text);
624
- }
625
- node.forEachChild(visit);
626
- };
627
- file.forEachChild(visit);
628
- return [...methods].sort((left, right) => left.localeCompare(right));
629
- }
630
- function extractApiRouteInterceptorBridges(file, context) {
631
- const exportedMethods = exportedHttpMethods(file);
632
- const phasesByMethod = /* @__PURE__ */ new Map();
633
- const addPhase = (method, phase) => {
634
- const phases = phasesByMethod.get(method) ?? /* @__PURE__ */ new Set();
635
- phases.add(phase);
636
- phasesByMethod.set(method, phases);
637
- };
638
- const visit = (node) => {
639
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
640
- const calleeName = node.expression.text;
641
- if (calleeName === "makeCrudRoute") {
642
- for (const method of exportedMethods) {
643
- addPhase(method, "before");
644
- addPhase(method, "after");
645
- }
646
- }
647
- const phase = API_INTERCEPTOR_BRIDGE_CALLS[calleeName];
648
- if (phase) {
649
- const callOptions = node.arguments[0] ? staticValue(node.arguments[0], context) : void 0;
650
- const declaredMethod = isStaticObject(callOptions) ? stringValue(callOptions.method) : void 0;
651
- const methods = declaredMethod && isHttpMethodName(declaredMethod) ? [declaredMethod] : exportedMethods;
652
- for (const method of methods) addPhase(method, phase);
653
- }
654
- }
655
- node.forEachChild(visit);
656
- };
657
- file.forEachChild(visit);
658
- return [...phasesByMethod.entries()].map(([method, phases]) => ({
659
- method,
660
- phases: [...phases].sort((left, right) => left.localeCompare(right))
661
- })).sort((left, right) => left.method.localeCompare(right.method));
662
- }
663
- function extractActivationTargetOwners(options) {
664
- const apiRoutes = [];
665
- for (const filePath of sourceFilesBelow(path.join(options.moduleRoot, "api"))) {
666
- const routeId = apiRouteId(options.moduleId, options.moduleRoot, filePath);
667
- if (!routeId) continue;
668
- const file = sourceFile(filePath);
669
- const bridges = file ? extractApiRouteInterceptorBridges(file, buildStaticContext(file)) : [];
670
- apiRoutes.push({
671
- id: routeId,
672
- source: { sourcePath: portablePath(options.moduleRoot, options.sourceRoot, filePath) },
673
- bridges
674
- });
675
- }
676
- const commands = [];
677
- const seenCommands = /* @__PURE__ */ new Set();
678
- for (const filePath of sourceFilesBelow(path.join(options.moduleRoot, "commands"))) {
679
- if (path.basename(filePath).replace(/\.(?:ts|tsx)$/, "") === "interceptors") continue;
680
- const source = { sourcePath: portablePath(options.moduleRoot, options.sourceRoot, filePath) };
681
- for (const id of extractCommandIdsFromSource(filePath)) {
682
- if (seenCommands.has(id)) continue;
683
- seenCommands.add(id);
684
- commands.push({ id, source });
685
- }
686
- }
687
- return { apiRoutes, commands };
688
- }
689
- function extractFactRefHosts(options) {
690
- const hosts = [];
691
- for (const entity of options.entities) {
692
- hosts.push(factRefHost({
693
- key: `entity.${entity.id}`,
694
- id: entity.id,
695
- moduleId: options.moduleId,
696
- family: "entity",
697
- capabilities: ["response-enricher", "query-enricher", "mutation-guard", "entity-extension"],
698
- factSection: "entities",
699
- activation: "host-opt-in",
700
- scopeContract: "tenant-and-organization"
701
- }));
702
- }
703
- for (const route of options.apiRoutes) {
704
- hosts.push(factRefHost({
705
- key: `api-route.${route.path}`,
706
- id: route.path,
707
- moduleId: options.moduleId,
708
- family: "api-route",
709
- capabilities: ["api-interceptor", "mutation-guard"],
710
- factSection: "apiRoutes",
711
- phases: ["before", "after"],
712
- activation: "host-opt-in",
713
- scopeContract: "request-auth-scope"
714
- }));
715
- }
716
- for (const event of options.events) {
717
- const capabilities = ["async-subscriber", "sync-subscriber"];
718
- if (event.clientBroadcast) capabilities.push("browser-client");
719
- if (event.portalBroadcast) capabilities.push("browser-portal");
720
- hosts.push(factRefHost({
721
- key: `event.${event.id}`,
722
- id: event.id,
723
- moduleId: options.moduleId,
724
- family: "event",
725
- capabilities,
726
- factSection: "events",
727
- scopeContract: "tenant-organization-and-audience"
728
- }));
729
- }
730
- for (const entityId of options.searchEntities) {
731
- const eventStem = entityId.replace(":", ".");
732
- for (const phase of ["querying", "queried"]) {
733
- hosts.push(factRefHost({
734
- key: `query-lifecycle.${eventStem}.${phase}`,
735
- id: `${eventStem}.${phase}`,
736
- moduleId: options.moduleId,
737
- family: "query-lifecycle",
738
- capabilities: ["sync-subscriber"],
739
- factSection: "searchEntities",
740
- factKey: entityId,
741
- phases: phase === "querying" ? ["block", "query-transform"] : ["result-transform", "scope-reapply"],
742
- activation: "caller-opt-in",
743
- scopeContract: "tenant-and-organization-reapplied-after-result"
744
- }));
745
- }
746
- }
747
- const apiHosts = apiExtensionHostIds(options.moduleId, options.moduleRoot);
748
- for (const entityId of apiHosts.entityIds) {
749
- const declaringFile = apiHosts.entitySourceFiles[entityId];
750
- const host = factRefHost({
751
- key: `api-entity.${entityId}`,
752
- id: entityId,
753
- moduleId: options.moduleId,
754
- family: "entity",
755
- capabilities: ["response-enricher", "query-enricher", "mutation-guard"],
756
- factSection: "apiRoutes",
757
- activation: "host-opt-in",
758
- scopeContract: "tenant-and-organization"
759
- });
760
- hosts.push(declaringFile ? {
761
- ...host,
762
- source: {
763
- kind: "declaration",
764
- path: portablePath(options.moduleRoot, options.sourceRoot, declaringFile),
765
- symbol: entityId
766
- }
767
- } : host);
768
- }
769
- return sortHosts([...new Map(hosts.map((host) => [`${host.family}:${host.id}`, host])).values()]);
770
- }
771
- function contributionBase(id, sourcePath, sourceSymbol) {
772
- return {
773
- id,
774
- targets: [],
775
- scopeContract: "tenant-and-organization",
776
- source: { path: sourcePath, ...sourceSymbol ? { symbol: sourceSymbol } : {} }
777
- };
778
- }
779
- function extractInjectionTable(options) {
780
- const filePath = conventionPath(options.moduleRoot, "widgets/injection-table.ts");
781
- if (!filePath) return [];
782
- const table = readRootObject(filePath, "injectionTable");
783
- if (!table) return [];
784
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, filePath);
785
- const facts = [];
786
- for (const targetId of Object.keys(table).sort((left, right) => left.localeCompare(right))) {
787
- const entries = table[targetId];
788
- if (!Array.isArray(entries)) continue;
789
- for (const entry of entries) {
790
- if (!isStaticObject(entry)) continue;
791
- const widgetId = stringValue(entry.widgetId);
792
- if (!widgetId) continue;
793
- const payload = targetId.endsWith(":columns") ? "column" : targetId.endsWith(":row-actions") ? "row-action" : targetId.endsWith(":bulk-actions") ? "bulk-action" : targetId.endsWith(":filters") ? "filter" : targetId.endsWith(":fields") ? "field" : "render";
794
- const base = contributionBase(`${widgetId}@${targetId}`, sourcePath, "injectionTable");
795
- const shared = {
796
- ...base,
797
- targets: [target(targetId)],
798
- features: strings(entry.features),
799
- placement: numberValue(entry.priority) !== void 0 ? { priority: numberValue(entry.priority) } : void 0
800
- };
801
- if (targetId.startsWith("data-table:")) {
802
- facts.push({
803
- ...shared,
804
- kind: "data-table",
805
- details: {
806
- payload: payload === "field" ? "render" : payload,
807
- tableId: targetId.replace(/^data-table:/, "").replace(/:(?:columns|row-actions|bulk-actions|filters|toolbar|header|footer|search-trailing)$/, ""),
808
- executionGuard: strings(entry.features).length > 0 ? "both" : "host"
809
- }
810
- });
811
- } else if (targetId.startsWith("crud-form:")) {
812
- facts.push({
813
- ...shared,
814
- kind: "crud-form",
815
- details: {
816
- payload: payload === "field" ? "field" : "render",
817
- entityId: targetId.replace(/^crud-form:/, "").replace(/:(?:fields|header)$/, ""),
818
- requestHeaderCapability: payload === "field"
819
- }
820
- });
821
- } else {
822
- facts.push({
823
- ...shared,
824
- kind: "widget",
825
- details: {
826
- payload: "render",
827
- registryKey: widgetId,
828
- executionGuard: strings(entry.features).length > 0 ? "both" : "host"
829
- }
830
- });
831
- }
832
- }
833
- }
834
- return facts;
835
- }
836
- function extractObjectConvention(options) {
837
- const filePath = conventionPath(options.module.moduleRoot, options.relativePath);
838
- if (!filePath) return [];
839
- const exportNames = [options.exportName, ...options.exportAliases ?? []];
840
- const entries = exportNames.reduce((found, exportName) => found.length > 0 ? found : readConventionObjectArray(filePath, exportName), []);
841
- const sourcePath = portablePath(options.module.moduleRoot, options.module.sourceRoot, filePath);
842
- return entries.flatMap((entry, index) => options.build(entry, sourcePath, index) ?? []);
843
- }
844
- function methodPhases(entry, map) {
845
- return map.flatMap(([property, phase]) => entry[property] === true ? [phase] : []);
846
- }
847
- function extractEnrichers(options) {
848
- return extractObjectConvention({
849
- module: options,
850
- relativePath: "data/enrichers.ts",
851
- exportName: "enrichers",
852
- build(entry, sourcePath, index) {
853
- const id = stringValue(entry.id) ?? `${options.moduleId}.enricher.${index}`;
854
- const targetEntity = stringValue(entry.targetEntity);
855
- if (!targetEntity) return null;
856
- const timeoutMs = numberValue(entry.timeout) ?? 2e3;
857
- const queryEngineConfig = isStaticObject(entry.queryEngine) ? entry.queryEngine : null;
858
- const queryEngine = queryEngineConfig && booleanValue(queryEngineConfig.enabled) === true ? queryEngineConfig : null;
859
- const surfaces = [entry.enrichMany === true ? "list" : null, entry.enrichOne === true ? "detail" : null].filter((value) => value !== null);
860
- const base = contributionBase(id, sourcePath, id);
861
- return {
862
- ...base,
863
- kind: "response-enricher",
864
- targets: [openTarget(targetEntity)],
865
- features: strings(entry.features),
866
- phases: surfaces,
867
- activation: queryEngine ? "caller-opt-in" : "host-opt-in",
868
- roundTripId: `${targetEntity}:read`,
869
- details: {
870
- targetEntity,
871
- surfaces,
872
- timeoutMs,
873
- fallback: entry.fallback === void 0 ? "none" : "configured",
874
- critical: booleanValue(entry.critical) ?? false,
875
- cachePosture: "rerun-on-list-cache-hit",
876
- ...queryEngine ? { queryEngine: {
877
- engines: strings(queryEngine.engines),
878
- applyOn: (strings(queryEngine.applyOn).length > 0 ? strings(queryEngine.applyOn) : ["list", "detail"]).filter((value) => value === "list" || value === "detail"),
879
- activation: "caller-opt-in"
880
- } } : {}
881
- }
882
- };
883
- }
884
- });
885
- }
886
- function extractApiInterceptors(options) {
887
- return extractObjectConvention({
888
- module: options,
889
- relativePath: "api/interceptors.ts",
890
- exportName: "interceptors",
891
- build(entry, sourcePath, index) {
892
- const id = stringValue(entry.id) ?? `${options.moduleId}.api-interceptor.${index}`;
893
- const targetRoute = stringValue(entry.targetRoute);
894
- if (!targetRoute) return null;
895
- const phases = methodPhases(entry, [["before", "before"], ["after", "after"]]).filter((phase) => phase === "before" || phase === "after");
896
- const methods = strings(entry.methods);
897
- const base = contributionBase(id, sourcePath, id);
898
- return {
899
- ...base,
900
- kind: "api-interceptor",
901
- targets: [openTarget(targetRoute)],
902
- phases,
903
- features: strings(entry.features),
904
- details: {
905
- route: targetRoute,
906
- methods,
907
- phases,
908
- activation: targetRoute.startsWith("/") ? "custom-route-bridge" : "crud-pipeline",
909
- timeoutMs: numberValue(entry.timeout) ?? 2e3,
910
- failurePosture: booleanValue(entry.critical) ? "fail-closed" : "fallback"
911
- }
912
- };
913
- }
914
- });
915
- }
916
- function extractCommandInterceptors(options) {
917
- return extractObjectConvention({
918
- module: options,
919
- relativePath: "commands/interceptors.ts",
920
- exportName: "interceptors",
921
- build(entry, sourcePath, index) {
922
- const id = stringValue(entry.id) ?? `${options.moduleId}.command-interceptor.${index}`;
923
- const targetCommand = stringValue(entry.targetCommand);
924
- if (!targetCommand) return null;
925
- const phases = methodPhases(entry, [
926
- ["beforeExecute", "before-execute"],
927
- ["afterExecute", "after-execute"],
928
- ["beforeUndo", "before-undo"],
929
- ["afterUndo", "after-undo"]
930
- ]).filter((phase) => phase === "before-execute" || phase === "after-execute" || phase === "before-undo" || phase === "after-undo");
931
- const base = contributionBase(id, sourcePath, id);
932
- return {
933
- ...base,
934
- kind: "command-interceptor",
935
- targets: [openTarget(targetCommand)],
936
- phases,
937
- features: strings(entry.features),
938
- details: { targetCommand, phases }
939
- };
940
- }
941
- });
942
- }
943
- function extractGuards(options) {
944
- return extractObjectConvention({
945
- module: options,
946
- relativePath: "data/guards.ts",
947
- exportName: "guards",
948
- build(entry, sourcePath, index) {
949
- const id = stringValue(entry.id) ?? `${options.moduleId}.guard.${index}`;
950
- const targetEntity = stringValue(entry.targetEntity);
951
- if (!targetEntity) return null;
952
- const operations = strings(entry.operations).filter((operation) => operation === "create" || operation === "update" || operation === "delete");
953
- const capabilities = [entry.validate === true ? "block" : null, entry.validate === true ? "rewrite" : null, entry.afterSuccess === true ? "after-success" : null].filter((value) => value !== null);
954
- const base = contributionBase(id, sourcePath, id);
955
- return {
956
- ...base,
957
- kind: "mutation-guard",
958
- targets: [openTarget(targetEntity)],
959
- operations,
960
- features: strings(entry.features),
961
- roundTripId: `${targetEntity}:write`,
962
- details: { entityId: targetEntity, operations, capabilities, optimisticLock: "preserved" }
963
- };
964
- }
965
- });
966
- }
967
- function extractEntityExtensions(options) {
968
- return extractObjectConvention({
969
- module: options,
970
- relativePath: "data/extensions.ts",
971
- exportName: "entityExtensions",
972
- exportAliases: ["extensions"],
973
- build(entry, sourcePath, index) {
974
- const baseEntity = stringValue(entry.base);
975
- const extensionEntity = stringValue(entry.extension);
976
- const join = isStaticObject(entry.join) ? entry.join : null;
977
- if (!baseEntity || !extensionEntity || !join) return null;
978
- const id = `${options.moduleId}.entity-extension.${index}:${baseEntity}->${extensionEntity}`;
979
- const contribution = contributionBase(id, sourcePath, "extensions");
980
- return {
981
- ...contribution,
982
- kind: "entity-extension",
983
- targets: [openTarget(baseEntity)],
984
- details: {
985
- hostEntityId: baseEntity,
986
- extensionEntityId: extensionEntity,
987
- linkId: `${stringValue(join.baseKey) ?? "id"}:${stringValue(join.extensionKey) ?? "id"}`,
988
- scopeContract: "tenant-and-organization",
989
- orphanContract: booleanValue(entry.required) ? "required" : "optional"
990
- }
991
- };
992
- }
993
- });
994
- }
995
- function extractSubscribers(options) {
996
- const directory = path.join(options.moduleRoot, "subscribers");
997
- if (!fs.existsSync(directory)) return [];
998
- const facts = [];
999
- for (const filePath of sourceFilesBelow(directory)) {
1000
- const metadata = readRootObject(filePath, "metadata");
1001
- if (!metadata) continue;
1002
- const event = stringValue(metadata.event);
1003
- if (!event) continue;
1004
- const relativeStem = path.relative(directory, filePath).replace(/\.tsx?$/, "").split(path.sep).join("/");
1005
- const subscriberId = stringValue(metadata.id) ?? `${options.moduleId}:${relativeStem}`;
1006
- const persistent = booleanValue(metadata.persistent) ?? false;
1007
- const sync = booleanValue(metadata.sync) ?? !persistent;
1008
- const contribution = contributionBase(subscriberId, portablePath(options.moduleRoot, options.sourceRoot, filePath), "metadata");
1009
- facts.push({
1010
- ...contribution,
1011
- kind: "subscriber",
1012
- targets: [openTarget(event)],
1013
- phases: sync ? ["before-or-after"] : ["async-delivery"],
1014
- details: {
1015
- event,
1016
- subscriberId,
1017
- persistent,
1018
- sync,
1019
- ...numberValue(metadata.priority) !== void 0 ? { priority: numberValue(metadata.priority) } : {}
1020
- }
1021
- });
1022
- }
1023
- return facts;
1024
- }
1025
- function extractBrowserReactions(options) {
1026
- return options.events.flatMap((event) => {
1027
- const transports = [event.clientBroadcast ? "client" : null, event.portalBroadcast ? "portal" : null].filter((value) => value !== null);
1028
- if (transports.length === 0) return [];
1029
- const contribution = contributionBase(`${event.id}.browser`, path.posix.join(options.sourceRoot, "events.ts"), "events");
1030
- return [{
1031
- ...contribution,
1032
- kind: "browser-reaction",
1033
- targets: [factTarget(event.id, "events")],
1034
- details: {
1035
- transports,
1036
- hooks: transports.flatMap((transport) => transport === "client" ? ["useAppEvent", "useOperationProgress"] : ["usePortalAppEvent"]),
1037
- audienceScopeContract: "tenant-organization-user-role-and-customer"
1038
- }
1039
- }];
1040
- });
1041
- }
1042
- function extractNotificationReactions(options) {
1043
- return extractObjectConvention({
1044
- module: options,
1045
- relativePath: "notifications.handlers.ts",
1046
- exportName: "notificationHandlers",
1047
- build(entry, sourcePath, index) {
1048
- const notificationType = stringValue(entry.notificationType);
1049
- if (!notificationType) return null;
1050
- const declaredId = stringValue(entry.id);
1051
- const id = declaredId ?? `${options.moduleId}.notification-handler.${index}`;
1052
- const contribution = contributionBase(id, sourcePath, "notificationHandlers");
1053
- return {
1054
- ...contribution,
1055
- kind: "browser-reaction",
1056
- targets: [factTarget(notificationType, "notifications")],
1057
- features: strings(entry.features),
1058
- placement: numberValue(entry.priority) !== void 0 ? { priority: numberValue(entry.priority) } : void 0,
1059
- details: {
1060
- transports: ["notification-effect"],
1061
- hooks: ["useNotificationEffect"],
1062
- audienceScopeContract: "tenant-organization-user-role-and-customer",
1063
- ...declaredId ? { overrideKey: declaredId } : {}
1064
- }
1065
- };
1066
- }
1067
- });
1068
- }
1069
- function extractComponentOverrides(options) {
1070
- return extractObjectConvention({
1071
- module: options,
1072
- relativePath: "widgets/components.ts",
1073
- exportName: "componentOverrides",
1074
- build(entry, sourcePath, index) {
1075
- const targetDefinition = isStaticObject(entry.target) ? entry.target : null;
1076
- const handle = targetDefinition ? stringValue(targetDefinition.componentId) : void 0;
1077
- if (!handle) return null;
1078
- const mode = entry.wrapper !== void 0 ? "wrapper" : entry.props !== void 0 ? "props" : "replace";
1079
- const id = `${options.moduleId}.component-override.${index}:${handle}`;
1080
- const contribution = contributionBase(id, sourcePath, "componentOverrides");
1081
- return {
1082
- ...contribution,
1083
- kind: "component-override",
1084
- targets: [target(handle)],
1085
- details: {
1086
- handle,
1087
- mode,
1088
- propsContract: stringValue(entry.propsContract) ?? "component-props-schema"
1089
- }
1090
- };
1091
- }
1092
- });
1093
- }
1094
- function extractSpecializedRegistries(options) {
1095
- const facts = [];
1096
- const add = (id, registry, sourcePath, specialistRoute, symbol = id) => {
1097
- const contributionId = `${registry}:${id}`;
1098
- const contribution = contributionBase(contributionId, sourcePath, id);
1099
- const fact = {
1100
- ...contribution,
1101
- kind: "specialized-registry",
1102
- targets: [factTarget(id, specialistRoute)],
1103
- source: { path: sourcePath, symbol },
1104
- details: { registry, registryId: id, specialistRoute }
1105
- };
1106
- const existingIndex = facts.findIndex((entry) => entry.id === contributionId);
1107
- if (existingIndex >= 0) facts[existingIndex] = fact;
1108
- else facts.push(fact);
1109
- };
1110
- for (const id of options.notifications ?? []) add(id, "notification", path.posix.join(options.sourceRoot, "notifications.ts"), "notifications");
1111
- for (const id of options.searchEntities) add(id, "search", path.posix.join(options.sourceRoot, "search.ts"), "search");
1112
- for (const tool of options.aiTools ?? []) add(tool.name, "ai", tool.sourcePath, "aiTools");
1113
- for (const agent of options.aiAgents ?? []) add(agent.id, "ai", agent.sourcePath, "aiAgents");
1114
- const vectorPath = conventionPath(options.moduleRoot, "vector.ts");
1115
- if (vectorPath) {
1116
- const vectorConfig = readRootObject(vectorPath, "vectorConfig") ?? readRootObject(vectorPath, "config");
1117
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, vectorPath);
1118
- if (vectorConfig && Array.isArray(vectorConfig.entities)) {
1119
- for (const entity of vectorConfig.entities) {
1120
- if (!isStaticObject(entity)) continue;
1121
- const entityId = stringValue(entity.entityId);
1122
- if (entityId) add(entityId, "vector", sourcePath, "vector", "vectorConfig");
1123
- }
1124
- }
1125
- }
1126
- const integrationPath = conventionPath(options.moduleRoot, "integration.ts");
1127
- if (integrationPath) {
1128
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, integrationPath);
1129
- const addIntegration = (integration, symbol, bundleId) => {
1130
- const integrationId = stringValue(integration.id);
1131
- if (integrationId) {
1132
- add(integrationId, "integration", sourcePath, "integrations", bundleId ? `${symbol}[${bundleId}]` : symbol);
1133
- }
1134
- const providerKey = stringValue(integration.providerKey);
1135
- const category = stringValue(integration.category);
1136
- const categoryRegistry = category === "payment" ? "payment" : category === "shipping" ? "shipping" : category === "currency" ? "currency" : null;
1137
- if (providerKey && categoryRegistry) {
1138
- const specialistRoute = categoryRegistry === "payment" ? "paymentGateways" : categoryRegistry === "shipping" ? "shippingCarriers" : "currencies";
1139
- add(providerKey, categoryRegistry, sourcePath, specialistRoute, `${symbol}.providerKey`);
1140
- }
1141
- };
1142
- const singular = readRootObject(integrationPath, "integration");
1143
- if (singular) addIntegration(singular, "integration");
1144
- for (const integration of readConventionObjectArray(integrationPath, "integrations")) {
1145
- addIntegration(integration, "integrations");
1146
- }
1147
- const bundle = readRootObject(integrationPath, "integrationBundle") ?? readRootObject(integrationPath, "bundle");
1148
- if (bundle) {
1149
- const bundleId = stringValue(bundle.id) ?? "bundle";
1150
- const members = Array.isArray(bundle.integrations) ? bundle.integrations : [];
1151
- for (const member of members) {
1152
- if (isStaticObject(member)) addIntegration(member, "integrationBundle", bundleId);
1153
- }
1154
- }
1155
- }
1156
- const workflowsPath = conventionPath(options.moduleRoot, "workflows.ts");
1157
- if (workflowsPath) {
1158
- const config = readRootObject(workflowsPath, "workflowsConfig");
1159
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, workflowsPath);
1160
- if (config && Array.isArray(config.workflows)) {
1161
- for (const workflow of config.workflows) {
1162
- if (!isStaticObject(workflow)) continue;
1163
- const workflowId = stringValue(workflow.workflowId);
1164
- if (workflowId) add(workflowId, "workflow", sourcePath, "workflows", "workflowsConfig");
1165
- }
1166
- }
1167
- }
1168
- const diPath = conventionPath(options.moduleRoot, "di.ts");
1169
- if (diPath) {
1170
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, diPath);
1171
- const registrations = readCallObjectArguments(diPath, /* @__PURE__ */ new Set([
1172
- "registerPaymentGatewayDescriptor",
1173
- "registerShippingAdapter",
1174
- "registerCurrencyProvider"
1175
- ]));
1176
- for (const registration of registrations) {
1177
- const registry = registration.callee === "registerPaymentGatewayDescriptor" ? "payment" : registration.callee === "registerShippingAdapter" ? "shipping" : "currency";
1178
- const registryId = stringValue(registration.value.providerKey) ?? stringValue(registration.value.key) ?? stringValue(registration.value.id);
1179
- if (!registryId) continue;
1180
- const specialistRoute = registry === "payment" ? "paymentGateways" : registry === "shipping" ? "shippingCarriers" : "currencies";
1181
- add(registryId, registry, sourcePath, specialistRoute, registration.callee);
1182
- }
1183
- }
1184
- const dashboardRoots = { appBase: path.join(options.moduleRoot, "__app__"), pkgBase: options.moduleRoot };
1185
- for (const widgetFile of scanModuleDir(dashboardRoots, SCAN_CONFIGS.dashboardWidgets)) {
1186
- const filePath = path.join(options.moduleRoot, "widgets", "dashboard", widgetFile.relPath);
1187
- const widget = readRootObject(filePath, "widget");
1188
- const metadata = widget && isStaticObject(widget.metadata) ? widget.metadata : null;
1189
- if (!metadata) continue;
1190
- const widgetId = stringValue(metadata.id);
1191
- if (!widgetId) continue;
1192
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, filePath);
1193
- const contribution = contributionBase(`dashboard:${widgetId}`, sourcePath, "widget.metadata");
1194
- facts.push({
1195
- ...contribution,
1196
- kind: "widget",
1197
- targets: [target(`dashboard:${widgetId}`)],
1198
- features: strings(metadata.features),
1199
- details: {
1200
- payload: "dashboard",
1201
- registryKey: widgetId,
1202
- executionGuard: strings(metadata.features).length > 0 ? "both" : "host"
1203
- }
1204
- });
1205
- }
1206
- return facts;
1207
- }
1208
- const ACTIVATION_ADAPTERS = {
1209
- "crud-response-enricher": { contributionKinds: ["response-enricher"], mode: "call-site-object" },
1210
- "query-enricher": { contributionKinds: ["response-enricher"], mode: "call-site-object" },
1211
- "mutation-guard": { contributionKinds: ["mutation-guard"], mode: "call-site-object" },
1212
- "api-interceptor-bridge": { contributionKinds: ["api-interceptor"], mode: "host-reference" },
1213
- "command-interceptor-bridge": { contributionKinds: ["command-interceptor"], mode: "owner-reference" },
1214
- "widget-injection-consumer": { contributionKinds: ["widget", "data-table", "crud-form"], mode: "host-reference" },
1215
- "component-extension-consumer": { contributionKinds: ["component-override"], mode: "host-reference" },
1216
- "dashboard-host-consumer": { contributionKinds: ["widget"], mode: "host-reference" }
1217
- };
1218
- const CONTRIBUTION_ACTIVATION_CLASSIFICATION = {
1219
- "response-enricher": ["crud-response-enricher", "query-enricher"],
1220
- "mutation-guard": ["mutation-guard"],
1221
- "api-interceptor": ["api-interceptor-bridge"],
1222
- "command-interceptor": ["command-interceptor-bridge"],
1223
- "widget": ["widget-injection-consumer", "dashboard-host-consumer"],
1224
- "data-table": ["widget-injection-consumer"],
1225
- "crud-form": ["widget-injection-consumer"],
1226
- "component-override": ["component-extension-consumer"],
1227
- "entity-extension": "capability-only",
1228
- "subscriber": "capability-only",
1229
- "browser-reaction": "capability-only",
1230
- "specialized-registry": "capability-only",
1231
- "module-override": "capability-only"
1232
- };
1233
- const ALL_ACTIVATION_KINDS = Object.keys(ACTIVATION_ADAPTERS);
1234
- const ALL_CONTRIBUTION_KINDS = Object.keys(CONTRIBUTION_ACTIVATION_CLASSIFICATION);
1235
- const MUTATION_GUARD_BRIDGE_ADAPTERS = {
1236
- runRouteMutationGuards: { resourceArgument: "input-property" },
1237
- validateCrudMutationGuard: { resourceArgument: "any-argument" },
1238
- runMutationGuards: { resourceArgument: "any-argument" }
1239
- };
1240
- const MUTATION_GUARD_SOURCE_DIRECTORIES = ["api", "lib"];
1241
- const MUTATION_GUARD_OPERATIONS = /* @__PURE__ */ new Set(["create", "update", "delete", "custom"]);
1242
- function toRegistryGuardOperation(operation) {
1243
- return operation === "custom" ? "update" : operation;
1244
- }
1245
- function readMutationGuardBridge(node, context) {
1246
- const callee = node.expression;
1247
- const calleeName = ts.isIdentifier(callee) ? callee.text : ts.isPropertyAccessExpression(callee) ? callee.name.text : null;
1248
- const adapter = calleeName ? MUTATION_GUARD_BRIDGE_ADAPTERS[calleeName] : void 0;
1249
- if (!adapter) return null;
1250
- const argumentObjects = node.arguments.map((argument) => staticValue(argument, context)).filter(isStaticObject);
1251
- const resourceObjects = adapter.resourceArgument === "input-property" ? argumentObjects.flatMap((argumentObject) => isStaticObject(argumentObject.input) ? [argumentObject.input] : []) : argumentObjects;
1252
- for (const resourceObject of resourceObjects) {
1253
- const entityId = stringValue(resourceObject.resourceKind) ?? stringValue(resourceObject.entityId);
1254
- if (!entityId) continue;
1255
- const declaredOperation = stringValue(resourceObject.operation);
1256
- const operations = declaredOperation && MUTATION_GUARD_OPERATIONS.has(declaredOperation) ? [toRegistryGuardOperation(declaredOperation)] : [];
1257
- return { entityId, operations };
1258
- }
1259
- return null;
1260
- }
1261
- function nodeLine(file, node) {
1262
- return file.getLineAndCharacterOfPosition(node.getStart(file)).line + 1;
1263
- }
1264
- function activationId(host, kind) {
1265
- const method = host.method ? `:${host.method}` : "";
1266
- return `${host.kind}:${host.id}${method}:${kind}`;
1267
- }
1268
- function sortActivations(activations) {
1269
- return [...activations].sort((left, right) => left.id.localeCompare(right.id));
1270
- }
1271
- function isQueryWithExtensionsCall(node, context) {
1272
- if (!ts.isCallExpression(node)) return false;
1273
- const callee = node.expression;
1274
- const calleeName = ts.isPropertyAccessExpression(callee) ? callee.name.text : ts.isIdentifier(callee) ? callee.text : null;
1275
- if (calleeName !== "query") return false;
1276
- const queryOptions = node.arguments[1] ? staticValue(node.arguments[1], context) : void 0;
1277
- return isStaticObject(queryOptions) && queryOptions.extensions !== void 0;
1278
- }
1279
- function extractCallSiteActivations(options) {
1280
- const activations = [];
1281
- const byId = /* @__PURE__ */ new Map();
1282
- const push = (activation) => {
1283
- const existing = byId.get(activation.id);
1284
- if (existing) {
1285
- if (!existing.operations || !activation.operations) {
1286
- delete existing.operations;
1287
- } else {
1288
- existing.operations = [.../* @__PURE__ */ new Set([...existing.operations, ...activation.operations])].sort((left, right) => left.localeCompare(right));
1289
- }
1290
- return;
1291
- }
1292
- byId.set(activation.id, activation);
1293
- activations.push(activation);
1294
- };
1295
- const scannedFiles = MUTATION_GUARD_SOURCE_DIRECTORIES.flatMap((directory) => sourceFilesBelow(path.join(options.moduleRoot, directory)));
1296
- for (const filePath of scannedFiles) {
1297
- const file = sourceFile(filePath);
1298
- if (!file) continue;
1299
- const context = buildStaticContext(file);
1300
- const sourcePath = portablePath(options.moduleRoot, options.sourceRoot, filePath);
1301
- const visit = (node) => {
1302
- if (ts.isPropertyAssignment(node) && propertyName(node.name) === "enrichers") {
1303
- const config = staticValue(node.initializer, context);
1304
- const entityId = isStaticObject(config) ? stringValue(config.entityId) : void 0;
1305
- if (entityId) {
1306
- const host = { kind: "entity", id: entityId, moduleId: options.moduleId };
1307
- push({
1308
- id: activationId(host, "crud-response-enricher"),
1309
- kind: "crud-response-enricher",
1310
- host,
1311
- contributionKinds: ["response-enricher"],
1312
- source: { sourcePath, line: nodeLine(file, node) }
1313
- });
1314
- }
1315
- }
1316
- if (isQueryWithExtensionsCall(node, context)) {
1317
- const entityId = stringValue(staticValue(node.arguments[0], context));
1318
- if (entityId) {
1319
- const host = { kind: "entity", id: entityId, moduleId: options.moduleId };
1320
- push({
1321
- id: activationId(host, "query-enricher"),
1322
- kind: "query-enricher",
1323
- host,
1324
- contributionKinds: ["response-enricher"],
1325
- source: { sourcePath, line: nodeLine(file, node) }
1326
- });
1327
- }
1328
- }
1329
- if (ts.isCallExpression(node)) {
1330
- const bridge = readMutationGuardBridge(node, context);
1331
- if (bridge) {
1332
- const host = { kind: "entity", id: bridge.entityId, moduleId: options.moduleId };
1333
- push({
1334
- id: activationId(host, "mutation-guard"),
1335
- kind: "mutation-guard",
1336
- host,
1337
- contributionKinds: ["mutation-guard"],
1338
- ...bridge.operations.length > 0 ? { operations: bridge.operations } : {},
1339
- source: { sourcePath, line: nodeLine(file, node) }
1340
- });
1341
- }
1342
- }
1343
- node.forEachChild(visit);
1344
- };
1345
- file.forEachChild(visit);
1346
- }
1347
- return sortActivations(activations);
1348
- }
1349
- function extractModuleExtensionFacts(options) {
1350
- const declared = extractDeclaredHosts(options);
1351
- const hosts = sortHosts([...declared.hosts, ...extractFactRefHosts(options)]);
1352
- const contributions = sortContributions([
1353
- ...extractInjectionTable(options),
1354
- ...extractEnrichers(options),
1355
- ...extractApiInterceptors(options),
1356
- ...extractCommandInterceptors(options),
1357
- ...extractGuards(options),
1358
- ...extractEntityExtensions(options),
1359
- ...extractSubscribers(options),
1360
- ...extractBrowserReactions(options),
1361
- ...extractNotificationReactions(options),
1362
- ...extractComponentOverrides(options),
1363
- ...extractSpecializedRegistries(options)
1364
- ]);
1365
- return {
1366
- hosts,
1367
- contributions,
1368
- unresolved: declared.unresolved,
1369
- activations: extractCallSiteActivations(options)
1370
- };
1371
- }
1372
- function patternMatches(pattern, targetId) {
1373
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\\\{[^}]+\\\}/g, "[^:]+").replace(/\*/g, ".*");
1374
- return new RegExp(`^${escaped}$`).test(targetId);
1375
- }
1376
- function targetModuleId(targetId) {
1377
- const withoutPrefix = targetId.replace(/^(?:data-table|crud-form|detail|portal-page):/, "");
1378
- const match = /^([a-z][a-z0-9_]*)[.:]/.exec(withoutPrefix);
1379
- return match?.[1] ?? null;
1380
- }
1381
- function correlateExtensionTarget(targetFact, options) {
1382
- if (targetFact.resolution !== "unresolved") return targetFact;
1383
- const allHosts = Object.values(options.surfacesByModule).flatMap((surface) => surface.hosts);
1384
- if (targetFact.id.includes("*") || targetFact.id.includes("{")) {
1385
- const knownIds = [
1386
- ...allHosts.filter((host) => host.bound).map((host) => host.id),
1387
- ...options.entityIds,
1388
- ...options.eventIds,
1389
- ...options.apiRoutes,
1390
- ...options.commandIds ?? []
1391
- ];
1392
- if (targetFact.id === "*" || knownIds.some((knownId) => patternMatches(targetFact.id, knownId))) {
1393
- return { id: targetFact.id, resolution: "pattern" };
1394
- }
1395
- }
1396
- const exact = allHosts.find((host) => host.bound && (host.id === targetFact.id || host.aliases?.includes(targetFact.id) || host.family === "api-route" && host.id.endsWith(`/${targetFact.id}`)));
1397
- if (exact) {
1398
- return exact.source.kind === "fact-ref" ? factTarget(targetFact.id, exact.source.factSection, exact.source.factKey) : { id: targetFact.id, resolution: "exact" };
1399
- }
1400
- const patterned = allHosts.find((host) => host.bound && host.resolution === "pattern" && patternMatches(host.id, targetFact.id));
1401
- if (patterned) return { id: targetFact.id, resolution: "pattern" };
1402
- const framework = allFrameworkHosts().find((host) => patternMatches(host.id, targetFact.id)) ?? (FRAMEWORK_PREFIXES.some((prefix) => targetFact.id.startsWith(prefix)) ? FRAMEWORK_HOSTS[0] : void 0);
1403
- if (framework) return { id: targetFact.id, resolution: "framework" };
1404
- if (options.entityIds.has(targetFact.id)) {
1405
- return { id: targetFact.id, resolution: "fact-ref", factRef: { factSection: "entities", factKey: targetFact.id } };
1406
- }
1407
- if (options.eventIds.has(targetFact.id)) {
1408
- return { id: targetFact.id, resolution: "fact-ref", factRef: { factSection: "events", factKey: targetFact.id } };
1409
- }
1410
- if (options.commandIds?.has(targetFact.id)) {
1411
- return factTarget(targetFact.id, "ownedContracts.command");
1412
- }
1413
- const route = [...options.apiRoutes].find((apiRoute) => apiRoute === targetFact.id || apiRoute.endsWith(`/${targetFact.id}`));
1414
- if (route) return { id: targetFact.id, resolution: "fact-ref", factRef: { factSection: "apiRoutes", factKey: route } };
1415
- const ownerModule = targetModuleId(targetFact.id);
1416
- if (ownerModule && !options.surfacesByModule[ownerModule]) {
1417
- return { id: targetFact.id, resolution: "optional-external", optionalOwnerPackage: `module:${ownerModule}` };
1418
- }
1419
- if (ownerModule && options.contributingModuleId && ownerModule !== options.contributingModuleId) {
1420
- return { id: targetFact.id, resolution: "optional-external", optionalOwnerPackage: `module:${ownerModule}` };
1421
- }
1422
- return targetFact;
1423
- }
1424
- function correlateModuleExtensionFacts(options) {
1425
- const result = {};
1426
- for (const moduleId of Object.keys(options.surfacesByModule).sort((left, right) => left.localeCompare(right))) {
1427
- const surface = options.surfacesByModule[moduleId];
1428
- const unresolved = [...surface.unresolved];
1429
- const contributions = surface.contributions.map((contribution) => {
1430
- const targets = contribution.targets.map((entry) => correlateExtensionTarget(entry, {
1431
- ...options,
1432
- contributingModuleId: moduleId
1433
- }));
1434
- for (const entry of targets) {
1435
- if (entry.resolution !== "unresolved") continue;
1436
- unresolved.push({
1437
- key: `${contribution.id}:${entry.id}`,
1438
- source: contribution.source,
1439
- reason: "unresolved-first-party-target"
1440
- });
1441
- }
1442
- return { ...contribution, targets };
1443
- });
1444
- result[moduleId] = {
1445
- hosts: sortHosts([...surface.hosts]),
1446
- contributions: sortContributions(contributions),
1447
- unresolved: unresolved.sort((left, right) => left.key.localeCompare(right.key)),
1448
- activations: sortActivations([...surface.activations ?? []])
1449
- };
1450
- }
1451
- return result;
1452
- }
1453
- function normalizeRouteId(routeId) {
1454
- return routeId.replace(/^\//, "");
1455
- }
1456
- const FRAMEWORK_HOST_OWNER = "framework";
1457
- const FRAMEWORK_HOST_FAMILIES_BY_ACTIVATION = {
1458
- "dashboard-host-consumer": ["dashboard"],
1459
- "widget-injection-consumer": ["menu", "generic", "crud-form", "data-table", "notification", "integration"],
1460
- "component-extension-consumer": ["component-handle"]
1461
- };
1462
- function findFrameworkHost(targetId, activationKind) {
1463
- const families = FRAMEWORK_HOST_FAMILIES_BY_ACTIVATION[activationKind];
1464
- if (!families) return null;
1465
- const candidates = FRAMEWORK_HOSTS.filter((host) => families.includes(host.family));
1466
- const exact = candidates.find((host) => host.id === targetId);
1467
- if (exact) return exact;
1468
- return candidates.find((host) => host.resolution === "pattern" && patternMatches(host.id, targetId)) ?? null;
1469
- }
1470
- function operationsIntersect(activationOperations, contributionOperations) {
1471
- if (!activationOperations || activationOperations.length === 0) return true;
1472
- if (!contributionOperations || contributionOperations.length === 0) return true;
1473
- return contributionOperations.some((operation) => activationOperations.includes(operation));
1474
- }
1475
- function contributionSourceRef(contribution) {
1476
- return {
1477
- sourcePath: contribution.source.path,
1478
- ...contribution.source.symbol ? { exportName: contribution.source.symbol } : {}
1479
- };
1480
- }
1481
- function targetRefKindFor(contribution, targetId) {
1482
- if (targetId === "*" || targetId.includes("*") || targetId.includes("{")) return "wildcard";
1483
- switch (contribution.kind) {
1484
- case "response-enricher":
1485
- case "mutation-guard":
1486
- case "entity-extension":
1487
- return "entity";
1488
- case "api-interceptor":
1489
- return "api-route";
1490
- case "command-interceptor":
1491
- return "command";
1492
- case "component-override":
1493
- return "component";
1494
- case "subscriber":
1495
- return "event";
1496
- case "browser-reaction":
1497
- return contribution.details.transports.includes("notification-effect") ? "notification" : "event";
1498
- case "widget":
1499
- case "data-table":
1500
- case "crud-form":
1501
- return "widget-spot";
1502
- case "specialized-registry":
1503
- case "module-override":
1504
- return "module";
1505
- default:
1506
- return "module";
1507
- }
1508
- }
1509
- function correlateIncomingExtensions(options) {
1510
- const moduleIds = Object.keys(options.surfacesByModule).sort((left, right) => left.localeCompare(right));
1511
- const apiRouteOwners = options.apiRouteOwners ?? /* @__PURE__ */ new Map();
1512
- const commandOwners = options.commandOwners ?? /* @__PURE__ */ new Map();
1513
- const activationIndex = /* @__PURE__ */ new Map();
1514
- const activationKey = (kind, hostKind, id) => {
1515
- const normId = hostKind === "api-route" ? normalizeRouteId(id) : id;
1516
- return JSON.stringify([kind, hostKind, normId]);
1517
- };
1518
- const boundHostIndex = /* @__PURE__ */ new Map();
1519
- for (const moduleId of moduleIds) {
1520
- const surface = options.surfacesByModule[moduleId];
1521
- for (const activation of surface.activations ?? []) {
1522
- const key = activationKey(activation.kind, activation.host.kind, activation.host.id);
1523
- const bucket = activationIndex.get(key);
1524
- if (bucket) bucket.push({ moduleId, activation });
1525
- else activationIndex.set(key, [{ moduleId, activation }]);
1526
- }
1527
- for (const host of surface.hosts) {
1528
- if (!host.bound) continue;
1529
- if (!boundHostIndex.has(host.id)) boundHostIndex.set(host.id, { moduleId, host });
1530
- }
1531
- }
1532
- const incomingByModule = {};
1533
- const resolutionsByModule = {};
1534
- const syntheticActivations = {};
1535
- for (const moduleId of moduleIds) {
1536
- incomingByModule[moduleId] = [];
1537
- resolutionsByModule[moduleId] = [];
1538
- syntheticActivations[moduleId] = [];
1539
- }
1540
- const registerSyntheticActivation = (ownerModule, activation) => {
1541
- if (!syntheticActivations[ownerModule]) syntheticActivations[ownerModule] = [];
1542
- if (!syntheticActivations[ownerModule].some((entry) => entry.id === activation.id)) {
1543
- syntheticActivations[ownerModule].push(activation);
1544
- }
1545
- };
1546
- const findCallSiteActivations = (contributionKind, activationKinds, targetRef, contributionOperations) => {
1547
- const matches = [];
1548
- for (const kind of activationKinds) {
1549
- if (ACTIVATION_ADAPTERS[kind].mode !== "call-site-object") continue;
1550
- const bucket = activationIndex.get(activationKey(kind, targetRef.kind, targetRef.id)) ?? [];
1551
- for (const entry of bucket) {
1552
- if (!entry.activation.contributionKinds.includes(contributionKind)) continue;
1553
- if (!operationsIntersect(entry.activation.operations, contributionOperations)) continue;
1554
- matches.push(entry);
1555
- }
1556
- }
1557
- return matches.sort((left, right) => left.activation.id.localeCompare(right.activation.id));
1558
- };
1559
- for (const contributorModuleId of moduleIds) {
1560
- const surface = options.surfacesByModule[contributorModuleId];
1561
- for (const contribution of surface.contributions) {
1562
- const classification = CONTRIBUTION_ACTIVATION_CLASSIFICATION[contribution.kind];
1563
- for (const resolvedTarget of contribution.targets) {
1564
- const targetKind = targetRefKindFor(contribution, resolvedTarget.id);
1565
- const baseTarget = { kind: targetKind, id: resolvedTarget.id };
1566
- let resolution;
1567
- let ownerModule = null;
1568
- let boundActivationIds = [];
1569
- if (targetKind === "wildcard" || resolvedTarget.resolution === "pattern") {
1570
- resolution = "wildcard";
1571
- } else if (resolvedTarget.resolution === "optional-external") {
1572
- resolution = "optional-target-missing";
1573
- } else if (resolvedTarget.resolution === "unresolved") {
1574
- resolution = "unresolved";
1575
- } else {
1576
- const activationKinds = classification === "capability-only" ? [] : classification;
1577
- const callSiteMatches = findCallSiteActivations(
1578
- contribution.kind,
1579
- activationKinds,
1580
- baseTarget,
1581
- contribution.operations
1582
- );
1583
- if (callSiteMatches.length > 0) {
1584
- resolution = "bound";
1585
- ownerModule = callSiteMatches[0].moduleId;
1586
- boundActivationIds = callSiteMatches.map((entry) => entry.activation.id);
1587
- } else {
1588
- const referenceBinding = resolveReferenceBinding({
1589
- contribution,
1590
- activationKinds,
1591
- targetRef: baseTarget,
1592
- boundHostIndex,
1593
- apiRouteOwners,
1594
- commandOwners
1595
- });
1596
- if (referenceBinding) {
1597
- resolution = "bound";
1598
- const isFrameworkHost = referenceBinding.ownerModule === FRAMEWORK_HOST_OWNER;
1599
- ownerModule = isFrameworkHost ? null : referenceBinding.ownerModule;
1600
- const activationOwner = isFrameworkHost ? contributorModuleId : referenceBinding.ownerModule;
1601
- for (const activation of referenceBinding.activations) {
1602
- registerSyntheticActivation(activationOwner, activation);
1603
- }
1604
- boundActivationIds = referenceBinding.activations.map((activation) => activation.id);
1605
- } else {
1606
- const hostOwner = boundHostIndex.get(resolvedTarget.id);
1607
- if (hostOwner) {
1608
- resolution = "capability-only";
1609
- ownerModule = hostOwner.moduleId;
1610
- } else {
1611
- resolution = "capability-only";
1612
- ownerModule = null;
1613
- }
1614
- }
1615
- }
1616
- }
1617
- const resolutionTarget = ownerModule ? { ...baseTarget, moduleId: ownerModule } : baseTarget;
1618
- resolutionsByModule[contributorModuleId].push({
1619
- contributionId: contribution.id,
1620
- target: resolutionTarget,
1621
- resolution,
1622
- activationIds: [...boundActivationIds].sort((left, right) => left.localeCompare(right))
1623
- });
1624
- if (ownerModule && ownerModule !== contributorModuleId && (resolution === "bound" || resolution === "capability-only")) {
1625
- const source = contributionSourceRef(contribution);
1626
- const incomingTarget = { ...baseTarget, moduleId: ownerModule };
1627
- if (resolution === "bound" && boundActivationIds.length > 0) {
1628
- for (const activationRefId of boundActivationIds) {
1629
- incomingByModule[ownerModule].push({
1630
- contributionId: contribution.id,
1631
- contributionKind: contribution.kind,
1632
- contributorModuleId,
1633
- target: incomingTarget,
1634
- activationId: activationRefId,
1635
- resolution: "bound",
1636
- source
1637
- });
1638
- }
1639
- } else {
1640
- incomingByModule[ownerModule].push({
1641
- contributionId: contribution.id,
1642
- contributionKind: contribution.kind,
1643
- contributorModuleId,
1644
- target: incomingTarget,
1645
- resolution,
1646
- source
1647
- });
1648
- }
1649
- }
1650
- }
1651
- }
1652
- }
1653
- const result = {};
1654
- for (const moduleId of moduleIds) {
1655
- const surface = options.surfacesByModule[moduleId];
1656
- result[moduleId] = {
1657
- ...surface,
1658
- activations: sortActivations([...surface.activations ?? [], ...syntheticActivations[moduleId]]),
1659
- incoming: dedupeIncoming(incomingByModule[moduleId]),
1660
- contributionResolutions: sortResolutions(resolutionsByModule[moduleId])
1661
- };
1662
- }
1663
- return result;
1664
- }
1665
- function matchApiInterceptorBridges(contribution, owner) {
1666
- if (contribution.kind !== "api-interceptor") return [];
1667
- const bridges = owner.bridges ?? [];
1668
- const declaredMethods = contribution.details.methods ?? [];
1669
- const declaredPhases = contribution.phases ?? [];
1670
- const matched = [];
1671
- for (const bridge of bridges) {
1672
- if (declaredMethods.length > 0 && !declaredMethods.includes(bridge.method)) continue;
1673
- const phases = declaredPhases.length > 0 ? bridge.phases.filter((phase) => declaredPhases.includes(phase)) : bridge.phases;
1674
- if (phases.length === 0) continue;
1675
- matched.push({ method: bridge.method, phases });
1676
- }
1677
- return matched;
1678
- }
1679
- function resolveReferenceBinding(input) {
1680
- for (const kind of input.activationKinds) {
1681
- const adapter = ACTIVATION_ADAPTERS[kind];
1682
- if (adapter.mode === "call-site-object") continue;
1683
- if (!adapter.contributionKinds.includes(input.contribution.kind)) continue;
1684
- if (adapter.mode === "host-reference" && kind === "api-interceptor-bridge") {
1685
- const routeId = normalizeRouteId(input.targetRef.id);
1686
- const owner = input.apiRouteOwners.get(routeId);
1687
- if (!owner) continue;
1688
- const matchedBridges = matchApiInterceptorBridges(input.contribution, owner);
1689
- if (matchedBridges.length === 0) continue;
1690
- return {
1691
- ownerModule: owner.moduleId,
1692
- activations: matchedBridges.map((bridge) => {
1693
- const host = {
1694
- kind: "api-route",
1695
- id: routeId,
1696
- moduleId: owner.moduleId,
1697
- method: bridge.method
1698
- };
1699
- return {
1700
- id: activationId(host, kind),
1701
- kind,
1702
- host,
1703
- contributionKinds: ["api-interceptor"],
1704
- phases: bridge.phases,
1705
- source: owner.source,
1706
- bridge: { factSection: "apiRoutes", factKey: `/${routeId}` }
1707
- };
1708
- })
1709
- };
1710
- }
1711
- if (adapter.mode === "owner-reference" && kind === "command-interceptor-bridge") {
1712
- const owner = input.commandOwners.get(input.targetRef.id);
1713
- if (!owner) continue;
1714
- const host = { kind: "command", id: input.targetRef.id, moduleId: owner.moduleId };
1715
- return {
1716
- ownerModule: owner.moduleId,
1717
- activations: [{
1718
- id: activationId(host, kind),
1719
- kind,
1720
- host,
1721
- contributionKinds: ["command-interceptor"],
1722
- source: owner.source,
1723
- bridge: { factSection: "ownedContracts.command", factKey: input.targetRef.id }
1724
- }]
1725
- };
1726
- }
1727
- if (adapter.mode === "host-reference" && (kind === "widget-injection-consumer" || kind === "component-extension-consumer" || kind === "dashboard-host-consumer")) {
1728
- const frameworkHostFact = input.boundHostIndex.has(input.targetRef.id) ? null : findFrameworkHost(input.targetRef.id, kind);
1729
- const hostEntry = input.boundHostIndex.get(input.targetRef.id) ?? (frameworkHostFact ? { moduleId: FRAMEWORK_HOST_OWNER, host: frameworkHostFact } : void 0);
1730
- if (!hostEntry) continue;
1731
- const hostSource = hostReferenceSource(hostEntry.host);
1732
- if (!hostSource) continue;
1733
- const host = { ...input.targetRef, moduleId: hostEntry.moduleId };
1734
- return {
1735
- ownerModule: hostEntry.moduleId,
1736
- activations: [{
1737
- id: activationId(host, kind),
1738
- kind,
1739
- host,
1740
- contributionKinds: adapter.contributionKinds,
1741
- source: hostSource,
1742
- bridge: { factSection: "hosts", factKey: hostEntry.host.key }
1743
- }]
1744
- };
1745
- }
1746
- }
1747
- return null;
1748
- }
1749
- function hostReferenceSource(host) {
1750
- if (host.source.kind === "declaration" || host.source.kind === "framework") {
1751
- return { sourcePath: host.source.path, exportName: host.source.symbol };
1752
- }
1753
- return null;
1754
- }
1755
- function incomingIdentity(entry) {
1756
- const target2 = JSON.stringify([entry.target.kind, entry.target.id]);
1757
- return JSON.stringify([entry.contributorModuleId, entry.contributionId, target2, entry.activationId ?? entry.resolution]);
1758
- }
1759
- function dedupeIncoming(entries) {
1760
- const seen = /* @__PURE__ */ new Set();
1761
- const unique = [];
1762
- for (const entry of entries) {
1763
- const identity = incomingIdentity(entry);
1764
- if (seen.has(identity)) continue;
1765
- seen.add(identity);
1766
- unique.push(entry);
1767
- }
1768
- return unique.sort((left, right) => incomingIdentity(left).localeCompare(incomingIdentity(right)));
1769
- }
1770
- function resolutionIdentity(entry) {
1771
- return JSON.stringify([entry.contributionId, entry.target.kind, entry.target.id, entry.resolution]);
1772
- }
1773
- function sortResolutions(entries) {
1774
- const seen = /* @__PURE__ */ new Set();
1775
- const unique = [];
1776
- for (const entry of entries) {
1777
- const identity = resolutionIdentity(entry);
1778
- if (seen.has(identity)) continue;
1779
- seen.add(identity);
1780
- unique.push(entry);
1781
- }
1782
- return unique.sort((left, right) => resolutionIdentity(left).localeCompare(resolutionIdentity(right)));
1783
- }
1784
- function assertNoUnresolvedExtensionTargets(surfacesByModule) {
1785
- const unresolved = Object.entries(surfacesByModule).flatMap(
1786
- ([moduleId, surface]) => surface.unresolved.filter((entry) => entry.reason === "unresolved-first-party-target").map((entry) => `${moduleId}:${entry.key}`)
1787
- ).sort((left, right) => left.localeCompare(right));
1788
- if (unresolved.length > 0) {
1789
- throw new Error(`[module-facts] unresolved first-party extension targets: ${unresolved.join(", ")}`);
1790
- }
1791
- }
1792
- function getFrameworkOverrideModes() {
1793
- const modes = {};
1794
- for (const host of FRAMEWORK_OVERRIDE_HOSTS) {
1795
- const dotted = host.key.replace(/^framework\.module-override\./, "");
1796
- const mode = host.operations?.[0];
1797
- if (mode === "disable-replace" || mode === "replace" || mode === "additive") modes[dotted] = mode;
1798
- }
1799
- return modes;
1800
- }
1801
- function getFrameworkExtensionHosts() {
1802
- return sortHosts(allFrameworkHosts().map((host) => ({
1803
- ...host,
1804
- capabilities: [...host.capabilities],
1805
- ...host.operations ? { operations: [...host.operations] } : {}
1806
- })));
1807
- }
1808
- function renderFrameworkExtensionPointsMarkdown() {
1809
- const rows = getFrameworkExtensionHosts().map(
1810
- (host) => `| ${host.id} | ${host.family} | ${[...host.capabilities, ...host.operations ?? []].join(", ")} | ${host.stability.toUpperCase()} |`
1811
- );
1812
- return [
1813
- "# Framework extension points (generated, do not edit)",
1814
- "",
1815
- "| ID / pattern | Family | Supports | Stability |",
1816
- "|---|---|---|---|",
1817
- ...rows,
1818
- ""
1819
- ].join("\n");
1820
- }
1821
- export {
1822
- ACTIVATION_ADAPTERS,
1823
- ALL_ACTIVATION_KINDS,
1824
- ALL_CONTRIBUTION_KINDS,
1825
- CONTRIBUTION_ACTIVATION_CLASSIFICATION,
1826
- assertNoUnresolvedExtensionTargets,
1827
- correlateExtensionTarget,
1828
- correlateIncomingExtensions,
1829
- correlateModuleExtensionFacts,
1830
- extractActivationTargetOwners,
1831
- extractKnownApiRouteIds,
1832
- extractKnownCommandIds,
1833
- extractModuleExtensionFacts,
1834
- getFrameworkExtensionHosts,
1835
- getFrameworkOverrideModes,
1836
- readConventionObjectArray,
1837
- renderFrameworkExtensionPointsMarkdown,
1838
- withModuleExtensionFactExtractionCache
1839
- };
1840
- //# sourceMappingURL=module-extension-facts.js.map