@open-mercato/cli 0.4.2-canary-f80d1bfa83 โ†’ 0.4.2-canary-5035717565

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.4.2-canary-f80d1bfa83",
3
+ "version": "0.4.2-canary-5035717565",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -55,7 +55,7 @@
55
55
  "@mikro-orm/core": "^6.6.2",
56
56
  "@mikro-orm/migrations": "^6.6.2",
57
57
  "@mikro-orm/postgresql": "^6.6.2",
58
- "@open-mercato/shared": "0.4.2-canary-f80d1bfa83",
58
+ "@open-mercato/shared": "0.4.2-canary-5035717565",
59
59
  "pg": "^8.16.3",
60
60
  "typescript": "^5.9.3"
61
61
  },
@@ -77,8 +77,7 @@ async function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver)
77
77
  path.join(roots.appBase, 'db'),
78
78
  path.join(roots.pkgBase, 'db'),
79
79
  ]
80
- // Check both .ts (src/monorepo) and .js (dist/production) extensions
81
- const candidates = ['entities.ts', 'entities.js', 'schema.ts', 'schema.js']
80
+ const candidates = ['entities.ts', 'schema.ts']
82
81
 
83
82
  for (const base of bases) {
84
83
  for (const f of candidates) {
@@ -86,12 +85,10 @@ async function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver)
86
85
  if (fs.existsSync(p)) {
87
86
  const sub = path.basename(base)
88
87
  const fromApp = base.startsWith(roots.appBase)
89
- const ext = path.extname(f)
90
- const baseName = f.replace(ext, '')
91
88
  // For @app modules, use file:// URL since @/ alias doesn't work in Node.js runtime
92
89
  const importPath = (isAppModule && fromApp)
93
90
  ? `file://${p.replace(/\.ts$/, '.js')}`
94
- : `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${baseName}`
91
+ : `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${f.replace(/\.ts$/, '')}`
95
92
  try {
96
93
  const mod = await import(importPath)
97
94
  const entities = Object.values(mod).filter((v) => typeof v === 'function')
@@ -110,15 +107,25 @@ async function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver)
110
107
 
111
108
  function getMigrationsPath(entry: ModuleEntry, resolver: PackageResolver): string {
112
109
  const from = entry.from || '@open-mercato/core'
113
-
114
- if (from === '@app') {
115
- // For @app modules, use the app directory
116
- return path.join(resolver.getAppDir(), 'src/modules', entry.id, 'migrations')
110
+ let pkgModRoot: string
111
+
112
+ if (from === '@open-mercato/core') {
113
+ pkgModRoot = path.join(resolver.getRootDir(), 'packages/core/src/modules', entry.id)
114
+ } else if (/^@open-mercato\//.test(from)) {
115
+ const segs = from.split('/')
116
+ if (segs.length > 1 && segs[1]) {
117
+ pkgModRoot = path.join(resolver.getRootDir(), `packages/${segs[1]}/src/modules`, entry.id)
118
+ } else {
119
+ pkgModRoot = path.join(resolver.getRootDir(), 'packages/core/src/modules', entry.id)
120
+ }
121
+ } else if (from === '@app') {
122
+ // For @app modules, use the app directory not the monorepo root
123
+ pkgModRoot = path.join(resolver.getAppDir(), 'src/modules', entry.id)
124
+ } else {
125
+ pkgModRoot = path.join(resolver.getRootDir(), 'packages/core/src/modules', entry.id)
117
126
  }
118
127
 
119
- // Use resolver's getModulePaths which handles monorepo vs production mode
120
- const { pkgBase } = resolver.getModulePaths(entry)
121
- return path.join(pkgBase, 'migrations')
128
+ return path.join(pkgModRoot, 'migrations')
122
129
  }
123
130
 
124
131
  export interface DbOptions {
@@ -179,8 +179,7 @@ export async function generateEntityIds(options: EntityIdsOptions): Promise<Gene
179
179
  const appDb = path.join(roots.appBase, 'db')
180
180
  const pkgDb = path.join(roots.pkgBase, 'db')
181
181
  const bases = [appData, pkgData, appDb, pkgDb]
182
- // Check both .ts (src/monorepo) and .js (dist/production) extensions
183
- const candidates = ['entities.override.ts', 'entities.override.js', 'entities.ts', 'entities.js', 'schema.ts', 'schema.js']
182
+ const candidates = ['entities.override.ts', 'entities.ts', 'schema.ts']
184
183
  let importPath: string | null = null
185
184
  let filePath: string | null = null
186
185
 
@@ -190,8 +189,7 @@ export async function generateEntityIds(options: EntityIdsOptions): Promise<Gene
190
189
  if (fs.existsSync(p)) {
191
190
  const fromApp = base.startsWith(roots.appBase)
192
191
  const sub = path.basename(base) // 'data' | 'db'
193
- const fileBaseName = f.replace(/\.(ts|js)$/, '')
194
- importPath = `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${fileBaseName}`
192
+ importPath = `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${f.replace(/\.ts$/, '')}`
195
193
  filePath = p
196
194
  break
197
195
  }
@@ -34,13 +34,10 @@ export async function generateModuleDi(options: ModuleDiOptions): Promise<Genera
34
34
  const modId = entry.id
35
35
  const roots = resolver.getModulePaths(entry)
36
36
  const imp = resolver.getModuleImportBase(entry)
37
- // Check both .ts (src/monorepo) and .js (dist/production) extensions
38
- const appDiTs = path.join(roots.appBase, 'di.ts')
39
- const appDiJs = path.join(roots.appBase, 'di.js')
40
- const pkgDiTs = path.join(roots.pkgBase, 'di.ts')
41
- const pkgDiJs = path.join(roots.pkgBase, 'di.js')
42
- const useApp = fs.existsSync(appDiTs) || fs.existsSync(appDiJs)
43
- const usePkg = fs.existsSync(pkgDiTs) || fs.existsSync(pkgDiJs)
37
+ const appDi = path.join(roots.appBase, 'di.ts')
38
+ const pkgDi = path.join(roots.pkgBase, 'di.ts')
39
+ const useApp = fs.existsSync(appDi)
40
+ const usePkg = fs.existsSync(pkgDi)
44
41
  const importName = `D_${toVar(modId)}_${i++}`
45
42
 
46
43
  if (useApp) {
@@ -41,7 +41,7 @@ export async function generateModuleEntities(options: ModuleEntitiesOptions): Pr
41
41
  const appDb = path.join(roots.appBase, 'db')
42
42
  const pkgDb = path.join(roots.pkgBase, 'db')
43
43
  const bases = [appData, pkgData, appDb, pkgDb]
44
- const candidates = ['entities.override.ts', 'entities.override.js', 'entities.ts', 'entities.js', 'schema.ts', 'schema.js']
44
+ const candidates = ['entities.override.ts', 'entities.ts', 'schema.ts']
45
45
 
46
46
  let found: { base: string; file: string } | null = null
47
47
  for (const base of bases) {
@@ -63,13 +63,12 @@ export async function generateModuleEntities(options: ModuleEntitiesOptions): Pr
63
63
  // For @app modules, use relative path to ensure it works both in Next.js and Node.js CLI context
64
64
  // From .mercato/generated/, the relative path to src/modules/ is ../src/modules/
65
65
  let relImport: string
66
- const fileBaseName = found.file.replace(/\.(ts|js)$/, '')
67
66
  if (isAppModule && fromApp) {
68
67
  // From .mercato/generated/, go up two levels (../..) to reach the app root, then into src/modules/
69
- relImport = `../../src/modules/${modId}/${sub}/${fileBaseName}`
68
+ relImport = `../../src/modules/${modId}/${sub}/${found.file.replace(/\.ts$/, '')}`
70
69
  } else {
71
70
  const baseImport = fromApp ? imp.appBase : imp.pkgBase
72
- relImport = `${baseImport}/${sub}/${fileBaseName}`
71
+ relImport = `${baseImport}/${sub}/${found.file.replace(/\.ts$/, '')}`
73
72
  }
74
73
  imports.push(`import * as ${importName} from '${relImport}'`)
75
74
  entitySources.push({ importName, moduleId: modId })
@@ -15,21 +15,6 @@ import {
15
15
 
16
16
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
17
17
 
18
- /**
19
- * Find a module file, checking for both .ts (src) and .js (dist) extensions.
20
- * Supports both simple names (e.g., 'cli') and nested paths (e.g., 'data/extensions').
21
- * Returns the path if found, null otherwise.
22
- */
23
- function findModuleFile(basePath: string, ...segments: string[]): string | null {
24
- const name = segments.pop()!
25
- const dir = segments.length ? path.join(basePath, ...segments) : basePath
26
- const tsPath = path.join(dir, `${name}.ts`)
27
- if (fs.existsSync(tsPath)) return tsPath
28
- const jsPath = path.join(dir, `${name}.js`)
29
- if (fs.existsSync(jsPath)) return jsPath
30
- return null
31
- }
32
-
33
18
  export interface ModuleRegistryOptions {
34
19
  resolver: PackageResolver
35
20
  quiet?: boolean
@@ -94,9 +79,9 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
94
79
  let injectionTableImportName: string | null = null
95
80
 
96
81
  // Module metadata: index.ts (overrideable)
97
- const appIndex = findModuleFile(roots.appBase, 'index')
98
- const pkgIndex = findModuleFile(roots.pkgBase, 'index')
99
- const indexTs = appIndex ?? pkgIndex
82
+ const appIndex = path.join(roots.appBase, 'index.ts')
83
+ const pkgIndex = path.join(roots.pkgBase, 'index.ts')
84
+ const indexTs = fs.existsSync(appIndex) ? appIndex : fs.existsSync(pkgIndex) ? pkgIndex : null
100
85
  if (indexTs) {
101
86
  infoImportName = `I${importId++}_${toVar(modId)}`
102
87
  const importPath = indexTs.startsWith(roots.appBase) ? `${appImportBase}/index` : `${imps.pkgBase}/index`
@@ -205,10 +190,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
205
190
 
206
191
  // Entity extensions: src/modules/<module>/data/extensions.ts
207
192
  {
208
- const appFile = findModuleFile(roots.appBase, 'data', 'extensions')
209
- const pkgFile = findModuleFile(roots.pkgBase, 'data', 'extensions')
210
- const hasApp = !!appFile
211
- const hasPkg = !!pkgFile
193
+ const appFile = path.join(roots.appBase, 'data', 'extensions.ts')
194
+ const pkgFile = path.join(roots.pkgBase, 'data', 'extensions.ts')
195
+ const hasApp = fs.existsSync(appFile)
196
+ const hasPkg = fs.existsSync(pkgFile)
212
197
  if (hasApp || hasPkg) {
213
198
  const importName = `X_${toVar(modId)}_${importId++}`
214
199
  const importPath = hasApp ? `${appImportBase}/data/extensions` : `${imps.pkgBase}/data/extensions`
@@ -219,12 +204,12 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
219
204
 
220
205
  // RBAC feature declarations: module root acl.ts
221
206
  {
222
- const rootApp = findModuleFile(roots.appBase, 'acl')
223
- const rootPkg = findModuleFile(roots.pkgBase, 'acl')
224
- const hasRoot = rootApp || rootPkg
207
+ const rootApp = path.join(roots.appBase, 'acl.ts')
208
+ const rootPkg = path.join(roots.pkgBase, 'acl.ts')
209
+ const hasRoot = fs.existsSync(rootApp) || fs.existsSync(rootPkg)
225
210
  if (hasRoot) {
226
211
  const importName = `ACL_${toVar(modId)}_${importId++}`
227
- const useApp = rootApp ?? rootPkg!
212
+ const useApp = fs.existsSync(rootApp) ? rootApp : rootPkg
228
213
  const importPath = useApp.startsWith(roots.appBase) ? `${appImportBase}/acl` : `${imps.pkgBase}/acl`
229
214
  imports.push(`import * as ${importName} from '${importPath}'`)
230
215
  featuresImportName = importName
@@ -233,10 +218,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
233
218
 
234
219
  // Custom entities declarations: module root ce.ts
235
220
  {
236
- const appFile = findModuleFile(roots.appBase, 'ce')
237
- const pkgFile = findModuleFile(roots.pkgBase, 'ce')
238
- const hasApp = !!appFile
239
- const hasPkg = !!pkgFile
221
+ const appFile = path.join(roots.appBase, 'ce.ts')
222
+ const pkgFile = path.join(roots.pkgBase, 'ce.ts')
223
+ const hasApp = fs.existsSync(appFile)
224
+ const hasPkg = fs.existsSync(pkgFile)
240
225
  if (hasApp || hasPkg) {
241
226
  const importName = `CE_${toVar(modId)}_${importId++}`
242
227
  const importPath = hasApp ? `${appImportBase}/ce` : `${imps.pkgBase}/ce`
@@ -247,10 +232,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
247
232
 
248
233
  // Search module configuration: module root search.ts
249
234
  {
250
- const appFile = findModuleFile(roots.appBase, 'search')
251
- const pkgFile = findModuleFile(roots.pkgBase, 'search')
252
- const hasApp = !!appFile
253
- const hasPkg = !!pkgFile
235
+ const appFile = path.join(roots.appBase, 'search.ts')
236
+ const pkgFile = path.join(roots.pkgBase, 'search.ts')
237
+ const hasApp = fs.existsSync(appFile)
238
+ const hasPkg = fs.existsSync(pkgFile)
254
239
  if (hasApp || hasPkg) {
255
240
  const importName = `SEARCH_${toVar(modId)}_${importId++}`
256
241
  const importPath = hasApp ? `${appImportBase}/search` : `${imps.pkgBase}/search`
@@ -263,10 +248,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
263
248
 
264
249
  // Custom field declarations: src/modules/<module>/data/fields.ts
265
250
  {
266
- const appFile = findModuleFile(roots.appBase, 'data', 'fields')
267
- const pkgFile = findModuleFile(roots.pkgBase, 'data', 'fields')
268
- const hasApp = !!appFile
269
- const hasPkg = !!pkgFile
251
+ const appFile = path.join(roots.appBase, 'data', 'fields.ts')
252
+ const pkgFile = path.join(roots.pkgBase, 'data', 'fields.ts')
253
+ const hasApp = fs.existsSync(appFile)
254
+ const hasPkg = fs.existsSync(pkgFile)
270
255
  if (hasApp || hasPkg) {
271
256
  const importName = `F_${toVar(modId)}_${importId++}`
272
257
  const importPath = hasApp ? `${appImportBase}/data/fields` : `${imps.pkgBase}/data/fields`
@@ -483,9 +468,9 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
483
468
  }
484
469
 
485
470
  // CLI
486
- const cliApp = findModuleFile(roots.appBase, 'cli')
487
- const cliPkg = findModuleFile(roots.pkgBase, 'cli')
488
- const cliPath = cliApp ?? cliPkg
471
+ const cliApp = path.join(roots.appBase, 'cli.ts')
472
+ const cliPkg = path.join(roots.pkgBase, 'cli.ts')
473
+ const cliPath = fs.existsSync(cliApp) ? cliApp : fs.existsSync(cliPkg) ? cliPkg : null
489
474
  if (cliPath) {
490
475
  const importName = `CLI_${toVar(modId)}`
491
476
  const importPath = cliPath.startsWith(roots.appBase) ? `${appImportBase}/cli` : `${imps.pkgBase}/cli`
@@ -525,7 +510,7 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
525
510
  }
526
511
  }
527
512
 
528
- // Subscribers: src/modules/<module>/subscribers/*.ts or *.js
513
+ // Subscribers: src/modules/<module>/subscribers/*.ts
529
514
  const subApp = path.join(roots.appBase, 'subscribers')
530
515
  const subPkg = path.join(roots.pkgBase, 'subscribers')
531
516
  if (fs.existsSync(subApp) || fs.existsSync(subPkg)) {
@@ -535,9 +520,8 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
535
520
  if (e.isDirectory()) {
536
521
  if (e.name === '__tests__' || e.name === '__mocks__') continue
537
522
  walk(path.join(dir, e.name), [...rel, e.name])
538
- } else if (e.isFile() && (e.name.endsWith('.ts') || e.name.endsWith('.js'))) {
539
- if (/\.(test|spec)\.(ts|js)$/.test(e.name)) continue
540
- if (e.name.endsWith('.d.ts')) continue
523
+ } else if (e.isFile() && e.name.endsWith('.ts')) {
524
+ if (/\.(test|spec)\.ts$/.test(e.name)) continue
541
525
  found.push([...rel, e.name].join('/'))
542
526
  }
543
527
  }
@@ -548,12 +532,11 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
548
532
  for (const rel of files) {
549
533
  const segs = rel.split('/')
550
534
  const file = segs.pop()!
551
- const name = file.replace(/\.(ts|js)$/, '')
535
+ const name = file.replace(/\.ts$/, '')
552
536
  const importName = `Subscriber${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
553
537
  const metaName = `SubscriberMeta${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
554
- const appFileTs = path.join(subApp, ...segs, `${name}.ts`)
555
- const appFileJs = path.join(subApp, ...segs, `${name}.js`)
556
- const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
538
+ const appFile = path.join(subApp, ...segs, `${name}.ts`)
539
+ const fromApp = fs.existsSync(appFile)
557
540
  const importPath = `${fromApp ? appImportBase : imps.pkgBase}/subscribers/${[...segs, name].join('/')}`
558
541
  imports.push(`import ${importName}, * as ${metaName} from '${importPath}'`)
559
542
  const sid = [modId, ...segs, name].filter(Boolean).join(':')
@@ -563,7 +546,7 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
563
546
  }
564
547
  }
565
548
 
566
- // Workers: src/modules/<module>/workers/*.ts or *.js
549
+ // Workers: src/modules/<module>/workers/*.ts
567
550
  // Only includes files that export `metadata` with a `queue` property
568
551
  {
569
552
  const wrkApp = path.join(roots.appBase, 'workers')
@@ -575,9 +558,8 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
575
558
  if (e.isDirectory()) {
576
559
  if (e.name === '__tests__' || e.name === '__mocks__') continue
577
560
  walk(path.join(dir, e.name), [...rel, e.name])
578
- } else if (e.isFile() && (e.name.endsWith('.ts') || e.name.endsWith('.js'))) {
579
- if (/\.(test|spec)\.(ts|js)$/.test(e.name)) continue
580
- if (e.name.endsWith('.d.ts')) continue
561
+ } else if (e.isFile() && e.name.endsWith('.ts')) {
562
+ if (/\.(test|spec)\.ts$/.test(e.name)) continue
581
563
  found.push([...rel, e.name].join('/'))
582
564
  }
583
565
  }
@@ -588,10 +570,9 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
588
570
  for (const rel of files) {
589
571
  const segs = rel.split('/')
590
572
  const file = segs.pop()!
591
- const name = file.replace(/\.(ts|js)$/, '')
592
- const appFileTs = path.join(wrkApp, ...segs, `${name}.ts`)
593
- const appFileJs = path.join(wrkApp, ...segs, `${name}.js`)
594
- const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
573
+ const name = file.replace(/\.ts$/, '')
574
+ const appFile = path.join(wrkApp, ...segs, `${name}.ts`)
575
+ const fromApp = fs.existsSync(appFile)
595
576
  // Use package import path for checking exports (file path fails due to relative imports)
596
577
  const importPath = `${fromApp ? appImportBase : imps.pkgBase}/workers/${[...segs, name].join('/')}`
597
578
  // Only include files that export metadata with a queue property
@@ -949,9 +930,9 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
949
930
  let customFieldSetsExpr: string = '[]'
950
931
 
951
932
  // Module metadata: index.ts (overrideable)
952
- const appIndex = findModuleFile(roots.appBase, 'index')
953
- const pkgIndex = findModuleFile(roots.pkgBase, 'index')
954
- const indexTs = appIndex ?? pkgIndex
933
+ const appIndex = path.join(roots.appBase, 'index.ts')
934
+ const pkgIndex = path.join(roots.pkgBase, 'index.ts')
935
+ const indexTs = fs.existsSync(appIndex) ? appIndex : fs.existsSync(pkgIndex) ? pkgIndex : null
955
936
  if (indexTs) {
956
937
  infoImportName = `I${importId++}_${toVar(modId)}`
957
938
  const importPath = indexTs.startsWith(roots.appBase) ? `${appImportBase}/index` : `${imps.pkgBase}/index`
@@ -968,10 +949,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
968
949
 
969
950
  // Entity extensions: src/modules/<module>/data/extensions.ts
970
951
  {
971
- const appFile = findModuleFile(roots.appBase, 'data', 'extensions')
972
- const pkgFile = findModuleFile(roots.pkgBase, 'data', 'extensions')
973
- const hasApp = !!appFile
974
- const hasPkg = !!pkgFile
952
+ const appFile = path.join(roots.appBase, 'data', 'extensions.ts')
953
+ const pkgFile = path.join(roots.pkgBase, 'data', 'extensions.ts')
954
+ const hasApp = fs.existsSync(appFile)
955
+ const hasPkg = fs.existsSync(pkgFile)
975
956
  if (hasApp || hasPkg) {
976
957
  const importName = `X_${toVar(modId)}_${importId++}`
977
958
  const importPath = hasApp ? `${appImportBase}/data/extensions` : `${imps.pkgBase}/data/extensions`
@@ -982,12 +963,12 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
982
963
 
983
964
  // RBAC feature declarations: module root acl.ts
984
965
  {
985
- const rootApp = findModuleFile(roots.appBase, 'acl')
986
- const rootPkg = findModuleFile(roots.pkgBase, 'acl')
987
- const hasRoot = rootApp || rootPkg
966
+ const rootApp = path.join(roots.appBase, 'acl.ts')
967
+ const rootPkg = path.join(roots.pkgBase, 'acl.ts')
968
+ const hasRoot = fs.existsSync(rootApp) || fs.existsSync(rootPkg)
988
969
  if (hasRoot) {
989
970
  const importName = `ACL_${toVar(modId)}_${importId++}`
990
- const useApp = rootApp ?? rootPkg!
971
+ const useApp = fs.existsSync(rootApp) ? rootApp : rootPkg
991
972
  const importPath = useApp.startsWith(roots.appBase) ? `${appImportBase}/acl` : `${imps.pkgBase}/acl`
992
973
  imports.push(`import * as ${importName} from '${importPath}'`)
993
974
  featuresImportName = importName
@@ -996,10 +977,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
996
977
 
997
978
  // Custom entities declarations: module root ce.ts
998
979
  {
999
- const appFile = findModuleFile(roots.appBase, 'ce')
1000
- const pkgFile = findModuleFile(roots.pkgBase, 'ce')
1001
- const hasApp = !!appFile
1002
- const hasPkg = !!pkgFile
980
+ const appFile = path.join(roots.appBase, 'ce.ts')
981
+ const pkgFile = path.join(roots.pkgBase, 'ce.ts')
982
+ const hasApp = fs.existsSync(appFile)
983
+ const hasPkg = fs.existsSync(pkgFile)
1003
984
  if (hasApp || hasPkg) {
1004
985
  const importName = `CE_${toVar(modId)}_${importId++}`
1005
986
  const importPath = hasApp ? `${appImportBase}/ce` : `${imps.pkgBase}/ce`
@@ -1010,10 +991,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1010
991
 
1011
992
  // Vector search configuration: module root vector.ts
1012
993
  {
1013
- const appFile = findModuleFile(roots.appBase, 'vector')
1014
- const pkgFile = findModuleFile(roots.pkgBase, 'vector')
1015
- const hasApp = !!appFile
1016
- const hasPkg = !!pkgFile
994
+ const appFile = path.join(roots.appBase, 'vector.ts')
995
+ const pkgFile = path.join(roots.pkgBase, 'vector.ts')
996
+ const hasApp = fs.existsSync(appFile)
997
+ const hasPkg = fs.existsSync(pkgFile)
1017
998
  if (hasApp || hasPkg) {
1018
999
  const importName = `VECTOR_${toVar(modId)}_${importId++}`
1019
1000
  const importPath = hasApp ? `${appImportBase}/vector` : `${imps.pkgBase}/vector`
@@ -1024,10 +1005,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1024
1005
 
1025
1006
  // Custom field declarations: src/modules/<module>/data/fields.ts
1026
1007
  {
1027
- const appFile = findModuleFile(roots.appBase, 'data', 'fields')
1028
- const pkgFile = findModuleFile(roots.pkgBase, 'data', 'fields')
1029
- const hasApp = !!appFile
1030
- const hasPkg = !!pkgFile
1008
+ const appFile = path.join(roots.appBase, 'data', 'fields.ts')
1009
+ const pkgFile = path.join(roots.pkgBase, 'data', 'fields.ts')
1010
+ const hasApp = fs.existsSync(appFile)
1011
+ const hasPkg = fs.existsSync(pkgFile)
1031
1012
  if (hasApp || hasPkg) {
1032
1013
  const importName = `F_${toVar(modId)}_${importId++}`
1033
1014
  const importPath = hasApp ? `${appImportBase}/data/fields` : `${imps.pkgBase}/data/fields`
@@ -1037,9 +1018,9 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1037
1018
  }
1038
1019
 
1039
1020
  // CLI
1040
- const cliApp = findModuleFile(roots.appBase, 'cli')
1041
- const cliPkg = findModuleFile(roots.pkgBase, 'cli')
1042
- const cliPath = cliApp ?? cliPkg
1021
+ const cliApp = path.join(roots.appBase, 'cli.ts')
1022
+ const cliPkg = path.join(roots.pkgBase, 'cli.ts')
1023
+ const cliPath = fs.existsSync(cliApp) ? cliApp : fs.existsSync(cliPkg) ? cliPkg : null
1043
1024
  if (cliPath) {
1044
1025
  const importName = `CLI_${toVar(modId)}`
1045
1026
  const importPath = cliPath.startsWith(roots.appBase) ? `${appImportBase}/cli` : `${imps.pkgBase}/cli`
@@ -1079,7 +1060,7 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1079
1060
  }
1080
1061
  }
1081
1062
 
1082
- // Subscribers: src/modules/<module>/subscribers/*.ts or *.js
1063
+ // Subscribers: src/modules/<module>/subscribers/*.ts
1083
1064
  const subApp = path.join(roots.appBase, 'subscribers')
1084
1065
  const subPkg = path.join(roots.pkgBase, 'subscribers')
1085
1066
  if (fs.existsSync(subApp) || fs.existsSync(subPkg)) {
@@ -1089,9 +1070,8 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1089
1070
  if (e.isDirectory()) {
1090
1071
  if (e.name === '__tests__' || e.name === '__mocks__') continue
1091
1072
  walk(path.join(dir, e.name), [...rel, e.name])
1092
- } else if (e.isFile() && (e.name.endsWith('.ts') || e.name.endsWith('.js'))) {
1093
- if (/\.(test|spec)\.(ts|js)$/.test(e.name)) continue
1094
- if (e.name.endsWith('.d.ts')) continue
1073
+ } else if (e.isFile() && e.name.endsWith('.ts')) {
1074
+ if (/\.(test|spec)\.ts$/.test(e.name)) continue
1095
1075
  found.push([...rel, e.name].join('/'))
1096
1076
  }
1097
1077
  }
@@ -1102,12 +1082,11 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1102
1082
  for (const rel of files) {
1103
1083
  const segs = rel.split('/')
1104
1084
  const file = segs.pop()!
1105
- const name = file.replace(/\.(ts|js)$/, '')
1085
+ const name = file.replace(/\.ts$/, '')
1106
1086
  const importName = `Subscriber${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
1107
1087
  const metaName = `SubscriberMeta${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
1108
- const appFileTs = path.join(subApp, ...segs, `${name}.ts`)
1109
- const appFileJs = path.join(subApp, ...segs, `${name}.js`)
1110
- const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
1088
+ const appFile = path.join(subApp, ...segs, `${name}.ts`)
1089
+ const fromApp = fs.existsSync(appFile)
1111
1090
  const importPath = `${fromApp ? appImportBase : imps.pkgBase}/subscribers/${[...segs, name].join('/')}`
1112
1091
  imports.push(`import ${importName}, * as ${metaName} from '${importPath}'`)
1113
1092
  const sid = [modId, ...segs, name].filter(Boolean).join(':')
@@ -1117,7 +1096,7 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1117
1096
  }
1118
1097
  }
1119
1098
 
1120
- // Workers: src/modules/<module>/workers/*.ts or *.js
1099
+ // Workers: src/modules/<module>/workers/*.ts
1121
1100
  // Only includes files that export `metadata` with a `queue` property
1122
1101
  {
1123
1102
  const wrkApp = path.join(roots.appBase, 'workers')
@@ -1129,9 +1108,8 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1129
1108
  if (e.isDirectory()) {
1130
1109
  if (e.name === '__tests__' || e.name === '__mocks__') continue
1131
1110
  walk(path.join(dir, e.name), [...rel, e.name])
1132
- } else if (e.isFile() && (e.name.endsWith('.ts') || e.name.endsWith('.js'))) {
1133
- if (/\.(test|spec)\.(ts|js)$/.test(e.name)) continue
1134
- if (e.name.endsWith('.d.ts')) continue
1111
+ } else if (e.isFile() && e.name.endsWith('.ts')) {
1112
+ if (/\.(test|spec)\.ts$/.test(e.name)) continue
1135
1113
  found.push([...rel, e.name].join('/'))
1136
1114
  }
1137
1115
  }
@@ -1142,10 +1120,9 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
1142
1120
  for (const rel of files) {
1143
1121
  const segs = rel.split('/')
1144
1122
  const file = segs.pop()!
1145
- const name = file.replace(/\.(ts|js)$/, '')
1146
- const appFileTs = path.join(wrkApp, ...segs, `${name}.ts`)
1147
- const appFileJs = path.join(wrkApp, ...segs, `${name}.js`)
1148
- const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
1123
+ const name = file.replace(/\.ts$/, '')
1124
+ const appFile = path.join(wrkApp, ...segs, `${name}.ts`)
1125
+ const fromApp = fs.existsSync(appFile)
1149
1126
  // Use package import path for checking exports (file path fails due to relative imports)
1150
1127
  const importPath = `${fromApp ? appImportBase : imps.pkgBase}/workers/${[...segs, name].join('/')}`
1151
1128
  // Only include files that export metadata with a queue property
@@ -28,9 +28,10 @@ export interface PackageResolver {
28
28
 
29
29
  function pkgDirFor(rootDir: string, from?: string, isMonorepo = true): string {
30
30
  if (!isMonorepo) {
31
- // Production mode: look in node_modules dist (compiled JS)
31
+ // Production mode: look in node_modules
32
+ // Packages include source TypeScript files in src/modules
32
33
  const pkgName = from || '@open-mercato/core'
33
- return path.join(rootDir, 'node_modules', pkgName, 'dist', 'modules')
34
+ return path.join(rootDir, 'node_modules', pkgName, 'src', 'modules')
34
35
  }
35
36
 
36
37
  // Monorepo mode
@@ -151,8 +152,8 @@ function discoverPackagesInNodeModules(rootDir: string): PackageInfo[] {
151
152
 
152
153
  try {
153
154
  const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'))
154
- // Production mode: use compiled JS files from dist/modules
155
- const modulesPath = path.join(pkgPath, 'dist', 'modules')
155
+ // Packages include source TypeScript files in src/modules
156
+ const modulesPath = path.join(pkgPath, 'src', 'modules')
156
157
 
157
158
  if (fs.existsSync(modulesPath)) {
158
159
  packages.push({
package/src/mercato.ts CHANGED
@@ -63,25 +63,6 @@ async function runModuleCommand(
63
63
  await cmd.run(args)
64
64
  }
65
65
 
66
- // Helper to run a module command, skipping silently if module is not enabled
67
- async function tryRunModuleCommand(
68
- allModules: Module[],
69
- moduleName: string,
70
- commandName: string,
71
- args: string[] = []
72
- ): Promise<boolean> {
73
- const mod = allModules.find((m) => m.id === moduleName)
74
- if (!mod || !mod.cli || mod.cli.length === 0) {
75
- return false
76
- }
77
- const cmd = mod.cli.find((c) => c.command === commandName)
78
- if (!cmd) {
79
- return false
80
- }
81
- await cmd.run(args)
82
- return true
83
- }
84
-
85
66
  // Build all CLI modules (registered + built-in)
86
67
  async function buildAllModules(): Promise<Module[]> {
87
68
  const modules = getCliModules()
@@ -319,13 +300,13 @@ export async function run(argv = process.argv) {
319
300
  await runModuleCommand(allModules, 'customers', 'seed-dictionaries', ['--tenant', tenantId, '--org', orgId])
320
301
  console.log('๐Ÿ“š โœ… Customer dictionaries seeded\n')
321
302
 
322
- if (await tryRunModuleCommand(allModules, 'staff', 'seed-address-types', ['--tenant', tenantId, '--org', orgId])) {
323
- console.log('๐Ÿ  โœ… Staff address types seeded\n')
324
- }
303
+ console.log('๐Ÿ  Seeding staff address types...')
304
+ await runModuleCommand(allModules, 'staff', 'seed-address-types', ['--tenant', tenantId, '--org', orgId])
305
+ console.log('๐Ÿ  โœ… Staff address types seeded\n')
325
306
 
326
- if (await tryRunModuleCommand(allModules, 'resources', 'seed-address-types', ['--tenant', tenantId, '--org', orgId])) {
327
- console.log('๐Ÿ  โœ… Resources address types seeded\n')
328
- }
307
+ console.log('๐Ÿ  Seeding resources address types...')
308
+ await runModuleCommand(allModules, 'resources', 'seed-address-types', ['--tenant', tenantId, '--org', orgId])
309
+ console.log('๐Ÿ  โœ… Resources address types seeded\n')
329
310
 
330
311
  console.log('๐Ÿ“š Seeding currencies...')
331
312
  await runModuleCommand(allModules, 'currencies', 'seed', ['--tenant', tenantId, '--org', orgId])
@@ -335,9 +316,9 @@ export async function run(argv = process.argv) {
335
316
  await runModuleCommand(allModules, 'catalog', 'seed-units', ['--tenant', tenantId, '--org', orgId])
336
317
  console.log('๐Ÿ“ โœ… Catalog units seeded\n')
337
318
 
338
- if (await tryRunModuleCommand(allModules, 'planner', 'seed-unavailability-reasons', ['--tenant', tenantId, '--org', orgId])) {
339
- console.log('๐Ÿ—“๏ธ โœ… Unavailability reasons seeded\n')
340
- }
319
+ console.log('๐Ÿ—“๏ธ Seeding unavailability reasons...')
320
+ await runModuleCommand(allModules, 'planner', 'seed-unavailability-reasons', ['--tenant', tenantId, '--org', orgId])
321
+ console.log('๐Ÿ—“๏ธ โœ… Unavailability reasons seeded\n')
341
322
 
342
323
  const parsedEncryption = parseBooleanToken(process.env.TENANT_DATA_ENCRYPTION ?? 'yes')
343
324
  const encryptionEnabled = parsedEncryption === null ? true : parsedEncryption
@@ -396,21 +377,21 @@ export async function run(argv = process.argv) {
396
377
  await runModuleCommand(allModules, 'sales', 'seed-examples', ['--tenant', tenantId, '--org', orgId])
397
378
  console.log('๐Ÿงพ โœ… Sales examples seeded\n')
398
379
 
399
- if (await tryRunModuleCommand(allModules, 'staff', 'seed-examples', ['--tenant', tenantId, '--org', orgId])) {
400
- console.log('๐Ÿ‘ฅ โœ… Staff examples seeded\n')
401
- }
380
+ console.log('๐Ÿ‘ฅ Seeding staff examples...')
381
+ await runModuleCommand(allModules, 'staff', 'seed-examples', ['--tenant', tenantId, '--org', orgId])
382
+ console.log('๐Ÿ‘ฅ โœ… Staff examples seeded\n')
402
383
 
403
- if (await tryRunModuleCommand(allModules, 'resources', 'seed-capacity-units', ['--tenant', tenantId, '--org', orgId])) {
404
- console.log('๐Ÿ“ฆ โœ… Resource capacity units seeded\n')
405
- }
384
+ console.log('๐Ÿ“ฆ Seeding resource capacity units...')
385
+ await runModuleCommand(allModules, 'resources', 'seed-capacity-units', ['--tenant', tenantId, '--org', orgId])
386
+ console.log('๐Ÿ“ฆ โœ… Resource capacity units seeded\n')
406
387
 
407
- if (await tryRunModuleCommand(allModules, 'resources', 'seed-examples', ['--tenant', tenantId, '--org', orgId])) {
408
- console.log('๐Ÿงฐ โœ… Resource examples seeded\n')
409
- }
388
+ console.log('๐Ÿงฐ Seeding resource examples...')
389
+ await runModuleCommand(allModules, 'resources', 'seed-examples', ['--tenant', tenantId, '--org', orgId])
390
+ console.log('๐Ÿงฐ โœ… Resource examples seeded\n')
410
391
 
411
- if (await tryRunModuleCommand(allModules, 'planner', 'seed-availability-rulesets', ['--tenant', tenantId, '--org', orgId])) {
412
- console.log('๐Ÿ—“๏ธ โœ… Planner availability rulesets seeded\n')
413
- }
392
+ console.log('๐Ÿ—“๏ธ Seeding planner availability rulesets...')
393
+ await runModuleCommand(allModules, 'planner', 'seed-availability-rulesets', ['--tenant', tenantId, '--org', orgId])
394
+ console.log('๐Ÿ—“๏ธ โœ… Planner availability rulesets seeded\n')
414
395
 
415
396
  // Optional: seed example todos if the example module is enabled
416
397
  const exampleModule = allModules.find((m) => m.id === 'example')