@open-mercato/cli 0.6.4-develop.3938.1.c97dbde799 → 0.6.4-develop.3949.1.adc3d0b3b1

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.
@@ -1,4 +1,4 @@
1
- [build:cli] found 73 entry points
1
+ [build:cli] found 74 entry points
2
2
  Copied create-app/agentic/ → dist/agentic/
3
3
  Discovered 16 standalone guides → dist/agentic/guides/
4
4
  [build:cli] built successfully
@@ -0,0 +1,153 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import {
5
+ MODULE_CODE_EXTENSIONS,
6
+ SCAN_CONFIGS,
7
+ scanModuleDir,
8
+ stripModuleCodeExtension
9
+ } from "./generators/scanner.js";
10
+ const STRUCTURAL_CONVENTION_FILES = [
11
+ "index.ts",
12
+ "cli.ts",
13
+ "di.ts",
14
+ "acl.ts",
15
+ "setup.ts",
16
+ "encryption.ts",
17
+ "ce.ts",
18
+ "search.ts",
19
+ "events.ts",
20
+ "notifications.ts",
21
+ "notifications.client.ts",
22
+ "notifications.handlers.ts",
23
+ "translations.ts",
24
+ "generators.ts",
25
+ "ai-tools.ts",
26
+ "ai-agents.ts",
27
+ "analytics.ts",
28
+ "workflows.ts",
29
+ "inbox-actions.ts",
30
+ "message-types.ts",
31
+ "message-objects.ts",
32
+ "integration.ts",
33
+ "security.mfa-providers.ts",
34
+ "security.sudo.ts",
35
+ "data/entities.ts",
36
+ "data/extensions.ts",
37
+ "data/fields.ts",
38
+ "data/enrichers.ts",
39
+ "data/guards.ts",
40
+ "api/interceptors.ts",
41
+ "commands/interceptors.ts",
42
+ "widgets/components.ts",
43
+ "widgets/injection-table.ts",
44
+ "frontend/middleware.ts",
45
+ "backend/middleware.ts"
46
+ ];
47
+ const CONTENT_SENSITIVE_SCAN_CONFIGS = [
48
+ SCAN_CONFIGS.apiRoutes,
49
+ SCAN_CONFIGS.apiPlainFiles,
50
+ SCAN_CONFIGS.subscribers,
51
+ SCAN_CONFIGS.workers,
52
+ SCAN_CONFIGS.dashboardWidgets,
53
+ SCAN_CONFIGS.injectionWidgets
54
+ ];
55
+ const ROUTE_SHAPE_SCAN_CONFIGS = [
56
+ SCAN_CONFIGS.frontendPages,
57
+ SCAN_CONFIGS.backendPages
58
+ ];
59
+ function checksum(value) {
60
+ return crypto.createHash("md5").update(value).digest("hex");
61
+ }
62
+ function fileRecord(filePath, base, mode) {
63
+ if (!fs.existsSync(filePath)) return null;
64
+ let stat;
65
+ try {
66
+ stat = fs.statSync(filePath);
67
+ } catch {
68
+ return null;
69
+ }
70
+ if (!stat.isFile()) return null;
71
+ const rel = path.relative(base, filePath).replace(/\\/g, "/");
72
+ if (mode === "shape") {
73
+ return `file:${rel}`;
74
+ }
75
+ try {
76
+ return `file:${rel}:${stat.size}:${checksum(fs.readFileSync(filePath, "utf8"))}`;
77
+ } catch {
78
+ return `file:${rel}:unreadable`;
79
+ }
80
+ }
81
+ function resolveCodeFile(base, relativePath) {
82
+ const stripped = stripModuleCodeExtension(relativePath);
83
+ const candidates = MODULE_CODE_EXTENSIONS.map((extension) => `${stripped}${extension}`);
84
+ for (const candidate of candidates) {
85
+ const filePath = path.join(base, ...candidate.split("/"));
86
+ if (fs.existsSync(filePath)) return filePath;
87
+ }
88
+ return null;
89
+ }
90
+ function hasInlinePageMetadata(filePath) {
91
+ try {
92
+ const source = fs.readFileSync(filePath, "utf8");
93
+ return /\bexport\s+(?:const|let|var|function|class)\s+metadata\b/.test(source) || /\bexport\s+\{[^}]*\bmetadata\b[^}]*\}/.test(source);
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+ function addConventionRecords(records, roots) {
99
+ for (const base of [roots.pkgBase, roots.appBase]) {
100
+ records.push(`module-root:${base}:${fs.existsSync(base) ? "present" : "missing"}`);
101
+ for (const relativePath of STRUCTURAL_CONVENTION_FILES) {
102
+ const filePath = resolveCodeFile(base, relativePath);
103
+ if (!filePath) {
104
+ records.push(`missing:${base}:${relativePath}`);
105
+ continue;
106
+ }
107
+ const record = fileRecord(filePath, base, "content");
108
+ if (record) records.push(record);
109
+ }
110
+ }
111
+ }
112
+ function addScannedRecords(records, roots) {
113
+ for (const config of CONTENT_SENSITIVE_SCAN_CONFIGS) {
114
+ for (const scanned of scanModuleDir(roots, config)) {
115
+ const base = scanned.fromApp ? roots.appBase : roots.pkgBase;
116
+ const filePath = path.join(base, ...config.folder.split("/"), ...scanned.relPath.split("/"));
117
+ const record = fileRecord(filePath, base, "content");
118
+ if (record) records.push(`${config.folder}:${record}`);
119
+ }
120
+ }
121
+ for (const config of ROUTE_SHAPE_SCAN_CONFIGS) {
122
+ for (const scanned of scanModuleDir(roots, config)) {
123
+ const base = scanned.fromApp ? roots.appBase : roots.pkgBase;
124
+ const folderPath = path.join(base, ...config.folder.split("/"));
125
+ const filePath = path.join(folderPath, ...scanned.relPath.split("/"));
126
+ const pageRecord = fileRecord(filePath, base, hasInlinePageMetadata(filePath) ? "content" : "shape");
127
+ if (pageRecord) records.push(`${config.folder}:${pageRecord}`);
128
+ const dir = path.dirname(filePath);
129
+ const stem = stripModuleCodeExtension(path.basename(filePath));
130
+ const metaCandidates = stem === "page" ? ["page.meta", "meta"] : [`${stem}.meta`, "meta"];
131
+ for (const candidate of metaCandidates) {
132
+ const metaPath = resolveCodeFile(dir, candidate);
133
+ if (!metaPath) continue;
134
+ const record = fileRecord(metaPath, base, "content");
135
+ if (record) records.push(`${config.folder}:meta:${record}`);
136
+ }
137
+ }
138
+ }
139
+ }
140
+ function calculateGenerateWatchStructureChecksum(options) {
141
+ const records = [];
142
+ const modulesRecord = fileRecord(options.modulesFile, path.dirname(options.modulesFile), "content");
143
+ records.push(modulesRecord ?? `missing:${options.modulesFile}`);
144
+ for (const roots of options.moduleRoots) {
145
+ addConventionRecords(records, roots);
146
+ addScannedRecords(records, roots);
147
+ }
148
+ return checksum(records.sort((a, b) => a.localeCompare(b)).join("\n"));
149
+ }
150
+ export {
151
+ calculateGenerateWatchStructureChecksum
152
+ };
153
+ //# sourceMappingURL=generate-watch-structure.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/generate-watch-structure.ts"],
4
+ "sourcesContent": ["import crypto from 'node:crypto'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport {\n MODULE_CODE_EXTENSIONS,\n SCAN_CONFIGS,\n scanModuleDir,\n stripModuleCodeExtension,\n type ModuleRoots,\n} from './generators/scanner'\n\nconst STRUCTURAL_CONVENTION_FILES = [\n 'index.ts',\n 'cli.ts',\n 'di.ts',\n 'acl.ts',\n 'setup.ts',\n 'encryption.ts',\n 'ce.ts',\n 'search.ts',\n 'events.ts',\n 'notifications.ts',\n 'notifications.client.ts',\n 'notifications.handlers.ts',\n 'translations.ts',\n 'generators.ts',\n 'ai-tools.ts',\n 'ai-agents.ts',\n 'analytics.ts',\n 'workflows.ts',\n 'inbox-actions.ts',\n 'message-types.ts',\n 'message-objects.ts',\n 'integration.ts',\n 'security.mfa-providers.ts',\n 'security.sudo.ts',\n 'data/entities.ts',\n 'data/extensions.ts',\n 'data/fields.ts',\n 'data/enrichers.ts',\n 'data/guards.ts',\n 'api/interceptors.ts',\n 'commands/interceptors.ts',\n 'widgets/components.ts',\n 'widgets/injection-table.ts',\n 'frontend/middleware.ts',\n 'backend/middleware.ts',\n] as const\n\nconst CONTENT_SENSITIVE_SCAN_CONFIGS = [\n SCAN_CONFIGS.apiRoutes,\n SCAN_CONFIGS.apiPlainFiles,\n SCAN_CONFIGS.subscribers,\n SCAN_CONFIGS.workers,\n SCAN_CONFIGS.dashboardWidgets,\n SCAN_CONFIGS.injectionWidgets,\n] as const\n\nconst ROUTE_SHAPE_SCAN_CONFIGS = [\n SCAN_CONFIGS.frontendPages,\n SCAN_CONFIGS.backendPages,\n] as const\n\nfunction checksum(value: string): string {\n return crypto.createHash('md5').update(value).digest('hex')\n}\n\nfunction fileRecord(filePath: string, base: string, mode: 'content' | 'shape'): string | null {\n if (!fs.existsSync(filePath)) return null\n let stat: fs.Stats\n try {\n stat = fs.statSync(filePath)\n } catch {\n return null\n }\n if (!stat.isFile()) return null\n const rel = path.relative(base, filePath).replace(/\\\\/g, '/')\n if (mode === 'shape') {\n return `file:${rel}`\n }\n try {\n return `file:${rel}:${stat.size}:${checksum(fs.readFileSync(filePath, 'utf8'))}`\n } catch {\n return `file:${rel}:unreadable`\n }\n}\n\nfunction resolveCodeFile(base: string, relativePath: string): string | null {\n const stripped = stripModuleCodeExtension(relativePath)\n const candidates = MODULE_CODE_EXTENSIONS.map((extension) => `${stripped}${extension}`)\n for (const candidate of candidates) {\n const filePath = path.join(base, ...candidate.split('/'))\n if (fs.existsSync(filePath)) return filePath\n }\n return null\n}\n\nfunction hasInlinePageMetadata(filePath: string): boolean {\n try {\n const source = fs.readFileSync(filePath, 'utf8')\n return /\\bexport\\s+(?:const|let|var|function|class)\\s+metadata\\b/.test(source)\n || /\\bexport\\s+\\{[^}]*\\bmetadata\\b[^}]*\\}/.test(source)\n } catch {\n return false\n }\n}\n\nfunction addConventionRecords(records: string[], roots: ModuleRoots): void {\n for (const base of [roots.pkgBase, roots.appBase]) {\n records.push(`module-root:${base}:${fs.existsSync(base) ? 'present' : 'missing'}`)\n for (const relativePath of STRUCTURAL_CONVENTION_FILES) {\n const filePath = resolveCodeFile(base, relativePath)\n if (!filePath) {\n records.push(`missing:${base}:${relativePath}`)\n continue\n }\n const record = fileRecord(filePath, base, 'content')\n if (record) records.push(record)\n }\n }\n}\n\nfunction addScannedRecords(records: string[], roots: ModuleRoots): void {\n for (const config of CONTENT_SENSITIVE_SCAN_CONFIGS) {\n for (const scanned of scanModuleDir(roots, config)) {\n const base = scanned.fromApp ? roots.appBase : roots.pkgBase\n const filePath = path.join(base, ...config.folder.split('/'), ...scanned.relPath.split('/'))\n const record = fileRecord(filePath, base, 'content')\n if (record) records.push(`${config.folder}:${record}`)\n }\n }\n\n for (const config of ROUTE_SHAPE_SCAN_CONFIGS) {\n for (const scanned of scanModuleDir(roots, config)) {\n const base = scanned.fromApp ? roots.appBase : roots.pkgBase\n const folderPath = path.join(base, ...config.folder.split('/'))\n const filePath = path.join(folderPath, ...scanned.relPath.split('/'))\n const pageRecord = fileRecord(filePath, base, hasInlinePageMetadata(filePath) ? 'content' : 'shape')\n if (pageRecord) records.push(`${config.folder}:${pageRecord}`)\n\n const dir = path.dirname(filePath)\n const stem = stripModuleCodeExtension(path.basename(filePath))\n const metaCandidates = stem === 'page'\n ? ['page.meta', 'meta']\n : [`${stem}.meta`, 'meta']\n for (const candidate of metaCandidates) {\n const metaPath = resolveCodeFile(dir, candidate)\n if (!metaPath) continue\n const record = fileRecord(metaPath, base, 'content')\n if (record) records.push(`${config.folder}:meta:${record}`)\n }\n }\n }\n}\n\nexport function calculateGenerateWatchStructureChecksum(options: {\n modulesFile: string\n moduleRoots: ModuleRoots[]\n}): string {\n const records: string[] = []\n const modulesRecord = fileRecord(options.modulesFile, path.dirname(options.modulesFile), 'content')\n records.push(modulesRecord ?? `missing:${options.modulesFile}`)\n\n for (const roots of options.moduleRoots) {\n addConventionRecords(records, roots)\n addScannedRecords(records, roots)\n }\n\n return checksum(records.sort((a, b) => a.localeCompare(b)).join('\\n'))\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/mercato.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  import { parseModuleInstallArgs } from "./lib/module-install-args.js";
26
26
  import { resolveNextBuildIdCandidate } from "./lib/next-build-id.js";
27
27
  import { acquireServerStartLock } from "./lib/server-start-lock.js";
28
- import { createDevEnvReloader, watchDevEnvFiles, watchDevRuntimeFiles } from "./lib/dev-env-reload.js";
28
+ import { createDevEnvReloader, watchDevEnvFiles } from "./lib/dev-env-reload.js";
29
29
  const lazyIntegration = () => import("./lib/testing/integration.js");
30
30
  import path from "node:path";
31
31
  import fs from "node:fs";
@@ -246,6 +246,82 @@ function buildServerProcessEnvironment(environment) {
246
246
  }
247
247
  return runtimeEnv;
248
248
  }
249
+ function resolveDevRuntimeBaseUrl(environment = process.env) {
250
+ const configured = environment.APP_URL ?? environment.NEXT_PUBLIC_APP_URL ?? environment.NEXTAUTH_URL;
251
+ if (configured?.trim()) {
252
+ return configured.trim().replace(/\/+$/, "");
253
+ }
254
+ return `http://localhost:${environment.PORT?.trim() || "3000"}`;
255
+ }
256
+ function writeDevSplashChildState(state) {
257
+ if (process.env.OM_DEV_SPLASH_RUNTIME_WRAPPER === "1") return;
258
+ const stateFile = process.env.OM_DEV_SPLASH_CHILD_STATE_FILE;
259
+ if (!stateFile?.trim()) return;
260
+ try {
261
+ fs.mkdirSync(path.dirname(stateFile), { recursive: true });
262
+ fs.writeFileSync(stateFile, `${JSON.stringify({
263
+ mode: process.env.OM_DEV_SPLASH_MODE || "dev",
264
+ failed: false,
265
+ failureLines: [],
266
+ failureCommand: null,
267
+ ...state
268
+ }, null, 2)}
269
+ `);
270
+ } catch {
271
+ }
272
+ }
273
+ function writeDevSplashRuntimeStarting(detail = "Starting Next.js dev server") {
274
+ writeDevSplashChildState({
275
+ phase: "Preparing app runtime",
276
+ detail,
277
+ ready: false,
278
+ readyUrl: null,
279
+ loginUrl: null,
280
+ progressLabel: "Launching app runtime",
281
+ activity: detail
282
+ });
283
+ }
284
+ function resolveSplashProgressFallback() {
285
+ const current = Number.parseInt(process.env.OM_DEV_SPLASH_STAGE_CURRENT ?? "", 10);
286
+ const total = Number.parseInt(process.env.OM_DEV_SPLASH_STAGE_TOTAL ?? "", 10);
287
+ if (Number.isFinite(current) && Number.isFinite(total) && total > 0) {
288
+ return { current, total };
289
+ }
290
+ if (process.env.OM_DEV_SPLASH_MODE === "greenfield" || process.env.OM_DEV_SPLASH_MODE === "setup") {
291
+ return { current: 5, total: 5 };
292
+ }
293
+ return { current: 3, total: 3 };
294
+ }
295
+ function writeDevSplashRuntimeRestarting(reason) {
296
+ const progress = resolveSplashProgressFallback();
297
+ writeDevSplashChildState({
298
+ phase: "App runtime is restarting",
299
+ detail: `Reason: ${reason}`,
300
+ ready: false,
301
+ readyUrl: null,
302
+ loginUrl: null,
303
+ progressCurrent: progress.current,
304
+ progressTotal: progress.total,
305
+ progressLabel: "Restarting app runtime",
306
+ activity: `App runtime restart: ${reason}`
307
+ });
308
+ }
309
+ function writeDevSplashRuntimeReady(reason) {
310
+ const readyUrl = resolveDevRuntimeBaseUrl();
311
+ const progress = resolveSplashProgressFallback();
312
+ writeDevSplashChildState({
313
+ phase: "App is ready",
314
+ detail: reason ? `Restart completed after ${reason}` : "Next.js dev server is ready",
315
+ ready: true,
316
+ readyUrl,
317
+ loginUrl: `${readyUrl}/login`,
318
+ progressCurrent: progress.current,
319
+ progressTotal: progress.total,
320
+ progressPercent: 100,
321
+ progressLabel: "App is ready",
322
+ activity: reason ? `Restart completed after ${reason}` : "App runtime is ready"
323
+ });
324
+ }
249
325
  function waitForManagedProcessExit(proc, label) {
250
326
  return new Promise((resolve) => {
251
327
  proc.on("exit", (code, signal) => {
@@ -445,18 +521,17 @@ async function runGeneratorSuite(quiet) {
445
521
  function createGenerateWatchChecksumFn() {
446
522
  return async () => {
447
523
  const { createResolver } = await import("./lib/resolver.js");
448
- const { calculateStructureChecksum } = await import("./lib/utils.js");
524
+ const { calculateGenerateWatchStructureChecksum } = await import("./lib/generate-watch-structure.js");
449
525
  const resolver = createResolver();
450
- const tracked = /* @__PURE__ */ new Set([
451
- path.join(resolver.getAppDir(), "src", "modules.ts"),
452
- path.join(resolver.getAppDir(), "src", "modules")
453
- ]);
526
+ const moduleRoots = [];
454
527
  for (const entry of resolver.loadEnabledModules()) {
455
528
  const roots = resolver.getModulePaths(entry);
456
- tracked.add(roots.appBase);
457
- tracked.add(roots.pkgBase);
529
+ moduleRoots.push({ appBase: roots.appBase, pkgBase: roots.pkgBase });
458
530
  }
459
- return calculateStructureChecksum(Array.from(tracked));
531
+ return calculateGenerateWatchStructureChecksum({
532
+ modulesFile: path.join(resolver.getAppDir(), "src", "modules.ts"),
533
+ moduleRoots
534
+ });
460
535
  };
461
536
  }
462
537
  async function buildAllModules() {
@@ -1394,6 +1469,7 @@ async function run(argv = process.argv) {
1394
1469
  let activeLazySupervisor = null;
1395
1470
  let activeLazySchedulerSupervisor = null;
1396
1471
  let activeGenerateWatcher = null;
1472
+ let lastRestartReason = null;
1397
1473
  const generateWatcherMode = resolveGenerateWatcherMode(process.env);
1398
1474
  const envReloader = createDevEnvReloader(appDir, process.env, initialProcessEnvironmentEntries);
1399
1475
  function cleanup() {
@@ -1472,17 +1548,13 @@ async function run(argv = process.argv) {
1472
1548
  filePath
1473
1549
  });
1474
1550
  });
1475
- const stopRuntimeWatcher = watchDevRuntimeFiles(appDir, (filePath) => {
1476
- devRestartPromiseResolve?.({
1477
- label: "Runtime graph change",
1478
- restart: true,
1479
- filePath
1480
- });
1481
- });
1482
1551
  const waitForDevRestart = () => new Promise((resolve) => {
1483
1552
  devRestartPromiseResolve = resolve;
1484
1553
  });
1485
1554
  const startNextDev = (runtimeEnv) => new Promise((resolve) => {
1555
+ writeDevSplashRuntimeStarting(
1556
+ lastRestartReason ? `Restarting Next.js dev server. Reason: ${lastRestartReason}` : "Starting Next.js dev server"
1557
+ );
1486
1558
  const nextProcess = spawn("node", [nextBin, "dev", "--turbopack"], {
1487
1559
  stdio: ["inherit", "pipe", "pipe"],
1488
1560
  env: runtimeEnv,
@@ -1490,11 +1562,17 @@ async function run(argv = process.argv) {
1490
1562
  });
1491
1563
  processes.push(nextProcess);
1492
1564
  let combinedOutput = "";
1565
+ let reportedReady = false;
1493
1566
  const appendOutput = (chunk) => {
1494
1567
  combinedOutput += chunk;
1495
1568
  if (combinedOutput.length > 32768) {
1496
1569
  combinedOutput = combinedOutput.slice(-32768);
1497
1570
  }
1571
+ if (!reportedReady && /\bready in\b/i.test(chunk)) {
1572
+ reportedReady = true;
1573
+ writeDevSplashRuntimeReady(lastRestartReason ?? void 0);
1574
+ lastRestartReason = null;
1575
+ }
1498
1576
  };
1499
1577
  nextProcess.stdout?.on("data", (chunk) => {
1500
1578
  const text = typeof chunk === "string" ? chunk : chunk.toString();
@@ -1509,6 +1587,8 @@ async function run(argv = process.argv) {
1509
1587
  nextProcess.on("exit", async (code, signal) => {
1510
1588
  if (!didRetryCorruptedTurbopackCache && isTurbopackCacheCorruption(combinedOutput)) {
1511
1589
  didRetryCorruptedTurbopackCache = true;
1590
+ lastRestartReason = "corrupted Turbopack dev cache";
1591
+ writeDevSplashRuntimeRestarting(lastRestartReason);
1512
1592
  console.log("[server] Detected corrupted Turbopack dev cache. Clearing .mercato/next/dev and restarting Next.js once...");
1513
1593
  removeTurbopackDevCache(appDir);
1514
1594
  return resolve(await startNextDev(runtimeEnv));
@@ -1601,6 +1681,10 @@ async function run(argv = process.argv) {
1601
1681
  console.log("[server] Legacy out-of-process generate watcher selected via OM_DEV_GENERATE_WATCH_MODE=legacy \u2014 expect the dev orchestrator to spawn `mercato generate watch --skip-initial`.");
1602
1682
  }
1603
1683
  const firstExit = await Promise.race(managedExitPromises);
1684
+ if (isDevServerRestartResult(firstExit)) {
1685
+ lastRestartReason = `${firstExit.label.toLowerCase()} (${path.basename(firstExit.filePath)})`;
1686
+ writeDevSplashRuntimeRestarting(lastRestartReason);
1687
+ }
1604
1688
  await cleanupAndWait();
1605
1689
  devRestartPromiseResolve = null;
1606
1690
  if (isDevServerRestartResult(firstExit)) {
@@ -1614,7 +1698,6 @@ async function run(argv = process.argv) {
1614
1698
  }
1615
1699
  } finally {
1616
1700
  stopEnvWatcher();
1617
- stopRuntimeWatcher();
1618
1701
  }
1619
1702
  }
1620
1703
  },