@open-mercato/cli 0.7.1-develop.7137.1.26575786c0 → 0.7.1-develop.7149.1.7efa6e1612

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 (81) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +2 -0
  3. package/dist/agentic/guides/module-facts.json +128 -128
  4. package/dist/agentic/guides/module-facts.v2.json +128 -128
  5. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  6. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  7. package/dist/agentic/guides/modules/api_keys/index.md +1 -1
  8. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  9. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  10. package/dist/agentic/guides/modules/auth/index.md +1 -1
  11. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  12. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  13. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  14. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  15. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  16. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  17. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  18. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  19. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  20. package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
  21. package/dist/agentic/guides/modules/configs/index.md +1 -1
  22. package/dist/agentic/guides/modules/content/index.md +1 -1
  23. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  24. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  25. package/dist/agentic/guides/modules/customers/index.md +1 -1
  26. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  27. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  28. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  29. package/dist/agentic/guides/modules/devices/index.md +1 -1
  30. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  31. package/dist/agentic/guides/modules/directory/index.md +1 -1
  32. package/dist/agentic/guides/modules/documents/index.md +1 -1
  33. package/dist/agentic/guides/modules/entities/index.md +1 -1
  34. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  35. package/dist/agentic/guides/modules/events/index.md +1 -1
  36. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  37. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  38. package/dist/agentic/guides/modules/generators/index.md +1 -1
  39. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  40. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  41. package/dist/agentic/guides/modules/messages/index.md +1 -1
  42. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  43. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  44. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  45. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  46. package/dist/agentic/guides/modules/planner/index.md +1 -1
  47. package/dist/agentic/guides/modules/portal/index.md +1 -1
  48. package/dist/agentic/guides/modules/progress/index.md +1 -1
  49. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  50. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  51. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  52. package/dist/agentic/guides/modules/resources/index.md +1 -1
  53. package/dist/agentic/guides/modules/sales/index.md +1 -1
  54. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  55. package/dist/agentic/guides/modules/search/index.md +1 -1
  56. package/dist/agentic/guides/modules/security/index.md +1 -1
  57. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  58. package/dist/agentic/guides/modules/sso/index.md +1 -1
  59. package/dist/agentic/guides/modules/staff/index.md +1 -1
  60. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  61. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  62. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  63. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  64. package/dist/agentic/guides/modules/translations/index.md +1 -1
  65. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  66. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  67. package/dist/agentic/guides/modules/wms/index.md +1 -1
  68. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  69. package/dist/agentic/guides/reference-module-facts.json +1 -1
  70. package/dist/agentic/guides/upstream/manifest.json +1 -1
  71. package/dist/agentic/shared/ai/review-checklist.md +1 -0
  72. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +30 -2
  73. package/dist/lib/db/commands.js +106 -60
  74. package/dist/lib/db/commands.js.map +2 -2
  75. package/dist/lib/db/migration-reindex.js +104 -0
  76. package/dist/lib/db/migration-reindex.js.map +7 -0
  77. package/package.json +6 -6
  78. package/src/lib/db/__tests__/commands.migrate-reindex.test.ts +189 -0
  79. package/src/lib/db/__tests__/migration-reindex.test.ts +203 -0
  80. package/src/lib/db/commands.ts +132 -72
  81. package/src/lib/db/migration-reindex.ts +156 -0
@@ -7,9 +7,37 @@ Load this reference whenever entity metadata changes.
7
7
  3. Run `yarn db:generate` as a probe; inspect all SQL and snapshot changes.
8
8
  4. Remove unrelated generator churn. If scoped SQL must be written from known metadata, follow the module's existing migration style and update only its snapshot.
9
9
  5. Verify forward migration semantics, uniqueness/index names, nullable/default/backfill behavior, and safe rollback/compatibility strategy.
10
- 6. Never modify a shipped migration. Add a new one.
11
- 7. Ask before `yarn db:migrate`, greenfield reset, or changing a database target.
10
+ 6. Declare the query-index projections the migration invalidated (see below).
11
+ 7. Never modify a shipped migration. Add a new one.
12
+ 8. Ask before `yarn db:migrate`, greenfield reset, or changing a database target.
12
13
 
13
14
  Normal delivery stops after migration file/snapshot/tests; local applied state is not a PR artifact.
14
15
 
15
16
  Canonical example source — the shape `yarn db:generate` produces and diffs against: [`migrations/Migration20251030150038.ts`](../../../../src/modules/example/migrations/Migration20251030150038.ts), [`migrations/Migration20260226161000_example.ts`](../../../../src/modules/example/migrations/Migration20260226161000_example.ts), and the module-scoped [`migrations/.snapshot-open-mercato.json`](../../../../src/modules/example/migrations/.snapshot-open-mercato.json). Read them for style; never copy a migration into your own module.
17
+
18
+ ## Data migrations MUST declare the projections they invalidate
19
+
20
+ A migration that rewrites the VALUES of a column in raw SQL — a backfill, a rename, a
21
+ normalization — bypasses every CRUD/indexer helper that would emit `query_index.upsert_one`.
22
+ `entity_indexes.doc`, and every `search_tokens` row derived from it, then keeps the
23
+ pre-migration value permanently, with no failing job and no moved `updated_at` to signal it.
24
+ Global search and any `like`/`ilike` list filter routed through the token index then match the
25
+ record by its OLD text and miss its NEW text.
26
+
27
+ A migration cannot emit the refresh itself — it holds no DI container, and the projection must
28
+ only be rebuilt once its own transaction has committed. So it **declares**, and
29
+ `mercato db migrate` discharges the obligation after the run:
30
+
31
+ ```ts
32
+ import { declareQueryIndexReindex } from '@open-mercato/shared/lib/query/migration-reindex'
33
+
34
+ export const queryIndexReindexEntityTypes = declareQueryIndexReindex(['my_module:my_entity'])
35
+ ```
36
+
37
+ - Required whenever the migration changes stored values of a column on an entity whose CRUD route
38
+ sets `indexer: { entityType }`. Pure `ADD COLUMN`/`CREATE TABLE` DDL with no backfill needs nothing.
39
+ - Identifiers are `module:entity` (snake_case, exactly the `indexer.entityType` value). Use the
40
+ helper rather than a bare array literal — it throws on a malformed identifier at import time,
41
+ whereas a hand-written literal is only reported as a warning during `db migrate`.
42
+ - Both originals forward-only? A follow-up migration that carries **only** the declaration and
43
+ executes no SQL is the repair route for installs that already applied the original.
@@ -7,6 +7,11 @@ import { ReflectMetadataProvider } from "@mikro-orm/decorators/legacy";
7
7
  import { PostgreSqlDriver } from "@mikro-orm/postgresql";
8
8
  import { getSslConfig } from "@open-mercato/shared/lib/db/ssl";
9
9
  import { quotePostgresIdentifier } from "./identifiers.js";
10
+ import {
11
+ collectQueryIndexReindexEntityTypes,
12
+ isMigrationReindexEnabled,
13
+ requestQueryIndexReindex
14
+ } from "./migration-reindex.js";
10
15
  const QUIET_MODE = process.env.OM_CLI_QUIET === "1" || process.env.MERCATO_QUIET === "1";
11
16
  const PROGRESS_EMOJI = "";
12
17
  function formatResult(modId, message, emoji = "\u2022") {
@@ -256,70 +261,110 @@ async function dbMigrate(resolver, options = {}) {
256
261
  const modules = resolver.loadEnabledModules();
257
262
  const ordered = sortModules(modules);
258
263
  const results = [];
259
- for (const entry of ordered) {
260
- const modId = entry.id;
261
- const sanitizedModId = sanitizeModuleId(modId);
262
- const entities = await loadModuleEntities(entry, resolver);
263
- const migrationsPath = getMigrationsPath(entry, resolver);
264
- if (!entities.length && !fs.existsSync(migrationsPath)) continue;
265
- fs.mkdirSync(migrationsPath, { recursive: true });
266
- const tableName = `mikro_orm_migrations_${sanitizedModId}`;
267
- validateTableName(tableName);
268
- const sslConfig = getSslConfig();
269
- const orm = await MikroORM.init({
270
- driver: PostgreSqlDriver,
271
- clientUrl: getClientUrl(),
272
- loggerFactory: () => createMinimalLogger(),
273
- dynamicImportProvider,
274
- entities: [],
275
- metadataProvider: ReflectMetadataProvider,
276
- discovery: { warnWhenNoEntities: false },
277
- migrations: {
278
- path: migrationsPath,
279
- glob: "!(*.d).{ts,js}",
280
- tableName,
281
- snapshot: false,
282
- dropTables: false
283
- },
284
- schemaGenerator: {
285
- disableForeignKeys: true
286
- },
287
- pool: {
288
- min: 1,
289
- max: 3,
290
- idleTimeoutMillis: 3e4
291
- // acquireTimeoutMillis removed for v7 (pg.Pool doesn't support it; use connectionTimeoutMillis in driverOptions if needed)
292
- },
293
- driverOptions: sslConfig ? {
294
- ssl: sslConfig
295
- } : void 0
296
- });
297
- const migrator = orm.migrator;
298
- const pending = await migrator.getPending();
299
- if (!pending.length) {
300
- results.push(formatResult(modId, "no pending migrations", ""));
301
- } else {
302
- const renderProgress = createProgressRenderer(pending.length);
303
- let applied = 0;
304
- if (!QUIET_MODE) {
305
- process.stdout.write(` ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`);
306
- }
307
- for (const migration of pending) {
308
- const migrationName = typeof migration === "string" ? migration : migration.name ?? migration.fileName;
309
- await migrator.up(migrationName ? { migrations: [migrationName] } : void 0);
310
- applied += 1;
311
- if (!QUIET_MODE) {
312
- process.stdout.write(`\r ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`);
264
+ const appliedMigrations = [];
265
+ try {
266
+ for (const entry of ordered) {
267
+ const modId = entry.id;
268
+ const sanitizedModId = sanitizeModuleId(modId);
269
+ const entities = await loadModuleEntities(entry, resolver);
270
+ const migrationsPath = getMigrationsPath(entry, resolver);
271
+ if (!entities.length && !fs.existsSync(migrationsPath)) continue;
272
+ fs.mkdirSync(migrationsPath, { recursive: true });
273
+ const tableName = `mikro_orm_migrations_${sanitizedModId}`;
274
+ validateTableName(tableName);
275
+ const sslConfig = getSslConfig();
276
+ const orm = await MikroORM.init({
277
+ driver: PostgreSqlDriver,
278
+ clientUrl: getClientUrl(),
279
+ loggerFactory: () => createMinimalLogger(),
280
+ dynamicImportProvider,
281
+ entities: [],
282
+ metadataProvider: ReflectMetadataProvider,
283
+ discovery: { warnWhenNoEntities: false },
284
+ migrations: {
285
+ path: migrationsPath,
286
+ glob: "!(*.d).{ts,js}",
287
+ tableName,
288
+ snapshot: false,
289
+ dropTables: false
290
+ },
291
+ schemaGenerator: {
292
+ disableForeignKeys: true
293
+ },
294
+ pool: {
295
+ min: 1,
296
+ max: 3,
297
+ idleTimeoutMillis: 3e4
298
+ // acquireTimeoutMillis removed for v7 (pg.Pool doesn't support it; use connectionTimeoutMillis in driverOptions if needed)
299
+ },
300
+ driverOptions: sslConfig ? {
301
+ ssl: sslConfig
302
+ } : void 0
303
+ });
304
+ try {
305
+ const migrator = orm.migrator;
306
+ const pending = await migrator.getPending();
307
+ if (!pending.length) {
308
+ results.push(formatResult(modId, "no pending migrations", ""));
309
+ } else {
310
+ const renderProgress = createProgressRenderer(pending.length);
311
+ let applied = 0;
312
+ if (!QUIET_MODE) {
313
+ process.stdout.write(` ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`);
314
+ }
315
+ for (const migration of pending) {
316
+ const migrationName = typeof migration === "string" ? migration : migration.name ?? migration.fileName;
317
+ await migrator.up(migrationName ? { migrations: [migrationName] } : void 0);
318
+ if (migrationName) {
319
+ appliedMigrations.push({
320
+ moduleId: modId,
321
+ migrationsPath,
322
+ name: String(migrationName),
323
+ filePath: typeof migration === "string" ? null : migration.path ?? null
324
+ });
325
+ }
326
+ applied += 1;
327
+ if (!QUIET_MODE) {
328
+ process.stdout.write(`\r ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`);
329
+ }
330
+ }
331
+ if (!QUIET_MODE) process.stdout.write("\n");
332
+ results.push(
333
+ formatResult(modId, `${pending.length} migration${pending.length === 1 ? "" : "s"} applied`, "")
334
+ );
313
335
  }
336
+ } finally {
337
+ await orm.close(true);
314
338
  }
315
- if (!QUIET_MODE) process.stdout.write("\n");
316
- results.push(
317
- formatResult(modId, `${pending.length} migration${pending.length === 1 ? "" : "s"} applied`, "")
318
- );
319
339
  }
320
- await orm.close(true);
340
+ } finally {
341
+ console.log(results.join("\n"));
342
+ await dischargeQueryIndexReindexRequests(appliedMigrations);
343
+ }
344
+ }
345
+ async function dischargeQueryIndexReindexRequests(applied) {
346
+ if (!applied.length || !isMigrationReindexEnabled()) return;
347
+ try {
348
+ const entityTypes = await collectQueryIndexReindexEntityTypes(applied, {
349
+ importModule: dynamicImportProvider,
350
+ onWarn: (message) => console.warn(message)
351
+ });
352
+ if (!entityTypes.length) return;
353
+ await requestQueryIndexReindex(entityTypes, {
354
+ createContainer: async () => {
355
+ const { createRequestContainer } = await import("@open-mercato/shared/lib/di/container");
356
+ return await createRequestContainer();
357
+ },
358
+ onInfo: (message) => {
359
+ if (!QUIET_MODE) console.log(message);
360
+ },
361
+ onWarn: (message) => console.warn(message)
362
+ });
363
+ } catch (error) {
364
+ console.warn(
365
+ `[query_index] Could not determine which projections the migrations invalidated: ${error instanceof Error ? error.message : String(error)}`
366
+ );
321
367
  }
322
- console.log(results.join("\n"));
323
368
  }
324
369
  async function dbGreenfield(resolver, options) {
325
370
  if (!options.yes) {
@@ -439,6 +484,7 @@ export {
439
484
  dbGenerate,
440
485
  dbGreenfield,
441
486
  dbMigrate,
487
+ dischargeQueryIndexReindexRequests,
442
488
  getMigrationSnapshotName,
443
489
  makeConstraintDropsIdempotent,
444
490
  resolveGeneratedMigrationPath,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/db/commands.ts"],
4
- "sourcesContent": ["import path from 'node:path'\nimport fs from 'node:fs'\nimport { pathToFileURL } from 'node:url'\nimport ts from 'typescript-js'\nimport { MikroORM, MetadataStorage, type Logger } from '@mikro-orm/core'\nimport { ReflectMetadataProvider } from '@mikro-orm/decorators/legacy'\nimport { Migrator } from '@mikro-orm/migrations'\nimport { PostgreSqlDriver } from '@mikro-orm/postgresql'\nimport { getSslConfig } from '@open-mercato/shared/lib/db/ssl'\nimport type { PackageResolver, ModuleEntry } from '../resolver'\nimport { quotePostgresIdentifier } from './identifiers'\n\nconst QUIET_MODE = process.env.OM_CLI_QUIET === '1' || process.env.MERCATO_QUIET === '1'\nconst PROGRESS_EMOJI = ''\n\nfunction formatResult(modId: string, message: string, emoji = '\\u2022') {\n return `${emoji} ${modId}: ${message}`\n}\n\nfunction createProgressRenderer(total: number) {\n const width = 20\n const normalizedTotal = total > 0 ? total : 1\n return (current: number) => {\n const clamped = Math.min(Math.max(current, 0), normalizedTotal)\n const filled = Math.round((clamped / normalizedTotal) * width)\n const bar = `${'='.repeat(filled)}${'.'.repeat(Math.max(width - filled, 0))}`\n return `[${bar}] ${clamped}/${normalizedTotal}`\n }\n}\n\nfunction createMinimalLogger(): Logger {\n return {\n log: () => { },\n error: (_namespace, message) => console.error(message),\n warn: (_namespace, message) => {\n if (!QUIET_MODE) console.warn(message)\n },\n logQuery: () => { },\n setDebugMode: () => { },\n isEnabled: () => false,\n }\n}\n\nfunction getClientUrl(): string {\n const url = process.env.DATABASE_URL\n if (!url) throw new Error('DATABASE_URL is not set')\n return url\n}\n\nfunction sortModules(mods: ModuleEntry[]): ModuleEntry[] {\n // Sort modules alphabetically since they are now isomorphic\n return mods.slice().sort((a, b) => a.id.localeCompare(b.id))\n}\n\n/**\n * Custom dynamic import provider for MikroORM that properly handles Windows paths.\n * MikroORM's built-in handling has a bug where it converts file:// URLs back to\n * Windows paths when the extension isn't in require.extensions (which is always\n * true for .ts files in ESM mode).\n */\nasync function dynamicImportProvider(id: string): Promise<any> {\n // On Windows, convert absolute paths to file:// URLs\n // Check if it's a Windows absolute path (e.g., C:\\... or D:\\...)\n if (process.platform === 'win32' && /^[a-zA-Z]:[\\\\/]/.test(id)) {\n id = pathToFileURL(id).href\n }\n return import(id)\n}\n\n/**\n * Sanitizes a module ID for use in SQL identifiers (table names).\n * Replaces non-alphanumeric characters with underscores to prevent SQL injection.\n * @public Exported for testing\n */\nexport function sanitizeModuleId(modId: string): string {\n return modId.replace(/[^a-z0-9_]/gi, '_')\n}\n\n/**\n * Validates that a table name is safe for use in SQL queries.\n * @throws Error if the table name contains invalid characters.\n * @public Exported for testing\n */\nexport function validateTableName(tableName: string): void {\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {\n throw new Error(`Invalid table name: ${tableName}. Table names must start with a letter or underscore and contain only alphanumeric characters and underscores.`)\n }\n}\n\nexport function makeConstraintDropsIdempotent(sql: string): string {\n return sql.replace(/alter table\\s+(\"[^\"]+\"|\\S+)\\s+drop constraint\\s+(\"[^\"]+\"|\\S+);/gi, 'alter table $1 drop constraint if exists $2;')\n}\n\nexport function getMigrationSnapshotName(resolver: Pick<PackageResolver, 'getRootDir'>): string {\n void resolver\n return '.snapshot-open-mercato'\n}\n\nexport function shouldCreateInitialModuleMigration(migrationsPath: string, snapshotName: string): boolean {\n const snapshotPath = path.join(migrationsPath, `${snapshotName}.json`)\n if (fs.existsSync(snapshotPath)) return false\n if (!fs.existsSync(migrationsPath)) return true\n\n const migrationFiles = fs\n .readdirSync(migrationsPath)\n .filter((file) => /^Migration.*\\.(ts|js)$/.test(file) && !file.endsWith('.d.ts'))\n\n return migrationFiles.length === 0\n}\n\nexport function resolveGeneratedMigrationPath(fileName: string, migrationsPath: string): string {\n return path.isAbsolute(fileName) ? fileName : path.join(migrationsPath, fileName)\n}\n\nlet tsxLoaderRegistered = false\nlet temporaryModuleCounter = 0\n\nasync function ensureTsxLoaderRegistered() {\n if (tsxLoaderRegistered) return\n try {\n const { register } = await import('tsx/esm/api')\n register()\n tsxLoaderRegistered = true\n } catch {\n // Continue without the loader. Relative TypeScript imports may fail in this case.\n }\n}\n\nasync function importWithTypeScriptFile(filePath: string): Promise<any> {\n await ensureTsxLoaderRegistered()\n const source = fs.readFileSync(filePath, 'utf8')\n const compiled = ts.transpileModule(source, {\n fileName: filePath,\n compilerOptions: {\n module: ts.ModuleKind.ESNext,\n target: ts.ScriptTarget.ES2022,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n esModuleInterop: true,\n resolveJsonModule: true,\n jsx: ts.JsxEmit.ReactJSX,\n experimentalDecorators: true,\n emitDecoratorMetadata: false,\n useDefineForClassFields: false,\n },\n }).outputText\n const tempPath = `${filePath}.mercato-db-generate-${process.pid}-${temporaryModuleCounter++}.mjs`\n fs.writeFileSync(tempPath, compiled, 'utf8')\n try {\n return await import(pathToFileURL(tempPath).href)\n } finally {\n try {\n fs.unlinkSync(tempPath)\n } catch {\n // Ignore cleanup failures for temporary compiled modules.\n }\n }\n}\n\nasync function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver): Promise<any[]> {\n const roots = resolver.getModulePaths(entry)\n const imps = resolver.getModuleImportBase(entry)\n const isAppModule = entry.from === '@app'\n const shouldImportFromSource = isAppModule || resolver.isMonorepo()\n const bases = [\n path.join(roots.appBase, 'data'),\n path.join(roots.pkgBase, 'data'),\n path.join(roots.appBase, 'db'),\n path.join(roots.pkgBase, 'db'),\n ]\n const candidates = ['entities.ts', 'schema.ts']\n\n for (const base of bases) {\n for (const f of candidates) {\n const p = path.join(base, f)\n if (fs.existsSync(p)) {\n const sub = path.basename(base)\n const fromApp = base.startsWith(roots.appBase)\n const importPath = fromApp || shouldImportFromSource\n ? pathToFileURL(p).href\n : `${imps.pkgBase}/${sub}/${f.replace(/\\.ts$/, '')}`\n try {\n const mod = fromApp || shouldImportFromSource\n ? await importWithTypeScriptFile(p)\n : await import(importPath)\n const entities = Object.values(mod).filter((v) => typeof v === 'function')\n if (entities.length) return entities as any[]\n } catch (err) {\n // For @app modules we try a TS loader fallback; otherwise propagate errors\n if (isAppModule) {\n if (process.env.MERCATO_CLI_DEBUG_IMPORTS === '1') {\n console.warn(`[db] failed to load app module entities from ${p}: ${(err as Error)?.message || String(err)}`)\n }\n continue\n }\n throw err\n }\n }\n }\n }\n return []\n}\n\nfunction getMigrationsPath(entry: ModuleEntry, resolver: PackageResolver): string {\n const roots = resolver.getModulePaths(entry)\n\n if (entry.from === '@app') {\n // @app modules: use src/ (user's TypeScript source)\n // Normalize to forward slashes for ESM compatibility on Windows\n return path.join(roots.appBase, 'migrations').replace(/\\\\/g, '/')\n }\n\n // Package modules: in standalone mode, use dist/ (compiled JS) since Node.js\n // can't run TypeScript from node_modules. In monorepo, use src/ (TypeScript).\n if (!resolver.isMonorepo()) {\n // Replace src/modules with dist/modules for standalone apps\n // Use regex to handle both forward and backslashes\n const distPath = roots.pkgBase.replace(/[/\\\\]src[/\\\\]modules[/\\\\]/, '/dist/modules/')\n return path.join(distPath, 'migrations').replace(/\\\\/g, '/')\n }\n\n // Normalize to forward slashes for ESM compatibility on Windows\n return path.join(roots.pkgBase, 'migrations').replace(/\\\\/g, '/')\n}\n\nexport interface DbOptions {\n quiet?: boolean\n}\n\nexport interface GreenfieldOptions extends DbOptions {\n yes: boolean\n}\n\nexport async function dbGenerate(resolver: PackageResolver, options: DbOptions = {}): Promise<void> {\n const modules = resolver.loadEnabledModules()\n const ordered = sortModules(modules)\n const results: string[] = []\n\n const sslConfig = getSslConfig()\n const usedFileNames = new Set<string>()\n\n for (const entry of ordered) {\n // Clear the global @Entity() decorator registry before loading this module's\n // entities. MikroORM's migrator reads MetadataStorage at createMigration()\n // time, so without this clear, every module's migration would include every\n // previously-loaded module's tables (see issue #1911).\n MetadataStorage.clear()\n\n const modId = entry.id\n const sanitizedModId = sanitizeModuleId(modId)\n const entities = await loadModuleEntities(entry, resolver)\n if (!entities.length) {\n if (entry.from === '@app') {\n results.push(formatResult(modId, 'no entities discovered', ''))\n }\n continue\n }\n\n const migrationsPath = getMigrationsPath(entry, resolver)\n fs.mkdirSync(migrationsPath, { recursive: true })\n\n const tableName = `mikro_orm_migrations_${sanitizedModId}`\n validateTableName(tableName)\n const snapshotName = getMigrationSnapshotName(resolver)\n const createInitialMigration = shouldCreateInitialModuleMigration(migrationsPath, snapshotName)\n\n const orm = await MikroORM.init<PostgreSqlDriver>({\n driver: PostgreSqlDriver,\n clientUrl: getClientUrl(),\n loggerFactory: () => createMinimalLogger(),\n dynamicImportProvider,\n entities,\n metadataProvider: ReflectMetadataProvider,\n migrations: {\n path: migrationsPath,\n glob: '!(*.d).{ts,js}',\n tableName,\n snapshotName,\n dropTables: false,\n },\n schemaGenerator: {\n disableForeignKeys: true,\n },\n pool: {\n min: 1,\n max: 3,\n idleTimeoutMillis: 30000,\n // acquireTimeoutMillis removed for v7 (pg.Pool doesn't support it; use connectionTimeoutMillis in driverOptions if needed)\n },\n driverOptions: sslConfig ? {\n ssl: sslConfig,\n } : undefined,\n })\n\n try {\n const diff = await orm.migrator.create(undefined, false, createInitialMigration)\n if (diff && diff.fileName) {\n try {\n const orig = resolveGeneratedMigrationPath(diff.fileName, migrationsPath)\n const base = path.basename(orig)\n const dir = path.dirname(orig)\n const ext = path.extname(base)\n const stem = base.replace(ext, '')\n const suffix = `_${modId}`\n let candidate = stem.endsWith(suffix) ? base : `${stem}${suffix}${ext}`\n let dedupe = 1\n\n while (usedFileNames.has(path.join(dir, candidate))) {\n candidate = `${stem}${suffix}_${dedupe++}${ext}`\n }\n\n const newPath = path.join(dir, candidate)\n let content = fs.readFileSync(orig, 'utf8')\n content = makeConstraintDropsIdempotent(content)\n content = content.replace(\n /export class (Migration\\d+)/,\n `export class $1_${modId.replace(/[^a-zA-Z0-9]/g, '_')}`\n )\n fs.writeFileSync(newPath, content, 'utf8')\n if (newPath !== orig) fs.unlinkSync(orig)\n usedFileNames.add(newPath)\n results.push(formatResult(modId, `generated ${path.basename(newPath)}`, ''))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n results.push(formatResult(modId, `generated ${path.basename(diff.fileName)} (rename failed: ${message})`, ''))\n }\n } else {\n results.push(formatResult(modId, 'no changes', ''))\n }\n } finally {\n await orm.close(true)\n }\n }\n\n console.log(results.join('\\n'))\n}\n\nexport async function dbMigrate(resolver: PackageResolver, options: DbOptions = {}): Promise<void> {\n const modules = resolver.loadEnabledModules()\n const ordered = sortModules(modules)\n const results: string[] = []\n\n for (const entry of ordered) {\n const modId = entry.id\n const sanitizedModId = sanitizeModuleId(modId)\n const entities = await loadModuleEntities(entry, resolver)\n\n const migrationsPath = getMigrationsPath(entry, resolver)\n\n // Skip if no entities AND no migrations directory exists\n // (allows @app modules to run migrations even if entities can't be dynamically imported)\n if (!entities.length && !fs.existsSync(migrationsPath)) continue\n fs.mkdirSync(migrationsPath, { recursive: true })\n\n const tableName = `mikro_orm_migrations_${sanitizedModId}`\n validateTableName(tableName)\n\n // dbMigrate only runs existing migration files \u2014 entities are intentionally\n // omitted so MikroORM does not compare them against the snapshot and\n // auto-generate a phantom diff migration (that would duplicate tables\n // already created by committed migrations).\n const sslConfig = getSslConfig()\n const orm = await MikroORM.init<PostgreSqlDriver>({\n driver: PostgreSqlDriver,\n clientUrl: getClientUrl(),\n loggerFactory: () => createMinimalLogger(),\n dynamicImportProvider,\n entities: [],\n metadataProvider: ReflectMetadataProvider,\n discovery: { warnWhenNoEntities: false },\n migrations: {\n path: migrationsPath,\n glob: '!(*.d).{ts,js}',\n tableName,\n snapshot: false,\n dropTables: false,\n },\n schemaGenerator: {\n disableForeignKeys: true,\n },\n pool: {\n min: 1,\n max: 3,\n idleTimeoutMillis: 30000,\n // acquireTimeoutMillis removed for v7 (pg.Pool doesn't support it; use connectionTimeoutMillis in driverOptions if needed)\n },\n driverOptions: sslConfig ? {\n ssl: sslConfig,\n } : undefined,\n })\n\n const migrator = orm.migrator as Migrator\n const pending = await migrator.getPending()\n if (!pending.length) {\n results.push(formatResult(modId, 'no pending migrations', ''))\n } else {\n const renderProgress = createProgressRenderer(pending.length)\n let applied = 0\n if (!QUIET_MODE) {\n process.stdout.write(` ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`)\n }\n for (const migration of pending) {\n const migrationName =\n typeof migration === 'string'\n ? migration\n : (migration as any).name ?? (migration as any).fileName\n await migrator.up(migrationName ? { migrations: [migrationName] } : undefined)\n applied += 1\n if (!QUIET_MODE) {\n process.stdout.write(`\\r ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`)\n }\n }\n if (!QUIET_MODE) process.stdout.write('\\n')\n results.push(\n formatResult(modId, `${pending.length} migration${pending.length === 1 ? '' : 's'} applied`, '')\n )\n }\n\n await orm.close(true)\n }\n\n console.log(results.join('\\n'))\n}\n\nexport async function dbGreenfield(resolver: PackageResolver, options: GreenfieldOptions): Promise<void> {\n if (!options.yes) {\n console.error('This command will DELETE all data. Use --yes to confirm.')\n process.exit(1)\n }\n\n console.log('Cleaning up migrations and snapshots for greenfield setup...')\n\n const modules = resolver.loadEnabledModules()\n const ordered = sortModules(modules)\n const results: string[] = []\n const outputDir = resolver.getOutputDir()\n\n for (const entry of ordered) {\n const modId = entry.id\n const migrationsPath = getMigrationsPath(entry, resolver)\n\n if (fs.existsSync(migrationsPath)) {\n // Remove all migration files\n const migrationFiles = fs\n .readdirSync(migrationsPath)\n .filter((file) => file.endsWith('.ts') && file.startsWith('Migration'))\n\n for (const file of migrationFiles) {\n fs.unlinkSync(path.join(migrationsPath, file))\n }\n\n // Remove snapshot files\n const snapshotFiles = fs\n .readdirSync(migrationsPath)\n .filter((file) => file.endsWith('.json') && file.includes('snapshot'))\n\n for (const file of snapshotFiles) {\n fs.unlinkSync(path.join(migrationsPath, file))\n }\n\n if (migrationFiles.length > 0 || snapshotFiles.length > 0) {\n results.push(\n formatResult(modId, `cleaned ${migrationFiles.length} migrations, ${snapshotFiles.length} snapshots`, '')\n )\n } else {\n results.push(formatResult(modId, 'already clean', ''))\n }\n } else {\n results.push(formatResult(modId, 'no migrations directory', ''))\n }\n\n // Clean up checksum files using glob pattern\n if (fs.existsSync(outputDir)) {\n const files = fs.readdirSync(outputDir)\n const checksumFiles = files.filter((file) => file.endsWith('.checksum'))\n\n for (const file of checksumFiles) {\n fs.unlinkSync(path.join(outputDir, file))\n }\n\n if (checksumFiles.length > 0) {\n results.push(formatResult(modId, `cleaned ${checksumFiles.length} checksum files`, ''))\n }\n }\n }\n\n console.log(results.join('\\n'))\n\n // Drop per-module MikroORM migration tables to ensure clean slate\n console.log('Dropping per-module migration tables...')\n try {\n const { Client } = await import('pg')\n const client = new Client({ connectionString: getClientUrl(), ssl: getSslConfig() })\n await client.connect()\n try {\n await client.query('BEGIN')\n for (const entry of ordered) {\n const modId = entry.id\n const sanitizedModId = sanitizeModuleId(modId)\n const tableName = `mikro_orm_migrations_${sanitizedModId}`\n validateTableName(tableName)\n await client.query(`DROP TABLE IF EXISTS \"${tableName}\"`)\n console.log(` ${modId}: dropped table ${tableName}`)\n }\n await client.query('COMMIT')\n } catch (e) {\n await client.query('ROLLBACK')\n throw e\n } finally {\n try {\n await client.end()\n } catch { }\n }\n } catch (e) {\n console.error('Failed to drop migration tables:', (e as any)?.message || e)\n throw e\n }\n\n // Drop all existing user tables to ensure fresh CREATE-only migrations\n console.log('Dropping ALL public tables for true greenfield...')\n try {\n const { Client } = await import('pg')\n const client = new Client({ connectionString: getClientUrl(), ssl: getSslConfig() })\n await client.connect()\n try {\n const res = await client.query(`SELECT tablename FROM pg_tables WHERE schemaname = current_schema()`)\n const tables: string[] = (res.rows || []).map((r: any) => String(r.tablename))\n if (tables.length) {\n await client.query('BEGIN')\n try {\n await client.query(\"SET session_replication_role = 'replica'\")\n for (const t of tables) {\n await client.query(`DROP TABLE IF EXISTS ${quotePostgresIdentifier(t)} CASCADE`)\n }\n await client.query(\"SET session_replication_role = 'origin'\")\n await client.query('COMMIT')\n console.log(` Dropped ${tables.length} tables.`)\n } catch (e) {\n await client.query('ROLLBACK')\n throw e\n }\n } else {\n console.log(' No tables found to drop.')\n }\n } finally {\n try {\n await client.end()\n } catch { }\n }\n } catch (e) {\n console.error('Failed to drop public tables:', (e as any)?.message || e)\n throw e\n }\n\n // Generate fresh migrations for all modules\n console.log('Generating fresh migrations for all modules...')\n await dbGenerate(resolver)\n\n // Apply migrations\n console.log('Applying migrations...')\n await dbMigrate(resolver)\n\n console.log('Greenfield reset complete! Fresh migrations generated and applied.')\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import path from 'node:path'\nimport fs from 'node:fs'\nimport { pathToFileURL } from 'node:url'\nimport ts from 'typescript-js'\nimport { MikroORM, MetadataStorage, type Logger } from '@mikro-orm/core'\nimport { ReflectMetadataProvider } from '@mikro-orm/decorators/legacy'\nimport { Migrator } from '@mikro-orm/migrations'\nimport { PostgreSqlDriver } from '@mikro-orm/postgresql'\nimport { getSslConfig } from '@open-mercato/shared/lib/db/ssl'\nimport type { PackageResolver, ModuleEntry } from '../resolver'\nimport { quotePostgresIdentifier } from './identifiers'\nimport {\n collectQueryIndexReindexEntityTypes,\n isMigrationReindexEnabled,\n requestQueryIndexReindex,\n type AppliedMigration,\n} from './migration-reindex'\n\nconst QUIET_MODE = process.env.OM_CLI_QUIET === '1' || process.env.MERCATO_QUIET === '1'\nconst PROGRESS_EMOJI = ''\n\nfunction formatResult(modId: string, message: string, emoji = '\\u2022') {\n return `${emoji} ${modId}: ${message}`\n}\n\nfunction createProgressRenderer(total: number) {\n const width = 20\n const normalizedTotal = total > 0 ? total : 1\n return (current: number) => {\n const clamped = Math.min(Math.max(current, 0), normalizedTotal)\n const filled = Math.round((clamped / normalizedTotal) * width)\n const bar = `${'='.repeat(filled)}${'.'.repeat(Math.max(width - filled, 0))}`\n return `[${bar}] ${clamped}/${normalizedTotal}`\n }\n}\n\nfunction createMinimalLogger(): Logger {\n return {\n log: () => { },\n error: (_namespace, message) => console.error(message),\n warn: (_namespace, message) => {\n if (!QUIET_MODE) console.warn(message)\n },\n logQuery: () => { },\n setDebugMode: () => { },\n isEnabled: () => false,\n }\n}\n\nfunction getClientUrl(): string {\n const url = process.env.DATABASE_URL\n if (!url) throw new Error('DATABASE_URL is not set')\n return url\n}\n\nfunction sortModules(mods: ModuleEntry[]): ModuleEntry[] {\n // Sort modules alphabetically since they are now isomorphic\n return mods.slice().sort((a, b) => a.id.localeCompare(b.id))\n}\n\n/**\n * Custom dynamic import provider for MikroORM that properly handles Windows paths.\n * MikroORM's built-in handling has a bug where it converts file:// URLs back to\n * Windows paths when the extension isn't in require.extensions (which is always\n * true for .ts files in ESM mode).\n */\nasync function dynamicImportProvider(id: string): Promise<any> {\n // On Windows, convert absolute paths to file:// URLs\n // Check if it's a Windows absolute path (e.g., C:\\... or D:\\...)\n if (process.platform === 'win32' && /^[a-zA-Z]:[\\\\/]/.test(id)) {\n id = pathToFileURL(id).href\n }\n return import(id)\n}\n\n/**\n * Sanitizes a module ID for use in SQL identifiers (table names).\n * Replaces non-alphanumeric characters with underscores to prevent SQL injection.\n * @public Exported for testing\n */\nexport function sanitizeModuleId(modId: string): string {\n return modId.replace(/[^a-z0-9_]/gi, '_')\n}\n\n/**\n * Validates that a table name is safe for use in SQL queries.\n * @throws Error if the table name contains invalid characters.\n * @public Exported for testing\n */\nexport function validateTableName(tableName: string): void {\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {\n throw new Error(`Invalid table name: ${tableName}. Table names must start with a letter or underscore and contain only alphanumeric characters and underscores.`)\n }\n}\n\nexport function makeConstraintDropsIdempotent(sql: string): string {\n return sql.replace(/alter table\\s+(\"[^\"]+\"|\\S+)\\s+drop constraint\\s+(\"[^\"]+\"|\\S+);/gi, 'alter table $1 drop constraint if exists $2;')\n}\n\nexport function getMigrationSnapshotName(resolver: Pick<PackageResolver, 'getRootDir'>): string {\n void resolver\n return '.snapshot-open-mercato'\n}\n\nexport function shouldCreateInitialModuleMigration(migrationsPath: string, snapshotName: string): boolean {\n const snapshotPath = path.join(migrationsPath, `${snapshotName}.json`)\n if (fs.existsSync(snapshotPath)) return false\n if (!fs.existsSync(migrationsPath)) return true\n\n const migrationFiles = fs\n .readdirSync(migrationsPath)\n .filter((file) => /^Migration.*\\.(ts|js)$/.test(file) && !file.endsWith('.d.ts'))\n\n return migrationFiles.length === 0\n}\n\nexport function resolveGeneratedMigrationPath(fileName: string, migrationsPath: string): string {\n return path.isAbsolute(fileName) ? fileName : path.join(migrationsPath, fileName)\n}\n\nlet tsxLoaderRegistered = false\nlet temporaryModuleCounter = 0\n\nasync function ensureTsxLoaderRegistered() {\n if (tsxLoaderRegistered) return\n try {\n const { register } = await import('tsx/esm/api')\n register()\n tsxLoaderRegistered = true\n } catch {\n // Continue without the loader. Relative TypeScript imports may fail in this case.\n }\n}\n\nasync function importWithTypeScriptFile(filePath: string): Promise<any> {\n await ensureTsxLoaderRegistered()\n const source = fs.readFileSync(filePath, 'utf8')\n const compiled = ts.transpileModule(source, {\n fileName: filePath,\n compilerOptions: {\n module: ts.ModuleKind.ESNext,\n target: ts.ScriptTarget.ES2022,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n esModuleInterop: true,\n resolveJsonModule: true,\n jsx: ts.JsxEmit.ReactJSX,\n experimentalDecorators: true,\n emitDecoratorMetadata: false,\n useDefineForClassFields: false,\n },\n }).outputText\n const tempPath = `${filePath}.mercato-db-generate-${process.pid}-${temporaryModuleCounter++}.mjs`\n fs.writeFileSync(tempPath, compiled, 'utf8')\n try {\n return await import(pathToFileURL(tempPath).href)\n } finally {\n try {\n fs.unlinkSync(tempPath)\n } catch {\n // Ignore cleanup failures for temporary compiled modules.\n }\n }\n}\n\nasync function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver): Promise<any[]> {\n const roots = resolver.getModulePaths(entry)\n const imps = resolver.getModuleImportBase(entry)\n const isAppModule = entry.from === '@app'\n const shouldImportFromSource = isAppModule || resolver.isMonorepo()\n const bases = [\n path.join(roots.appBase, 'data'),\n path.join(roots.pkgBase, 'data'),\n path.join(roots.appBase, 'db'),\n path.join(roots.pkgBase, 'db'),\n ]\n const candidates = ['entities.ts', 'schema.ts']\n\n for (const base of bases) {\n for (const f of candidates) {\n const p = path.join(base, f)\n if (fs.existsSync(p)) {\n const sub = path.basename(base)\n const fromApp = base.startsWith(roots.appBase)\n const importPath = fromApp || shouldImportFromSource\n ? pathToFileURL(p).href\n : `${imps.pkgBase}/${sub}/${f.replace(/\\.ts$/, '')}`\n try {\n const mod = fromApp || shouldImportFromSource\n ? await importWithTypeScriptFile(p)\n : await import(importPath)\n const entities = Object.values(mod).filter((v) => typeof v === 'function')\n if (entities.length) return entities as any[]\n } catch (err) {\n // For @app modules we try a TS loader fallback; otherwise propagate errors\n if (isAppModule) {\n if (process.env.MERCATO_CLI_DEBUG_IMPORTS === '1') {\n console.warn(`[db] failed to load app module entities from ${p}: ${(err as Error)?.message || String(err)}`)\n }\n continue\n }\n throw err\n }\n }\n }\n }\n return []\n}\n\nfunction getMigrationsPath(entry: ModuleEntry, resolver: PackageResolver): string {\n const roots = resolver.getModulePaths(entry)\n\n if (entry.from === '@app') {\n // @app modules: use src/ (user's TypeScript source)\n // Normalize to forward slashes for ESM compatibility on Windows\n return path.join(roots.appBase, 'migrations').replace(/\\\\/g, '/')\n }\n\n // Package modules: in standalone mode, use dist/ (compiled JS) since Node.js\n // can't run TypeScript from node_modules. In monorepo, use src/ (TypeScript).\n if (!resolver.isMonorepo()) {\n // Replace src/modules with dist/modules for standalone apps\n // Use regex to handle both forward and backslashes\n const distPath = roots.pkgBase.replace(/[/\\\\]src[/\\\\]modules[/\\\\]/, '/dist/modules/')\n return path.join(distPath, 'migrations').replace(/\\\\/g, '/')\n }\n\n // Normalize to forward slashes for ESM compatibility on Windows\n return path.join(roots.pkgBase, 'migrations').replace(/\\\\/g, '/')\n}\n\nexport interface DbOptions {\n quiet?: boolean\n}\n\nexport interface GreenfieldOptions extends DbOptions {\n yes: boolean\n}\n\nexport async function dbGenerate(resolver: PackageResolver, options: DbOptions = {}): Promise<void> {\n const modules = resolver.loadEnabledModules()\n const ordered = sortModules(modules)\n const results: string[] = []\n\n const sslConfig = getSslConfig()\n const usedFileNames = new Set<string>()\n\n for (const entry of ordered) {\n // Clear the global @Entity() decorator registry before loading this module's\n // entities. MikroORM's migrator reads MetadataStorage at createMigration()\n // time, so without this clear, every module's migration would include every\n // previously-loaded module's tables (see issue #1911).\n MetadataStorage.clear()\n\n const modId = entry.id\n const sanitizedModId = sanitizeModuleId(modId)\n const entities = await loadModuleEntities(entry, resolver)\n if (!entities.length) {\n if (entry.from === '@app') {\n results.push(formatResult(modId, 'no entities discovered', ''))\n }\n continue\n }\n\n const migrationsPath = getMigrationsPath(entry, resolver)\n fs.mkdirSync(migrationsPath, { recursive: true })\n\n const tableName = `mikro_orm_migrations_${sanitizedModId}`\n validateTableName(tableName)\n const snapshotName = getMigrationSnapshotName(resolver)\n const createInitialMigration = shouldCreateInitialModuleMigration(migrationsPath, snapshotName)\n\n const orm = await MikroORM.init<PostgreSqlDriver>({\n driver: PostgreSqlDriver,\n clientUrl: getClientUrl(),\n loggerFactory: () => createMinimalLogger(),\n dynamicImportProvider,\n entities,\n metadataProvider: ReflectMetadataProvider,\n migrations: {\n path: migrationsPath,\n glob: '!(*.d).{ts,js}',\n tableName,\n snapshotName,\n dropTables: false,\n },\n schemaGenerator: {\n disableForeignKeys: true,\n },\n pool: {\n min: 1,\n max: 3,\n idleTimeoutMillis: 30000,\n // acquireTimeoutMillis removed for v7 (pg.Pool doesn't support it; use connectionTimeoutMillis in driverOptions if needed)\n },\n driverOptions: sslConfig ? {\n ssl: sslConfig,\n } : undefined,\n })\n\n try {\n const diff = await orm.migrator.create(undefined, false, createInitialMigration)\n if (diff && diff.fileName) {\n try {\n const orig = resolveGeneratedMigrationPath(diff.fileName, migrationsPath)\n const base = path.basename(orig)\n const dir = path.dirname(orig)\n const ext = path.extname(base)\n const stem = base.replace(ext, '')\n const suffix = `_${modId}`\n let candidate = stem.endsWith(suffix) ? base : `${stem}${suffix}${ext}`\n let dedupe = 1\n\n while (usedFileNames.has(path.join(dir, candidate))) {\n candidate = `${stem}${suffix}_${dedupe++}${ext}`\n }\n\n const newPath = path.join(dir, candidate)\n let content = fs.readFileSync(orig, 'utf8')\n content = makeConstraintDropsIdempotent(content)\n content = content.replace(\n /export class (Migration\\d+)/,\n `export class $1_${modId.replace(/[^a-zA-Z0-9]/g, '_')}`\n )\n fs.writeFileSync(newPath, content, 'utf8')\n if (newPath !== orig) fs.unlinkSync(orig)\n usedFileNames.add(newPath)\n results.push(formatResult(modId, `generated ${path.basename(newPath)}`, ''))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n results.push(formatResult(modId, `generated ${path.basename(diff.fileName)} (rename failed: ${message})`, ''))\n }\n } else {\n results.push(formatResult(modId, 'no changes', ''))\n }\n } finally {\n await orm.close(true)\n }\n }\n\n console.log(results.join('\\n'))\n}\n\nexport async function dbMigrate(resolver: PackageResolver, options: DbOptions = {}): Promise<void> {\n const modules = resolver.loadEnabledModules()\n const ordered = sortModules(modules)\n const results: string[] = []\n const appliedMigrations: AppliedMigration[] = []\n\n try {\n for (const entry of ordered) {\n const modId = entry.id\n const sanitizedModId = sanitizeModuleId(modId)\n const entities = await loadModuleEntities(entry, resolver)\n\n const migrationsPath = getMigrationsPath(entry, resolver)\n\n // Skip if no entities AND no migrations directory exists\n // (allows @app modules to run migrations even if entities can't be dynamically imported)\n if (!entities.length && !fs.existsSync(migrationsPath)) continue\n fs.mkdirSync(migrationsPath, { recursive: true })\n\n const tableName = `mikro_orm_migrations_${sanitizedModId}`\n validateTableName(tableName)\n\n // dbMigrate only runs existing migration files \u2014 entities are intentionally\n // omitted so MikroORM does not compare them against the snapshot and\n // auto-generate a phantom diff migration (that would duplicate tables\n // already created by committed migrations).\n const sslConfig = getSslConfig()\n const orm = await MikroORM.init<PostgreSqlDriver>({\n driver: PostgreSqlDriver,\n clientUrl: getClientUrl(),\n loggerFactory: () => createMinimalLogger(),\n dynamicImportProvider,\n entities: [],\n metadataProvider: ReflectMetadataProvider,\n discovery: { warnWhenNoEntities: false },\n migrations: {\n path: migrationsPath,\n glob: '!(*.d).{ts,js}',\n tableName,\n snapshot: false,\n dropTables: false,\n },\n schemaGenerator: {\n disableForeignKeys: true,\n },\n pool: {\n min: 1,\n max: 3,\n idleTimeoutMillis: 30000,\n // acquireTimeoutMillis removed for v7 (pg.Pool doesn't support it; use connectionTimeoutMillis in driverOptions if needed)\n },\n driverOptions: sslConfig ? {\n ssl: sslConfig,\n } : undefined,\n })\n\n try {\n const migrator = orm.migrator as Migrator\n const pending = await migrator.getPending()\n if (!pending.length) {\n results.push(formatResult(modId, 'no pending migrations', ''))\n } else {\n const renderProgress = createProgressRenderer(pending.length)\n let applied = 0\n if (!QUIET_MODE) {\n process.stdout.write(` ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`)\n }\n for (const migration of pending) {\n const migrationName =\n typeof migration === 'string'\n ? migration\n : (migration as any).name ?? (migration as any).fileName\n await migrator.up(migrationName ? { migrations: [migrationName] } : undefined)\n if (migrationName) {\n appliedMigrations.push({\n moduleId: modId,\n migrationsPath,\n name: String(migrationName),\n filePath: typeof migration === 'string' ? null : (migration as any).path ?? null,\n })\n }\n applied += 1\n if (!QUIET_MODE) {\n process.stdout.write(`\\r ${PROGRESS_EMOJI} ${modId}: ${renderProgress(applied)}`)\n }\n }\n if (!QUIET_MODE) process.stdout.write('\\n')\n results.push(\n formatResult(modId, `${pending.length} migration${pending.length === 1 ? '' : 's'} applied`, '')\n )\n }\n } finally {\n await orm.close(true)\n }\n }\n } finally {\n console.log(results.join('\\n'))\n await dischargeQueryIndexReindexRequests(appliedMigrations)\n }\n}\n\n/**\n * Runs after every module migrated and after `orm.close()`, so the rewrites the declarations\n * refer to are committed before the reindex is queued.\n *\n * Reached from a `finally`, so it also runs when a later migration threw: the migrations that\n * did apply already committed, and their declarations are the only record that their projections\n * are stale \u2014 a re-run cannot recover them, because `getPending()` no longer lists them. It must\n * therefore never throw, or it would replace the migration failure the operator needs to see.\n */\nexport async function dischargeQueryIndexReindexRequests(\n applied: readonly AppliedMigration[],\n): Promise<void> {\n if (!applied.length || !isMigrationReindexEnabled()) return\n\n try {\n const entityTypes = await collectQueryIndexReindexEntityTypes(applied, {\n importModule: dynamicImportProvider,\n onWarn: (message) => console.warn(message),\n })\n if (!entityTypes.length) return\n\n await requestQueryIndexReindex(entityTypes, {\n createContainer: async () => {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n return (await createRequestContainer()) as any\n },\n onInfo: (message) => {\n if (!QUIET_MODE) console.log(message)\n },\n onWarn: (message) => console.warn(message),\n })\n } catch (error) {\n console.warn(\n `[query_index] Could not determine which projections the migrations invalidated: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n}\n\nexport async function dbGreenfield(resolver: PackageResolver, options: GreenfieldOptions): Promise<void> {\n if (!options.yes) {\n console.error('This command will DELETE all data. Use --yes to confirm.')\n process.exit(1)\n }\n\n console.log('Cleaning up migrations and snapshots for greenfield setup...')\n\n const modules = resolver.loadEnabledModules()\n const ordered = sortModules(modules)\n const results: string[] = []\n const outputDir = resolver.getOutputDir()\n\n for (const entry of ordered) {\n const modId = entry.id\n const migrationsPath = getMigrationsPath(entry, resolver)\n\n if (fs.existsSync(migrationsPath)) {\n // Remove all migration files\n const migrationFiles = fs\n .readdirSync(migrationsPath)\n .filter((file) => file.endsWith('.ts') && file.startsWith('Migration'))\n\n for (const file of migrationFiles) {\n fs.unlinkSync(path.join(migrationsPath, file))\n }\n\n // Remove snapshot files\n const snapshotFiles = fs\n .readdirSync(migrationsPath)\n .filter((file) => file.endsWith('.json') && file.includes('snapshot'))\n\n for (const file of snapshotFiles) {\n fs.unlinkSync(path.join(migrationsPath, file))\n }\n\n if (migrationFiles.length > 0 || snapshotFiles.length > 0) {\n results.push(\n formatResult(modId, `cleaned ${migrationFiles.length} migrations, ${snapshotFiles.length} snapshots`, '')\n )\n } else {\n results.push(formatResult(modId, 'already clean', ''))\n }\n } else {\n results.push(formatResult(modId, 'no migrations directory', ''))\n }\n\n // Clean up checksum files using glob pattern\n if (fs.existsSync(outputDir)) {\n const files = fs.readdirSync(outputDir)\n const checksumFiles = files.filter((file) => file.endsWith('.checksum'))\n\n for (const file of checksumFiles) {\n fs.unlinkSync(path.join(outputDir, file))\n }\n\n if (checksumFiles.length > 0) {\n results.push(formatResult(modId, `cleaned ${checksumFiles.length} checksum files`, ''))\n }\n }\n }\n\n console.log(results.join('\\n'))\n\n // Drop per-module MikroORM migration tables to ensure clean slate\n console.log('Dropping per-module migration tables...')\n try {\n const { Client } = await import('pg')\n const client = new Client({ connectionString: getClientUrl(), ssl: getSslConfig() })\n await client.connect()\n try {\n await client.query('BEGIN')\n for (const entry of ordered) {\n const modId = entry.id\n const sanitizedModId = sanitizeModuleId(modId)\n const tableName = `mikro_orm_migrations_${sanitizedModId}`\n validateTableName(tableName)\n await client.query(`DROP TABLE IF EXISTS \"${tableName}\"`)\n console.log(` ${modId}: dropped table ${tableName}`)\n }\n await client.query('COMMIT')\n } catch (e) {\n await client.query('ROLLBACK')\n throw e\n } finally {\n try {\n await client.end()\n } catch { }\n }\n } catch (e) {\n console.error('Failed to drop migration tables:', (e as any)?.message || e)\n throw e\n }\n\n // Drop all existing user tables to ensure fresh CREATE-only migrations\n console.log('Dropping ALL public tables for true greenfield...')\n try {\n const { Client } = await import('pg')\n const client = new Client({ connectionString: getClientUrl(), ssl: getSslConfig() })\n await client.connect()\n try {\n const res = await client.query(`SELECT tablename FROM pg_tables WHERE schemaname = current_schema()`)\n const tables: string[] = (res.rows || []).map((r: any) => String(r.tablename))\n if (tables.length) {\n await client.query('BEGIN')\n try {\n await client.query(\"SET session_replication_role = 'replica'\")\n for (const t of tables) {\n await client.query(`DROP TABLE IF EXISTS ${quotePostgresIdentifier(t)} CASCADE`)\n }\n await client.query(\"SET session_replication_role = 'origin'\")\n await client.query('COMMIT')\n console.log(` Dropped ${tables.length} tables.`)\n } catch (e) {\n await client.query('ROLLBACK')\n throw e\n }\n } else {\n console.log(' No tables found to drop.')\n }\n } finally {\n try {\n await client.end()\n } catch { }\n }\n } catch (e) {\n console.error('Failed to drop public tables:', (e as any)?.message || e)\n throw e\n }\n\n // Generate fresh migrations for all modules\n console.log('Generating fresh migrations for all modules...')\n await dbGenerate(resolver)\n\n // Apply migrations\n console.log('Applying migrations...')\n await dbMigrate(resolver)\n\n console.log('Greenfield reset complete! Fresh migrations generated and applied.')\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,104 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { parseBooleanWithDefault } from "@open-mercato/shared/lib/boolean";
4
+ import {
5
+ formatQueryIndexRebuildCommands,
6
+ readQueryIndexReindexDeclaration
7
+ } from "@open-mercato/shared/lib/query/migration-reindex";
8
+ const MIGRATION_FILE_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;
9
+ const MIGRATION_EXTENSIONS = [".ts", ".js", ".mjs", ".cjs"];
10
+ function isMigrationReindexEnabled(env = process.env) {
11
+ return parseBooleanWithDefault(env.OM_MIGRATION_REINDEX, true);
12
+ }
13
+ function resolveMigrationFilePath(migrationsPath, migrationName, knownPath, fileExists = fs.existsSync) {
14
+ if (knownPath && fileExists(knownPath)) return knownPath;
15
+ const stem = path.basename(migrationName).replace(/\.(ts|js|mjs|cjs)$/i, "");
16
+ if (!stem || !MIGRATION_FILE_NAME_PATTERN.test(stem)) return null;
17
+ for (const extension of MIGRATION_EXTENSIONS) {
18
+ const candidate = path.join(migrationsPath, `${stem}${extension}`);
19
+ if (fileExists(candidate)) return candidate;
20
+ }
21
+ return null;
22
+ }
23
+ async function collectQueryIndexReindexEntityTypes(applied, deps) {
24
+ const fileExists = deps.fileExists ?? fs.existsSync;
25
+ const collected = [];
26
+ for (const migration of applied) {
27
+ const filePath = resolveMigrationFilePath(
28
+ migration.migrationsPath,
29
+ migration.name,
30
+ migration.filePath,
31
+ fileExists
32
+ );
33
+ if (!filePath) continue;
34
+ let moduleExports;
35
+ try {
36
+ moduleExports = await deps.importModule(filePath);
37
+ } catch (error) {
38
+ deps.onWarn?.(
39
+ `[query_index] Could not read reindex declarations from ${migration.moduleId}/${migration.name}: ${error instanceof Error ? error.message : String(error)}`
40
+ );
41
+ continue;
42
+ }
43
+ const declared = readQueryIndexReindexDeclaration(moduleExports, (rejected) => {
44
+ deps.onWarn?.(
45
+ `[query_index] Ignoring an invalid reindex declaration in ${migration.moduleId}/${migration.name}: ${JSON.stringify(rejected) ?? String(rejected)} is not a "module:entity" identifier, so its projection will NOT be rebuilt.`
46
+ );
47
+ });
48
+ for (const entityType of declared) {
49
+ if (!collected.includes(entityType)) collected.push(entityType);
50
+ }
51
+ }
52
+ return collected;
53
+ }
54
+ function formatManualReindexInstructions(entityTypes) {
55
+ const commands = formatQueryIndexRebuildCommands(entityTypes).map((command) => ` ${command}`).join("\n");
56
+ return [
57
+ "[query_index] Could not queue the reindex requested by the migrations that just ran.",
58
+ " Their query-index projections still hold pre-migration values until you run:",
59
+ commands
60
+ ].join("\n");
61
+ }
62
+ async function requestQueryIndexReindex(entityTypes, deps) {
63
+ if (!entityTypes.length) return { requested: [], queued: false };
64
+ let container = null;
65
+ const queued = [];
66
+ try {
67
+ container = await deps.createContainer();
68
+ const eventBus = container.resolve("eventBus");
69
+ for (const entityType of entityTypes) {
70
+ await eventBus.emitEvent(
71
+ "query_index.reindex",
72
+ { entityType, allowAllTenants: true, force: false },
73
+ { persistent: true }
74
+ );
75
+ queued.push(entityType);
76
+ }
77
+ deps.onInfo?.(
78
+ `[query_index] Queued a reindex for ${queued.length} entity type(s) touched by data migrations: ${queued.join(", ")}`
79
+ );
80
+ return { requested: queued, queued: true };
81
+ } catch (error) {
82
+ const unqueued = entityTypes.filter((entityType) => !queued.includes(entityType));
83
+ deps.onWarn?.(
84
+ `${formatManualReindexInstructions(unqueued)}
85
+ Reason: ${error instanceof Error ? error.message : String(error)}`
86
+ );
87
+ return { requested: queued, queued: false };
88
+ } finally {
89
+ if (container && typeof container.dispose === "function") {
90
+ try {
91
+ await container.dispose();
92
+ } catch {
93
+ }
94
+ }
95
+ }
96
+ }
97
+ export {
98
+ collectQueryIndexReindexEntityTypes,
99
+ formatManualReindexInstructions,
100
+ isMigrationReindexEnabled,
101
+ requestQueryIndexReindex,
102
+ resolveMigrationFilePath
103
+ };
104
+ //# sourceMappingURL=migration-reindex.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/db/migration-reindex.ts"],
4
+ "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport {\n formatQueryIndexRebuildCommands,\n readQueryIndexReindexDeclaration,\n} from '@open-mercato/shared/lib/query/migration-reindex'\n\nconst MIGRATION_FILE_NAME_PATTERN = /^[A-Za-z0-9._-]+$/\nconst MIGRATION_EXTENSIONS = ['.ts', '.js', '.mjs', '.cjs']\n\nexport type AppliedMigration = {\n moduleId: string\n migrationsPath: string\n name: string\n filePath?: string | null\n}\n\nexport type MigrationReindexDeps = {\n importModule: (filePath: string) => Promise<unknown>\n fileExists?: (filePath: string) => boolean\n onWarn?: (message: string) => void\n}\n\nexport function isMigrationReindexEnabled(env: NodeJS.ProcessEnv = process.env): boolean {\n return parseBooleanWithDefault(env.OM_MIGRATION_REINDEX, true)\n}\n\nexport function resolveMigrationFilePath(\n migrationsPath: string,\n migrationName: string,\n knownPath?: string | null,\n fileExists: (filePath: string) => boolean = fs.existsSync,\n): string | null {\n if (knownPath && fileExists(knownPath)) return knownPath\n const stem = path.basename(migrationName).replace(/\\.(ts|js|mjs|cjs)$/i, '')\n if (!stem || !MIGRATION_FILE_NAME_PATTERN.test(stem)) return null\n for (const extension of MIGRATION_EXTENSIONS) {\n const candidate = path.join(migrationsPath, `${stem}${extension}`)\n if (fileExists(candidate)) return candidate\n }\n return null\n}\n\nexport async function collectQueryIndexReindexEntityTypes(\n applied: readonly AppliedMigration[],\n deps: MigrationReindexDeps,\n): Promise<string[]> {\n const fileExists = deps.fileExists ?? fs.existsSync\n const collected: string[] = []\n for (const migration of applied) {\n const filePath = resolveMigrationFilePath(\n migration.migrationsPath,\n migration.name,\n migration.filePath,\n fileExists,\n )\n if (!filePath) continue\n let moduleExports: unknown\n try {\n moduleExports = await deps.importModule(filePath)\n } catch (error) {\n deps.onWarn?.(\n `[query_index] Could not read reindex declarations from ${migration.moduleId}/${migration.name}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n continue\n }\n const declared = readQueryIndexReindexDeclaration(moduleExports, (rejected: unknown) => {\n deps.onWarn?.(\n `[query_index] Ignoring an invalid reindex declaration in ${migration.moduleId}/${migration.name}: ${\n JSON.stringify(rejected) ?? String(rejected)\n } is not a \"module:entity\" identifier, so its projection will NOT be rebuilt.`,\n )\n })\n for (const entityType of declared) {\n if (!collected.includes(entityType)) collected.push(entityType)\n }\n }\n return collected\n}\n\nexport function formatManualReindexInstructions(entityTypes: readonly string[]): string {\n const commands = formatQueryIndexRebuildCommands(entityTypes)\n .map((command) => ` ${command}`)\n .join('\\n')\n return [\n '[query_index] Could not queue the reindex requested by the migrations that just ran.',\n ' Their query-index projections still hold pre-migration values until you run:',\n commands,\n ].join('\\n')\n}\n\nexport type QueryIndexReindexEmitter = {\n emitEvent: (event: string, payload: Record<string, unknown>, options?: { persistent?: boolean }) => Promise<void>\n}\n\nexport type QueryIndexReindexContainer = {\n resolve: (name: string) => unknown\n dispose?: () => Promise<void> | void\n}\n\nexport type RequestQueryIndexReindexDeps = {\n createContainer: () => Promise<QueryIndexReindexContainer>\n onInfo?: (message: string) => void\n onWarn?: (message: string) => void\n}\n\n/**\n * Queued rather than executed inline: a rebuild of a large entity type must not hold up a\n * deploy's migration step. `force` stays false so the existing `query_index.reindex`\n * subscriber upserts in place \u2014 a forced run purges the entity's rows first, which would\n * leave the projection empty for the duration of the rebuild.\n */\nexport async function requestQueryIndexReindex(\n entityTypes: readonly string[],\n deps: RequestQueryIndexReindexDeps,\n): Promise<{ requested: string[]; queued: boolean }> {\n if (!entityTypes.length) return { requested: [], queued: false }\n\n let container: QueryIndexReindexContainer | null = null\n const queued: string[] = []\n try {\n container = await deps.createContainer()\n const eventBus = container.resolve('eventBus') as QueryIndexReindexEmitter\n for (const entityType of entityTypes) {\n await eventBus.emitEvent(\n 'query_index.reindex',\n { entityType, allowAllTenants: true, force: false },\n { persistent: true },\n )\n queued.push(entityType)\n }\n deps.onInfo?.(\n `[query_index] Queued a reindex for ${queued.length} entity type(s) touched by data migrations: ${queued.join(', ')}`,\n )\n return { requested: queued, queued: true }\n } catch (error) {\n const unqueued = entityTypes.filter((entityType) => !queued.includes(entityType))\n deps.onWarn?.(\n `${formatManualReindexInstructions(unqueued)}\\n Reason: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n return { requested: queued, queued: false }\n } finally {\n if (container && typeof container.dispose === 'function') {\n try {\n await container.dispose()\n } catch {\n // A container that fails to dispose must not turn a successful migration into a failure.\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.7.1-develop.7137.1.26575786c0",
3
+ "version": "0.7.1-develop.7149.1.7efa6e1612",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,9 +60,9 @@
60
60
  "@mikro-orm/decorators": "^7.1.8",
61
61
  "@mikro-orm/migrations": "^7.1.8",
62
62
  "@mikro-orm/postgresql": "^7.1.8",
63
- "@open-mercato/queue": "0.7.1-develop.7137.1.26575786c0",
64
- "@open-mercato/shared": "0.7.1-develop.7137.1.26575786c0",
65
- "@open-mercato/telemetry": "0.7.1-develop.7137.1.26575786c0",
63
+ "@open-mercato/queue": "0.7.1-develop.7149.1.7efa6e1612",
64
+ "@open-mercato/shared": "0.7.1-develop.7149.1.7efa6e1612",
65
+ "@open-mercato/telemetry": "0.7.1-develop.7149.1.7efa6e1612",
66
66
  "cross-spawn": "^7.0.6",
67
67
  "pg": "8.22.0",
68
68
  "semver": "^7.8.5",
@@ -73,10 +73,10 @@
73
73
  "typescript-js": "npm:typescript@6.0.3"
74
74
  },
75
75
  "peerDependencies": {
76
- "@open-mercato/shared": "0.7.1-develop.7137.1.26575786c0"
76
+ "@open-mercato/shared": "0.7.1-develop.7149.1.7efa6e1612"
77
77
  },
78
78
  "devDependencies": {
79
- "@open-mercato/shared": "0.7.1-develop.7137.1.26575786c0",
79
+ "@open-mercato/shared": "0.7.1-develop.7149.1.7efa6e1612",
80
80
  "@types/jest": "^30.0.0",
81
81
  "jest": "^30.4.2",
82
82
  "ts-jest": "^29.4.12"