@open-mercato/cli 0.10.1-develop.7836.1.0ef0f453c6 → 0.10.1-develop.7847.1.7d83dc5794

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 (95) hide show
  1. package/dist/agentic/guides/module-facts.json +174 -164
  2. package/dist/agentic/guides/module-facts.v2.json +174 -164
  3. package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
  4. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  5. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  6. package/dist/agentic/guides/modules/api_keys/index.md +1 -1
  7. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  8. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  9. package/dist/agentic/guides/modules/auth/index.md +1 -1
  10. package/dist/agentic/guides/modules/availability/index.md +1 -1
  11. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  12. package/dist/agentic/guides/modules/carrier_inpost/index.md +1 -1
  13. package/dist/agentic/guides/modules/cart/index.md +1 -1
  14. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  15. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  16. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  17. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  18. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  19. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  20. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  21. package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
  22. package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
  23. package/dist/agentic/guides/modules/channel_smtp/index.md +1 -1
  24. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  25. package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
  26. package/dist/agentic/guides/modules/configs/index.md +1 -1
  27. package/dist/agentic/guides/modules/content/index.md +1 -1
  28. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  29. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  30. package/dist/agentic/guides/modules/customer_groups/index.md +1 -1
  31. package/dist/agentic/guides/modules/customers/index.md +1 -1
  32. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  33. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  34. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  35. package/dist/agentic/guides/modules/devices/index.md +1 -1
  36. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  37. package/dist/agentic/guides/modules/directory/active-extension-bindings.md +1 -1
  38. package/dist/agentic/guides/modules/directory/index.md +1 -1
  39. package/dist/agentic/guides/modules/documents/index.md +1 -1
  40. package/dist/agentic/guides/modules/ecommerce/index.md +1 -1
  41. package/dist/agentic/guides/modules/entities/index.md +1 -1
  42. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  43. package/dist/agentic/guides/modules/eudr/owned-contract-module-metadata.md +1 -1
  44. package/dist/agentic/guides/modules/events/index.md +1 -1
  45. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  46. package/dist/agentic/guides/modules/forms/index.md +1 -1
  47. package/dist/agentic/guides/modules/gateway_autopay/index.md +1 -1
  48. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  49. package/dist/agentic/guides/modules/gateway_tpay/index.md +1 -1
  50. package/dist/agentic/guides/modules/generators/index.md +1 -1
  51. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  52. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  53. package/dist/agentic/guides/modules/messages/index.md +1 -1
  54. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  55. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  56. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  57. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  58. package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
  59. package/dist/agentic/guides/modules/planner/index.md +1 -1
  60. package/dist/agentic/guides/modules/portal/index.md +1 -1
  61. package/dist/agentic/guides/modules/progress/index.md +1 -1
  62. package/dist/agentic/guides/modules/promotions/index.md +1 -1
  63. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  64. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  65. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  66. package/dist/agentic/guides/modules/resources/index.md +1 -1
  67. package/dist/agentic/guides/modules/sales/index.md +1 -1
  68. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  69. package/dist/agentic/guides/modules/search/index.md +1 -1
  70. package/dist/agentic/guides/modules/security/index.md +1 -1
  71. package/dist/agentic/guides/modules/seeds/index.md +1 -1
  72. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  73. package/dist/agentic/guides/modules/sso/index.md +1 -1
  74. package/dist/agentic/guides/modules/staff/active-extension-bindings.md +1 -1
  75. package/dist/agentic/guides/modules/staff/index.md +1 -1
  76. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  77. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  78. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  79. package/dist/agentic/guides/modules/sync_excel/owned-contract-module-metadata.md +1 -1
  80. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  81. package/dist/agentic/guides/modules/telemetry/index.md +1 -1
  82. package/dist/agentic/guides/modules/tillio/index.md +1 -1
  83. package/dist/agentic/guides/modules/translations/index.md +1 -1
  84. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  85. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  86. package/dist/agentic/guides/modules/wms/index.md +1 -1
  87. package/dist/agentic/guides/modules/wms/owned-contract-module-metadata.md +1 -1
  88. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  89. package/dist/agentic/guides/reference-module-facts.json +1 -1
  90. package/dist/agentic/guides/upstream/manifest.json +1 -1
  91. package/dist/lib/generators/module-registry.js +18 -18
  92. package/dist/lib/generators/module-registry.js.map +2 -2
  93. package/package.json +7 -7
  94. package/src/lib/generators/__tests__/module-registry-requires-enforcement.test.ts +130 -0
  95. package/src/lib/generators/module-registry.ts +20 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.10.1-develop.7836.1.0ef0f453c6",
3
+ "version": "0.10.1-develop.7847.1.7d83dc5794",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,10 +60,10 @@
60
60
  "@mikro-orm/decorators": "^7.1.14",
61
61
  "@mikro-orm/migrations": "^7.1.14",
62
62
  "@mikro-orm/postgresql": "^7.1.14",
63
- "@open-mercato/events": "0.10.1-develop.7836.1.0ef0f453c6",
64
- "@open-mercato/queue": "0.10.1-develop.7836.1.0ef0f453c6",
65
- "@open-mercato/shared": "0.10.1-develop.7836.1.0ef0f453c6",
66
- "@open-mercato/telemetry": "0.10.1-develop.7836.1.0ef0f453c6",
63
+ "@open-mercato/events": "0.10.1-develop.7847.1.7d83dc5794",
64
+ "@open-mercato/queue": "0.10.1-develop.7847.1.7d83dc5794",
65
+ "@open-mercato/shared": "0.10.1-develop.7847.1.7d83dc5794",
66
+ "@open-mercato/telemetry": "0.10.1-develop.7847.1.7d83dc5794",
67
67
  "cross-spawn": "^7.0.6",
68
68
  "minisearch": "7.2.0",
69
69
  "pg": "8.23.0",
@@ -75,10 +75,10 @@
75
75
  "typescript-js": "npm:typescript@6.0.3"
76
76
  },
77
77
  "peerDependencies": {
78
- "@open-mercato/shared": "0.10.1-develop.7836.1.0ef0f453c6"
78
+ "@open-mercato/shared": "0.10.1-develop.7847.1.7d83dc5794"
79
79
  },
80
80
  "devDependencies": {
81
- "@open-mercato/shared": "0.10.1-develop.7836.1.0ef0f453c6",
81
+ "@open-mercato/shared": "0.10.1-develop.7847.1.7d83dc5794",
82
82
  "@types/jest": "^30.0.0",
83
83
  "jest": "^30.4.2",
84
84
  "ts-jest": "^29.4.12"
@@ -0,0 +1,130 @@
1
+ /**
2
+ * `metadata.requires` must actually block `yarn generate` when the required module is
3
+ * not enabled — it is not advisory text.
4
+ *
5
+ * The CLI package is built as an ES module (`packages/cli/package.json` `"type": "module"`),
6
+ * where the bare `require()` this check used to read `metadata.requires` is undefined and
7
+ * throws a `ReferenceError` on every module, every time. That throw was swallowed by a
8
+ * `catch {}`, so the dependency map stayed empty and the check below it never found
9
+ * anything to report: a module could declare `requires: ['catalog']`, `catalog` could be
10
+ * disabled, and `yarn generate` would still succeed. Unit tests missed this because Jest
11
+ * runs the generator under CommonJS, where `require()` is defined and the bug cannot
12
+ * reproduce.
13
+ *
14
+ * The fix reads `metadata.requires` through `loadModuleExportsFromSource` (a real
15
+ * `import()`) with an AST-based static fallback — the same mechanism this file already
16
+ * uses for route metadata — so there is no `require()` left to break under ESM. This test
17
+ * drives the real generator against real fixture files on disk rather than asserting on
18
+ * the implementation, so it fails again if a future change reintroduces `require()`.
19
+ */
20
+ import fs from 'node:fs'
21
+ import path from 'node:path'
22
+ import os from 'node:os'
23
+ import type { PackageResolver, ModuleEntry } from '../../resolver'
24
+ import { generateModuleRegistry } from '../module-registry'
25
+
26
+ let tmpDir: string
27
+ let outputDir: string
28
+
29
+ function touchFile(filePath: string, content: string): void {
30
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
31
+ fs.writeFileSync(filePath, content)
32
+ }
33
+
34
+ function pkgModulePath(modId: string, ...segments: string[]): string {
35
+ return path.join(tmpDir, 'packages', 'core', 'src', 'modules', modId, ...segments)
36
+ }
37
+
38
+ function createMockResolver(enabled: ModuleEntry[]): PackageResolver {
39
+ return {
40
+ isMonorepo: () => true,
41
+ getRootDir: () => tmpDir,
42
+ getAppDir: () => path.join(tmpDir, 'app'),
43
+ getOutputDir: () => outputDir,
44
+ getModulesConfigPath: () => path.join(tmpDir, 'app', 'src', 'modules.ts'),
45
+ discoverPackages: () => [],
46
+ loadEnabledModules: () => enabled,
47
+ getModulePaths: (entry: ModuleEntry) => ({
48
+ appBase: path.join(tmpDir, 'app', 'src', 'modules', entry.id),
49
+ pkgBase: path.join(tmpDir, 'packages', 'core', 'src', 'modules', entry.id),
50
+ }),
51
+ getModuleImportBase: (entry: ModuleEntry) => ({
52
+ appBase: `@/modules/${entry.id}`,
53
+ pkgBase: `@open-mercato/core/modules/${entry.id}`,
54
+ }),
55
+ getPackageOutputDir: () => outputDir,
56
+ getPackageRoot: () => path.join(tmpDir, 'packages', 'core'),
57
+ } as unknown as PackageResolver
58
+ }
59
+
60
+ function scaffoldDependentFixture(): void {
61
+ touchFile(pkgModulePath('leaf', 'index.ts'), "export const metadata = { id: 'leaf', label: 'Leaf' }\n")
62
+ touchFile(
63
+ pkgModulePath('dependent', 'index.ts'),
64
+ "export const metadata = { id: 'dependent', label: 'Dependent', requires: ['leaf'] }\n",
65
+ )
66
+ }
67
+
68
+ function mockProcessExit(): jest.SpyInstance {
69
+ return jest.spyOn(process, 'exit').mockImplementation(((code?: number) => {
70
+ throw new Error(`process.exit(${code})`)
71
+ }) as unknown as typeof process.exit)
72
+ }
73
+
74
+ describe('module registry enforces metadata.requires', () => {
75
+ beforeEach(() => {
76
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'registry-requires-'))
77
+ outputDir = path.join(tmpDir, 'app', '.mercato', 'generated')
78
+ fs.mkdirSync(outputDir, { recursive: true })
79
+ })
80
+
81
+ afterEach(() => {
82
+ fs.rmSync(tmpDir, { recursive: true, force: true })
83
+ })
84
+
85
+ it('refuses generation when a declared dependency is not enabled', async () => {
86
+ scaffoldDependentFixture()
87
+ const resolver = createMockResolver([{ id: 'dependent', from: '@open-mercato/core' }])
88
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation()
89
+ const exitSpy = mockProcessExit()
90
+
91
+ await expect(generateModuleRegistry({ resolver, quiet: true })).rejects.toThrow('process.exit(1)')
92
+
93
+ expect(exitSpy).toHaveBeenCalledWith(1)
94
+ expect(consoleErrorSpy.mock.calls.flat().join('\n')).toContain('Module "dependent" requires: leaf')
95
+
96
+ consoleErrorSpy.mockRestore()
97
+ exitSpy.mockRestore()
98
+ })
99
+
100
+ it('generates cleanly once the declared dependency is enabled', async () => {
101
+ scaffoldDependentFixture()
102
+ const resolver = createMockResolver([
103
+ { id: 'leaf', from: '@open-mercato/core' },
104
+ { id: 'dependent', from: '@open-mercato/core' },
105
+ ])
106
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation()
107
+ const exitSpy = mockProcessExit()
108
+
109
+ const result = await generateModuleRegistry({ resolver, quiet: true })
110
+
111
+ expect(result.errors).toEqual([])
112
+ expect(exitSpy).not.toHaveBeenCalled()
113
+
114
+ consoleErrorSpy.mockRestore()
115
+ exitSpy.mockRestore()
116
+ })
117
+ })
118
+
119
+ describe('module registry has no require() left to break under the ESM CLI build', () => {
120
+ it('reads metadata.requires without the CommonJS require() function', () => {
121
+ // Jest runs this generator under CommonJS, where `require()` is defined — the two
122
+ // tests above would pass even against the old, ESM-broken implementation. This
123
+ // static check is what actually guards against a regression: `@open-mercato/cli`
124
+ // is built as an ES module, so a bare `require()` call reintroduced here would throw
125
+ // under the real build regardless of what Jest reports.
126
+ const sourceFile = path.join(__dirname, '..', 'module-registry.ts')
127
+ const source = fs.readFileSync(sourceFile, 'utf8')
128
+ expect([...source.matchAll(/\brequire\(/g)]).toEqual([])
129
+ })
130
+ })
@@ -1722,6 +1722,20 @@ function resolveApiPathFromMetadata(metadata: unknown, fallbackPath: string): st
1722
1722
  return typeof candidate === 'string' && candidate.length > 0 ? candidate : fallbackPath
1723
1723
  }
1724
1724
 
1725
+ function resolveModuleRequiresFromMetadata(metadata: unknown): string[] | undefined {
1726
+ if (!metadata || typeof metadata !== 'object') return undefined
1727
+ const requires = (metadata as Record<string, unknown>).requires
1728
+ if (!Array.isArray(requires)) return undefined
1729
+ const resolved = requires.filter((value): value is string => typeof value === 'string')
1730
+ return resolved.length > 0 ? resolved : undefined
1731
+ }
1732
+
1733
+ async function resolveModuleRequiresFromIndexFile(indexFileAbsolutePath: string): Promise<string[] | undefined> {
1734
+ const loadedModule = await loadModuleExportsFromSource<Record<string, unknown>>(indexFileAbsolutePath)
1735
+ const metadata = loadedModule?.metadata ?? extractNamedObjectLiteralExport(indexFileAbsolutePath, 'metadata')
1736
+ return resolveModuleRequiresFromMetadata(metadata)
1737
+ }
1738
+
1725
1739
  function detectExportedHttpMethods(sourceFile: string): HttpMethod[] {
1726
1740
  let source = ''
1727
1741
  try {
@@ -3691,13 +3705,8 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
3691
3705
  const importPath = sanitizeGeneratedModuleSpecifier(indexResolved.importPath)
3692
3706
  imports.push(buildImportStatement(`* as ${infoImportName}`, importPath))
3693
3707
  runtimeImports.push(buildImportStatement(`* as ${infoImportName}`, importPath))
3694
- try {
3695
- // eslint-disable-next-line @typescript-eslint/no-var-requires
3696
- const mod = require(indexResolved.absolutePath)
3697
- const reqs: string[] | undefined =
3698
- mod?.metadata && Array.isArray(mod.metadata.requires) ? mod.metadata.requires : undefined
3699
- if (reqs && reqs.length) requiresByModule.set(modId, reqs)
3700
- } catch {}
3708
+ const reqs = await resolveModuleRequiresFromIndexFile(indexResolved.absolutePath)
3709
+ if (reqs && reqs.length) requiresByModule.set(modId, reqs)
3701
3710
  }
3702
3711
 
3703
3712
  // 2. Pages: frontend
@@ -4414,13 +4423,8 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
4414
4423
  const importPath = sanitizeGeneratedModuleSpecifier(indexResolved.importPath)
4415
4424
  imports.push(buildImportStatement(`* as ${infoImportName}`, importPath))
4416
4425
  bootstrapImports.push(buildImportStatement(`* as ${infoImportName}`, importPath))
4417
- try {
4418
- // eslint-disable-next-line @typescript-eslint/no-var-requires
4419
- const mod = require(indexResolved.absolutePath)
4420
- const reqs: string[] | undefined =
4421
- mod?.metadata && Array.isArray(mod.metadata.requires) ? mod.metadata.requires : undefined
4422
- if (reqs && reqs.length) requiresByModule.set(modId, reqs)
4423
- } catch {}
4426
+ const reqs = await resolveModuleRequiresFromIndexFile(indexResolved.absolutePath)
4427
+ if (reqs && reqs.length) requiresByModule.set(modId, reqs)
4424
4428
  }
4425
4429
 
4426
4430
  {
@@ -4849,13 +4853,8 @@ async function generateModuleRegistryCliFromDiscovery(options: ModuleRegistryRen
4849
4853
  infoImportName = `I${importIdRef.value++}_${toVar(modId)}`
4850
4854
  const importPath = sanitizeGeneratedModuleSpecifier(indexResolved.importPath)
4851
4855
  imports.push(buildImportStatement(`* as ${infoImportName}`, importPath))
4852
- try {
4853
- // eslint-disable-next-line @typescript-eslint/no-var-requires
4854
- const mod = require(indexResolved.absolutePath)
4855
- const reqs: string[] | undefined =
4856
- mod?.metadata && Array.isArray(mod.metadata.requires) ? mod.metadata.requires : undefined
4857
- if (reqs && reqs.length) requiresByModule.set(modId, reqs)
4858
- } catch {}
4856
+ const reqs = await resolveModuleRequiresFromIndexFile(indexResolved.absolutePath)
4857
+ if (reqs && reqs.length) requiresByModule.set(modId, reqs)
4859
4858
  }
4860
4859
 
4861
4860
  // Module setup configuration: setup.ts