@open-mercato/cli 0.6.7-develop.6553.1.2ec7246e04 → 0.6.7-develop.6565.1.1026d85fff
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/.turbo/turbo-build.log +3 -3
- package/AGENTS.md +1 -0
- package/dist/agentic/guides/module-facts.json +53 -53
- package/dist/agentic/guides/modules/ai_assistant.md +1 -1
- package/dist/agentic/guides/modules/api_docs.md +1 -1
- package/dist/agentic/guides/modules/api_keys.md +1 -1
- package/dist/agentic/guides/modules/attachments.md +1 -1
- package/dist/agentic/guides/modules/audit_logs.md +1 -1
- package/dist/agentic/guides/modules/auth.md +1 -1
- package/dist/agentic/guides/modules/business_rules.md +1 -1
- package/dist/agentic/guides/modules/catalog.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail.md +1 -1
- package/dist/agentic/guides/modules/channel_imap.md +1 -1
- package/dist/agentic/guides/modules/checkout.md +1 -1
- package/dist/agentic/guides/modules/communication_channels.md +1 -1
- package/dist/agentic/guides/modules/configs.md +1 -1
- package/dist/agentic/guides/modules/content.md +1 -1
- package/dist/agentic/guides/modules/currencies.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts.md +1 -1
- package/dist/agentic/guides/modules/customers.md +1 -1
- package/dist/agentic/guides/modules/dashboards.md +1 -1
- package/dist/agentic/guides/modules/data_sync.md +1 -1
- package/dist/agentic/guides/modules/dictionaries.md +1 -1
- package/dist/agentic/guides/modules/directory.md +1 -1
- package/dist/agentic/guides/modules/entities.md +1 -1
- package/dist/agentic/guides/modules/events.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe.md +1 -1
- package/dist/agentic/guides/modules/generators.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops.md +1 -1
- package/dist/agentic/guides/modules/integrations.md +1 -1
- package/dist/agentic/guides/modules/messages.md +1 -1
- package/dist/agentic/guides/modules/notifications.md +1 -1
- package/dist/agentic/guides/modules/onboarding.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways.md +1 -1
- package/dist/agentic/guides/modules/perspectives.md +1 -1
- package/dist/agentic/guides/modules/planner.md +1 -1
- package/dist/agentic/guides/modules/portal.md +1 -1
- package/dist/agentic/guides/modules/progress.md +1 -1
- package/dist/agentic/guides/modules/query_index.md +1 -1
- package/dist/agentic/guides/modules/record_locks.md +1 -1
- package/dist/agentic/guides/modules/resources.md +1 -1
- package/dist/agentic/guides/modules/sales.md +1 -1
- package/dist/agentic/guides/modules/scheduler.md +1 -1
- package/dist/agentic/guides/modules/search.md +1 -1
- package/dist/agentic/guides/modules/security.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers.md +1 -1
- package/dist/agentic/guides/modules/sso.md +1 -1
- package/dist/agentic/guides/modules/staff.md +1 -1
- package/dist/agentic/guides/modules/storage_s3.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo.md +1 -1
- package/dist/agentic/guides/modules/sync_excel.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays.md +1 -1
- package/dist/agentic/guides/modules/translations.md +1 -1
- package/dist/agentic/guides/modules/webhooks.md +1 -1
- package/dist/agentic/guides/modules/workflows.md +1 -1
- package/dist/agentic/shared/AGENTS.md.template +1 -1
- package/dist/agentic/shared/ai/skills/tiers.schema.json +15 -0
- package/dist/agentic/shared/scripts/install-skills.sh +244 -37
- package/dist/lib/__integration__/TC-INT-008.spec.js +9 -11
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-setup.js +14 -2
- package/dist/lib/agentic-setup.js.map +2 -2
- package/dist/lib/generate-watch-events.js +106 -0
- package/dist/lib/generate-watch-events.js.map +7 -0
- package/dist/lib/generators/entity-ids.js +20 -13
- package/dist/lib/generators/entity-ids.js.map +2 -2
- package/dist/lib/generators/openapi.js +114 -12
- package/dist/lib/generators/openapi.js.map +2 -2
- package/dist/lib/in-process-generate-watcher.js +13 -2
- package/dist/lib/in-process-generate-watcher.js.map +2 -2
- package/dist/mercato.js +68 -23
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/__tests__/mercato.test.ts +53 -2
- package/src/lib/__integration__/TC-INT-008.spec.ts +15 -15
- package/src/lib/__tests__/generate-watch-events.test.ts +112 -0
- package/src/lib/__tests__/generate-watch-structure.test.ts +20 -0
- package/src/lib/__tests__/in-process-generate-watcher.test.ts +193 -2
- package/src/lib/agentic-setup.ts +23 -4
- package/src/lib/generate-watch-events.ts +125 -0
- package/src/lib/generators/__tests__/entity-ids.test.ts +98 -1
- package/src/lib/generators/__tests__/openapi.test.ts +174 -0
- package/src/lib/generators/entity-ids.ts +33 -13
- package/src/lib/generators/openapi.ts +167 -14
- package/src/lib/in-process-generate-watcher.ts +35 -6
- package/src/mercato.ts +75 -27
|
@@ -3,20 +3,88 @@ import * as path from "node:path";
|
|
|
3
3
|
import { isModuleRouteFile } from "./scanner.js";
|
|
4
4
|
import {
|
|
5
5
|
calculateChecksum,
|
|
6
|
+
calculateStructureChecksum,
|
|
6
7
|
readChecksumRecord,
|
|
7
8
|
writeChecksumRecord,
|
|
8
9
|
logGenerationResult,
|
|
9
10
|
createGeneratorResult
|
|
10
11
|
} from "../utils.js";
|
|
12
|
+
const OPENAPI_INPUT_MANIFEST_VERSION = 1;
|
|
13
|
+
function createOpenApiInputContext(resolver) {
|
|
14
|
+
const enabled = resolver.loadEnabledModules();
|
|
15
|
+
const apiRoots = [];
|
|
16
|
+
const moduleIdentity = enabled.map((entry) => {
|
|
17
|
+
const roots = resolver.getModulePaths(entry);
|
|
18
|
+
apiRoots.push(path.join(roots.appBase, "api"), path.join(roots.pkgBase, "api"));
|
|
19
|
+
return {
|
|
20
|
+
id: entry.id,
|
|
21
|
+
from: entry.from ?? "@open-mercato/core",
|
|
22
|
+
appBase: path.resolve(roots.appBase),
|
|
23
|
+
pkgBase: path.resolve(roots.pkgBase)
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
return { enabled, apiRoots, moduleIdentity };
|
|
27
|
+
}
|
|
28
|
+
function readOpenApiInputManifest(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
31
|
+
if (parsed.version !== OPENAPI_INPUT_MANIFEST_VERSION || !Array.isArray(parsed.inputPaths) || parsed.inputPaths.some((entry) => typeof entry !== "string")) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
version: OPENAPI_INPUT_MANIFEST_VERSION,
|
|
36
|
+
inputPaths: Array.from(new Set(parsed.inputPaths.map((entry) => path.resolve(entry)))).sort((a, b) => a.localeCompare(b))
|
|
37
|
+
};
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function trackedPathRecord(filePath) {
|
|
43
|
+
try {
|
|
44
|
+
const stat = fs.statSync(filePath);
|
|
45
|
+
if (stat.isFile()) {
|
|
46
|
+
return `${path.resolve(filePath)}:${calculateChecksum(fs.readFileSync(filePath, "utf8"))}`;
|
|
47
|
+
}
|
|
48
|
+
return `${path.resolve(filePath)}:${stat.size}:${stat.mtimeMs}`;
|
|
49
|
+
} catch {
|
|
50
|
+
return `missing:${path.resolve(filePath)}`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function calculateOpenApiInputFingerprint(resolver, context, manifest) {
|
|
54
|
+
const rootDir = resolver.getRootDir();
|
|
55
|
+
const appDir = resolver.getAppDir();
|
|
56
|
+
const configPaths = [
|
|
57
|
+
resolver.getModulesConfigPath(),
|
|
58
|
+
path.join(rootDir, "package.json"),
|
|
59
|
+
path.join(rootDir, "yarn.lock"),
|
|
60
|
+
path.join(rootDir, "package-lock.json"),
|
|
61
|
+
path.join(rootDir, "pnpm-lock.yaml"),
|
|
62
|
+
path.join(rootDir, "tsconfig.json"),
|
|
63
|
+
path.join(rootDir, "tsconfig.base.json"),
|
|
64
|
+
path.join(appDir, "package.json"),
|
|
65
|
+
path.join(appDir, "tsconfig.json")
|
|
66
|
+
];
|
|
67
|
+
const trackedRecords = [...manifest.inputPaths, ...configPaths].map(trackedPathRecord).sort((a, b) => a.localeCompare(b));
|
|
68
|
+
return calculateChecksum(JSON.stringify({
|
|
69
|
+
version: OPENAPI_INPUT_MANIFEST_VERSION,
|
|
70
|
+
modules: context.moduleIdentity,
|
|
71
|
+
routeStructure: calculateStructureChecksum(context.apiRoots),
|
|
72
|
+
trackedRecords,
|
|
73
|
+
environment: {
|
|
74
|
+
node: process.version,
|
|
75
|
+
nodeEnv: process.env.NODE_ENV ?? "",
|
|
76
|
+
publicAppUrl: process.env.NEXT_PUBLIC_APP_URL ?? ""
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
11
80
|
function resolveExistingPath(paths) {
|
|
12
81
|
for (const candidate of paths) {
|
|
13
82
|
if (fs.existsSync(candidate)) return candidate;
|
|
14
83
|
}
|
|
15
84
|
return null;
|
|
16
85
|
}
|
|
17
|
-
async function findApiRoutes(resolver) {
|
|
86
|
+
async function findApiRoutes(resolver, enabled) {
|
|
18
87
|
const routes = [];
|
|
19
|
-
const enabled = resolver.loadEnabledModules();
|
|
20
88
|
for (const entry of enabled) {
|
|
21
89
|
const modId = entry.id;
|
|
22
90
|
const roots = resolver.getModulePaths(entry);
|
|
@@ -117,7 +185,7 @@ async function generateOpenApiViaBundle(routes, resolver, quiet) {
|
|
|
117
185
|
esbuild = await import("esbuild");
|
|
118
186
|
} catch {
|
|
119
187
|
if (!quiet) console.log("[OpenAPI] esbuild not available, skipping bundle approach");
|
|
120
|
-
return null;
|
|
188
|
+
return { doc: null, inputPaths: [] };
|
|
121
189
|
}
|
|
122
190
|
const { execFileSync } = await import("node:child_process");
|
|
123
191
|
const rootDir = resolver.getRootDir();
|
|
@@ -135,11 +203,12 @@ async function generateOpenApiViaBundle(routes, resolver, quiet) {
|
|
|
135
203
|
if (!quiet) {
|
|
136
204
|
console.log(`[OpenAPI] Generator source not found at ${generatorPath}, skipping bundle approach`);
|
|
137
205
|
}
|
|
138
|
-
return null;
|
|
206
|
+
return { doc: null, inputPaths: [] };
|
|
139
207
|
}
|
|
140
208
|
const cacheDir = path.join(rootDir, "node_modules", ".cache");
|
|
141
209
|
if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
|
|
142
210
|
const bundlePath = path.join(cacheDir, "_openapi-bundle.mjs");
|
|
211
|
+
let inputPaths = [];
|
|
143
212
|
const importLines = [
|
|
144
213
|
`import { buildOpenApiDocument } from ${JSON.stringify(generatorPath)};`
|
|
145
214
|
];
|
|
@@ -331,7 +400,7 @@ process.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>
|
|
|
331
400
|
}
|
|
332
401
|
};
|
|
333
402
|
try {
|
|
334
|
-
await esbuild.build({
|
|
403
|
+
const buildResult = await esbuild.build({
|
|
335
404
|
stdin: {
|
|
336
405
|
contents: entryScript,
|
|
337
406
|
resolveDir: appDir,
|
|
@@ -339,6 +408,8 @@ process.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>
|
|
|
339
408
|
loader: "ts"
|
|
340
409
|
},
|
|
341
410
|
bundle: true,
|
|
411
|
+
metafile: true,
|
|
412
|
+
absWorkingDir: rootDir,
|
|
342
413
|
format: "esm",
|
|
343
414
|
platform: "node",
|
|
344
415
|
target: "node18",
|
|
@@ -349,6 +420,7 @@ process.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>
|
|
|
349
420
|
jsx: "automatic",
|
|
350
421
|
plugins: [stubNextPlugin, resolveProjectImportsPlugin, externalNonWorkspacePlugin]
|
|
351
422
|
});
|
|
423
|
+
inputPaths = Object.keys(buildResult.metafile?.inputs ?? {}).filter((inputPath) => !inputPath.startsWith("<")).map((inputPath) => path.resolve(rootDir, inputPath)).filter((inputPath) => fs.existsSync(inputPath)).sort((a, b) => a.localeCompare(b));
|
|
352
424
|
const stdout = execFileSync(process.execPath, [bundlePath], {
|
|
353
425
|
timeout: 6e4,
|
|
354
426
|
maxBuffer: 20 * 1024 * 1024,
|
|
@@ -368,7 +440,7 @@ process.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>
|
|
|
368
440
|
}, 0);
|
|
369
441
|
console.log(`[OpenAPI] Bundle approach: ${pathCount} paths, ${withBody} with requestBody schemas`);
|
|
370
442
|
}
|
|
371
|
-
return doc;
|
|
443
|
+
return { doc, inputPaths };
|
|
372
444
|
} catch (err) {
|
|
373
445
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
374
446
|
const stderr = err?.stderr;
|
|
@@ -392,7 +464,7 @@ process.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>
|
|
|
392
464
|
}
|
|
393
465
|
}
|
|
394
466
|
}
|
|
395
|
-
return null;
|
|
467
|
+
return { doc: null, inputPaths };
|
|
396
468
|
} finally {
|
|
397
469
|
try {
|
|
398
470
|
await esbuild.stop();
|
|
@@ -440,14 +512,26 @@ async function generateOpenApi(options) {
|
|
|
440
512
|
const outputDir = resolver.getOutputDir();
|
|
441
513
|
const outFile = path.join(outputDir, "openapi.generated.json");
|
|
442
514
|
const checksumFile = path.join(outputDir, "openapi.generated.checksum");
|
|
515
|
+
const inputManifestFile = path.join(outputDir, "openapi.generated.inputs.json");
|
|
443
516
|
if (!fs.existsSync(outputDir)) {
|
|
444
517
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
445
518
|
}
|
|
446
|
-
const
|
|
519
|
+
const inputContext = createOpenApiInputContext(resolver);
|
|
520
|
+
const existingChecksums = readChecksumRecord(checksumFile);
|
|
521
|
+
const existingManifest = readOpenApiInputManifest(inputManifestFile);
|
|
522
|
+
if (existingChecksums?.structure && existingManifest && fs.existsSync(outFile) && calculateChecksum(fs.readFileSync(outFile, "utf8")) === existingChecksums.content && calculateOpenApiInputFingerprint(resolver, inputContext, existingManifest) === existingChecksums.structure) {
|
|
523
|
+
result.filesUnchanged.push(outFile);
|
|
524
|
+
if (!quiet) {
|
|
525
|
+
console.log(`[OpenAPI] Skipped (inputs unchanged): ${outFile}`);
|
|
526
|
+
}
|
|
527
|
+
return result;
|
|
528
|
+
}
|
|
529
|
+
const routes = await findApiRoutes(resolver, inputContext.enabled);
|
|
447
530
|
if (!quiet) {
|
|
448
531
|
console.log(`[OpenAPI] Found ${routes.length} API route files`);
|
|
449
532
|
}
|
|
450
|
-
|
|
533
|
+
const bundleResult = await generateOpenApiViaBundle(routes, resolver, quiet);
|
|
534
|
+
let doc = bundleResult.doc;
|
|
451
535
|
if (!doc) {
|
|
452
536
|
if (!quiet) {
|
|
453
537
|
console.log("[OpenAPI] Falling back to static regex approach");
|
|
@@ -478,8 +562,26 @@ async function generateOpenApi(options) {
|
|
|
478
562
|
}
|
|
479
563
|
const output = JSON.stringify(doc, null, 2);
|
|
480
564
|
const checksum = calculateChecksum(output);
|
|
481
|
-
|
|
482
|
-
if (
|
|
565
|
+
let structureChecksum = "";
|
|
566
|
+
if (bundleResult.doc && bundleResult.inputPaths.length > 0) {
|
|
567
|
+
const manifest = {
|
|
568
|
+
version: OPENAPI_INPUT_MANIFEST_VERSION,
|
|
569
|
+
inputPaths: Array.from(new Set(bundleResult.inputPaths)).sort((a, b) => a.localeCompare(b))
|
|
570
|
+
};
|
|
571
|
+
fs.writeFileSync(inputManifestFile, `${JSON.stringify(manifest, null, 2)}
|
|
572
|
+
`);
|
|
573
|
+
structureChecksum = calculateOpenApiInputFingerprint(resolver, inputContext, manifest);
|
|
574
|
+
} else {
|
|
575
|
+
try {
|
|
576
|
+
fs.unlinkSync(inputManifestFile);
|
|
577
|
+
} catch {
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const existingOutputMatches = fs.existsSync(outFile) && calculateChecksum(fs.readFileSync(outFile, "utf8")) === checksum;
|
|
581
|
+
if (existingChecksums && existingChecksums.content === checksum && existingOutputMatches) {
|
|
582
|
+
if (existingChecksums.structure !== structureChecksum) {
|
|
583
|
+
writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum });
|
|
584
|
+
}
|
|
483
585
|
result.filesUnchanged.push(outFile);
|
|
484
586
|
if (!quiet) {
|
|
485
587
|
console.log(`[OpenAPI] Skipped (unchanged): ${outFile}`);
|
|
@@ -487,7 +589,7 @@ async function generateOpenApi(options) {
|
|
|
487
589
|
return result;
|
|
488
590
|
}
|
|
489
591
|
fs.writeFileSync(outFile, output);
|
|
490
|
-
writeChecksumRecord(checksumFile, { content: checksum, structure:
|
|
592
|
+
writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum });
|
|
491
593
|
result.filesWritten.push(outFile);
|
|
492
594
|
if (!quiet) {
|
|
493
595
|
logGenerationResult(outFile, true);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/generators/openapi.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * OpenAPI JSON Generator\n *\n * Generates a static openapi.generated.json file at build time.\n * This allows CLI tools (like MCP dev server) to access API endpoint\n * information without requiring a running Next.js app.\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { PackageResolver } from '../resolver'\nimport { isModuleRouteFile } from './scanner'\nimport {\n calculateChecksum,\n readChecksumRecord,\n writeChecksumRecord,\n logGenerationResult,\n type GeneratorResult,\n createGeneratorResult,\n} from '../utils'\n\nexport interface GenerateOpenApiOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\ninterface ApiRouteInfo {\n path: string\n methods: HttpMethod[]\n openApiPath: string\n}\n\nfunction resolveExistingPath(paths: string[]): string | null {\n for (const candidate of paths) {\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\n/**\n * Find all API route files and extract their OpenAPI specs.\n */\nasync function findApiRoutes(resolver: PackageResolver): Promise<ApiRouteInfo[]> {\n const routes: ApiRouteInfo[] = []\n const enabled = resolver.loadEnabledModules()\n\n for (const entry of enabled) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n\n const apiApp = path.join(roots.appBase, 'api')\n const apiPkg = path.join(roots.pkgBase, 'api')\n\n // Scan route files\n const routeFiles: Array<{ relativePath: string; fullPath: string }> = []\n\n const walkDir = (dir: string, rel: string[] = []) => {\n if (!fs.existsSync(dir)) return\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n if (e.isDirectory()) {\n if (e.name === '__tests__' || e.name === '__mocks__') continue\n walkDir(path.join(dir, e.name), [...rel, e.name])\n } else if (e.isFile() && isModuleRouteFile(e.name)) {\n routeFiles.push({\n relativePath: [...rel].join('/'),\n fullPath: path.join(dir, e.name),\n })\n }\n }\n }\n\n // Scan package first, then app (app overrides)\n if (fs.existsSync(apiPkg)) walkDir(apiPkg)\n if (fs.existsSync(apiApp)) walkDir(apiApp)\n\n // Process unique routes (later app files overwrite earlier package files)\n const filesByRelativePath = new Map<string, string>()\n for (const { relativePath, fullPath } of routeFiles) {\n filesByRelativePath.set(relativePath, fullPath)\n }\n\n for (const [relativePath, fullPath] of filesByRelativePath) {\n\n // Build API path\n const routeSegs = relativePath ? relativePath.split('/') : []\n const apiPath = `/api/${modId}${routeSegs.length ? '/' + routeSegs.join('/') : ''}`\n // Convert [param] to {param} for OpenAPI format\n .replace(/\\[([^\\]]+)\\]/g, '{$1}')\n\n routes.push({\n path: fullPath,\n methods: await detectMethods(fullPath),\n openApiPath: apiPath,\n })\n }\n }\n\n return routes\n}\n\n/**\n * Detect which HTTP methods are exported from a route file.\n */\nasync function detectMethods(filePath: string): Promise<HttpMethod[]> {\n const methods: HttpMethod[] = []\n const content = fs.readFileSync(filePath, 'utf-8')\n\n const methodPatterns: HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n for (const method of methodPatterns) {\n // Check for export { GET }, export const GET, export async function GET\n const patterns = [\n new RegExp(`export\\\\s+(const|async\\\\s+function|function)\\\\s+${method}\\\\b`),\n new RegExp(`export\\\\s*\\\\{[^}]*\\\\b${method}\\\\b[^}]*\\\\}`),\n ]\n if (patterns.some((p) => p.test(content))) {\n methods.push(method)\n }\n }\n\n return methods\n}\n\n/**\n * Parse openApi export from route file source code statically.\n * This extracts basic operation info without needing to compile the file.\n */\nfunction parseOpenApiFromSource(filePath: string): Record<string, any> | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n\n // Check if file exports openApi\n if (!content.includes('export const openApi') && !content.includes('export { openApi')) {\n return null\n }\n\n // Extract operationId, summary, description from the source\n const result: Record<string, any> = {}\n const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n\n for (const method of methods) {\n // Look for method specs in the openApi object\n // Pattern: GET: { operationId: '...', summary: '...', ... }\n const methodPattern = new RegExp(\n `${method}\\\\s*:\\\\s*\\\\{([^}]+(?:\\\\{[^}]*\\\\}[^}]*)*)\\\\}`,\n 's'\n )\n const methodMatch = content.match(methodPattern)\n\n if (methodMatch) {\n const methodContent = methodMatch[1]\n const spec: Record<string, any> = {}\n\n // Extract operationId\n const opIdMatch = methodContent.match(/operationId\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (opIdMatch) spec.operationId = opIdMatch[1]\n\n // Extract summary\n const summaryMatch = methodContent.match(/summary\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (summaryMatch) spec.summary = summaryMatch[1]\n\n // Extract description\n const descMatch = methodContent.match(/description\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descMatch) spec.description = descMatch[1]\n\n // Extract tags\n const tagsMatch = methodContent.match(/tags\\s*:\\s*\\[([^\\]]*)\\]/)\n if (tagsMatch) {\n const tagsContent = tagsMatch[1]\n const tags = tagsContent.match(/['\"]([^'\"]+)['\"]/g)\n if (tags) {\n spec.tags = tags.map(t => t.replace(/['\"]/g, ''))\n }\n }\n\n if (Object.keys(spec).length > 0) {\n result[method] = spec\n }\n }\n }\n\n return Object.keys(result).length > 0 ? result : null\n } catch {\n return null\n }\n}\n\n/**\n * Generate a complete OpenAPI document by bundling route files with esbuild\n * and executing the bundle to call buildOpenApiDocument from @open-mercato/shared.\n *\n * esbuild compiles TypeScript with legacy decorator support (reads experimentalDecorators\n * from tsconfig.json), avoiding the TC39 decorator mismatch that breaks tsx-based imports.\n * External packages (zod, mikro-orm, etc.) are resolved from node_modules at runtime.\n */\nasync function generateOpenApiViaBundle(\n routes: ApiRouteInfo[],\n resolver: PackageResolver,\n quiet: boolean\n): Promise<Record<string, any> | null> {\n let esbuild: typeof import('esbuild')\n try {\n esbuild = await import('esbuild')\n } catch {\n if (!quiet) console.log('[OpenAPI] esbuild not available, skipping bundle approach')\n return null\n }\n\n const { execFileSync } = await import('node:child_process')\n\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const sharedPackageRoot = resolver.getPackageRoot('@open-mercato/shared')\n const corePackageRoot = resolver.getPackageRoot('@open-mercato/core')\n const tsconfigPath = resolveExistingPath([\n path.join(appDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(rootDir, 'tsconfig.json'),\n ])\n const generatorPath = path.join(sharedPackageRoot, 'src', 'lib', 'openapi', 'generator.ts')\n const coreGeneratedRoot = path.join(corePackageRoot, 'generated')\n\n if (!fs.existsSync(generatorPath)) {\n if (!quiet) {\n console.log(`[OpenAPI] Generator source not found at ${generatorPath}, skipping bundle approach`)\n }\n return null\n }\n\n const cacheDir = path.join(rootDir, 'node_modules', '.cache')\n if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true })\n\n const bundlePath = path.join(cacheDir, '_openapi-bundle.mjs')\n\n // Build the entry script that imports all routes and calls buildOpenApiDocument\n const importLines: string[] = [\n `import { buildOpenApiDocument } from ${JSON.stringify(generatorPath)};`,\n ]\n const routeMapLines: string[] = []\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i]\n importLines.push(`import * as R${i} from ${JSON.stringify(route.path)};`)\n // Use [param] format so normalizePath in buildOpenApiDocument extracts path params\n const bracketPath = route.openApiPath.replace(/\\{([^}]+)\\}/g, '[$1]')\n routeMapLines.push(` [${JSON.stringify(bracketPath)}, R${i}],`)\n }\n\n const entryScript = `${importLines.join('\\n')}\n\nconst routeEntries = [\n${routeMapLines.join('\\n')}\n];\n\nconst modules = new Map();\nfor (const [apiPath, mod] of routeEntries) {\n const moduleId = apiPath.replace(/^\\\\/api\\\\//, '').split('/')[0];\n if (!modules.has(moduleId)) modules.set(moduleId, { id: moduleId, apis: [] });\n modules.get(moduleId).apis.push({\n path: apiPath,\n handlers: mod,\n metadata: mod.metadata,\n });\n}\n\nconst doc = buildOpenApiDocument([...modules.values()], {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n servers: [{ url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' }],\n});\n\n// Deep-clone to break shared object references before serializing.\n// The zodToJsonSchema memo cache returns the same object instance for\n// fields like currencyCode that appear on both parent and child schemas.\n// A naive WeakSet-based circular-ref guard would drop the second occurrence,\n// causing properties to vanish from the generated spec (while the field\n// still appears in the 'required' array, since those are plain strings).\nconst deepClone = (v, ancestors = []) => {\n if (v === null || typeof v !== 'object') return v;\n if (typeof v === 'bigint') return Number(v);\n if (typeof v === 'function') return undefined;\n if (ancestors.includes(v)) return undefined; // true circular ref\n const next = [...ancestors, v];\n if (Array.isArray(v)) return v.map((item) => deepClone(item, next));\n const out = {};\n for (const [k, val] of Object.entries(v)) {\n const cloned = deepClone(val, next);\n if (cloned !== undefined) out[k] = cloned;\n }\n return out;\n};\nprocess.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>\n typeof v === 'bigint' ? Number(v) : v\n));\n`\n\n // Plugin: stub next/* imports (not available outside Next.js app context)\n const stubNextPlugin = {\n name: 'stub-next',\n setup(build: any) {\n build.onResolve({ filter: /^next($|\\/)/ }, () => ({\n path: 'next-stub',\n namespace: 'next-stub',\n }))\n build.onLoad({ filter: /.*/, namespace: 'next-stub' }, () => ({\n contents: [\n 'const p = new Proxy(function(){}, {',\n ' get(_, k) { return k === \"__esModule\" ? true : k === \"default\" ? p : p; },',\n ' apply() { return p; },',\n ' construct() { return p; },',\n '});',\n 'export default p;',\n 'export const NextRequest = p, NextResponse = p, headers = p, cookies = p;',\n 'export const redirect = p, notFound = p, useRouter = p, usePathname = p;',\n 'export const useSearchParams = p, permanentRedirect = p, revalidatePath = p;',\n ].join('\\n'),\n loader: 'js' as const,\n }))\n },\n }\n\n // Plugin: resolve workspace imports, aliases, and subpath imports\n const resolveProjectImportsPlugin = {\n name: 'resolve-project-imports',\n setup(build: any) {\n // @open-mercato/<pkg>/<path> \u2192 packageRoot/src/<path>.ts\n build.onResolve({ filter: /^@open-mercato\\// }, (args: any) => {\n const withoutScope = args.path.slice('@open-mercato/'.length)\n const slashIdx = withoutScope.indexOf('/')\n const pkg = slashIdx === -1 ? withoutScope : withoutScope.slice(0, slashIdx)\n const rest = slashIdx === -1 ? '' : withoutScope.slice(slashIdx + 1)\n const packageName = `@open-mercato/${pkg}`\n const packageRoot = resolver.getPackageRoot(packageName)\n\n const base = rest\n ? path.join(packageRoot, 'src', rest)\n : path.join(packageRoot, 'src', 'index')\n\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/.mercato/* \u2192 app/.mercato/* (tsconfig paths)\n build.onResolve({ filter: /^@\\/\\.mercato\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length) // '.mercato/generated/...'\n const base = path.join(appDir, rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx', '']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/* \u2192 app/src/* (tsconfig paths)\n build.onResolve({ filter: /^@\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length)\n const base = path.join(appDir, 'src', rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // #generated/* \u2192 core package generated/* (Node subpath imports)\n build.onResolve({ filter: /^#generated\\// }, (args: any) => {\n const rest = args.path.slice('#generated/'.length)\n const base = path.join(coreGeneratedRoot, rest)\n for (const ext of ['.ts', '/index.ts']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n },\n }\n\n // Plugin: externalize installed packages, stub missing ones\n const nodeBuiltins = new Set([\n 'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',\n 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2',\n 'https', 'module', 'net', 'os', 'path', 'perf_hooks', 'process',\n 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder',\n 'sys', 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'wasi',\n 'worker_threads', 'zlib', 'async_hooks', 'diagnostics_channel', 'inspector',\n 'trace_events',\n ])\n const externalNonWorkspacePlugin = {\n name: 'external-non-workspace',\n setup(build: any) {\n build.onResolve({ filter: /^[^./]/ }, (args: any) => {\n if (path.isAbsolute(args.path)) return undefined\n if (args.path.startsWith('@open-mercato/')) return undefined\n if (args.path.startsWith('@/')) return undefined\n if (args.path.startsWith('#generated/')) return undefined\n if (args.path.startsWith('next')) return undefined\n // Let esbuild handle Node builtins (with or without node: prefix)\n if (args.path.startsWith('node:')) return undefined\n const topLevel = args.path.split('/')[0]\n if (nodeBuiltins.has(topLevel)) return undefined\n\n // Extract package name (handle scoped packages like @mikro-orm/core)\n const pkgName = args.path.startsWith('@')\n ? args.path.split('/').slice(0, 2).join('/')\n : topLevel\n const pkgDir = path.join(rootDir, 'node_modules', pkgName)\n if (fs.existsSync(pkgDir)) return { external: true }\n\n // Package not installed \u2014 provide CJS stub (allows any named import)\n return { path: args.path, namespace: 'missing-pkg' }\n })\n build.onLoad({ filter: /.*/, namespace: 'missing-pkg' }, () => ({\n contents: 'var h={get:(_,k)=>k===\"__esModule\"?true:p};var p=new Proxy(function(){return p},{get:h.get,apply:()=>p,construct:()=>p});module.exports=p;',\n loader: 'js' as const,\n }))\n },\n }\n\n try {\n await esbuild.build({\n stdin: {\n contents: entryScript,\n resolveDir: appDir,\n sourcefile: 'openapi-entry.ts',\n loader: 'ts',\n },\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'node18',\n outfile: bundlePath,\n write: true,\n ...(tsconfigPath ? { tsconfig: tsconfigPath } : {}),\n logLevel: 'silent',\n jsx: 'automatic',\n plugins: [stubNextPlugin, resolveProjectImportsPlugin, externalNonWorkspacePlugin],\n })\n\n const stdout = execFileSync(process.execPath, [bundlePath], {\n timeout: 60_000,\n maxBuffer: 20 * 1024 * 1024,\n encoding: 'utf-8',\n env: { ...process.env, NODE_NO_WARNINGS: '1' },\n cwd: rootDir,\n })\n\n const lastLine = stdout.trim().split('\\n').pop()!\n const doc = JSON.parse(lastLine) as Record<string, any>\n\n if (!quiet) {\n const pathCount = Object.keys(doc.paths || {}).length\n const withBody = Object.values(doc.paths || {}).reduce((n: number, methods: any) => {\n for (const m of Object.values(methods)) {\n if ((m as any)?.requestBody) n++\n }\n return n\n }, 0)\n console.log(`[OpenAPI] Bundle approach: ${pathCount} paths, ${withBody} with requestBody schemas`)\n }\n\n return doc\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err)\n const stderr = (err as any)?.stderr\n const esbuildErrors = (err as any)?.errors as Array<{ text: string; location?: { file: string } }> | undefined\n if (!quiet) {\n console.log(`[OpenAPI] Bundle approach failed, will use static fallback: ${errMsg.split('\\n')[0]}`)\n if (esbuildErrors?.length) {\n const unique = new Map<string, string>()\n for (const e of esbuildErrors) {\n const key = e.text\n if (!unique.has(key)) unique.set(key, e.location?.file ?? '')\n }\n for (const [text, file] of [...unique.entries()].slice(0, 10)) {\n console.log(`[OpenAPI] ${text}${file ? ` (${path.basename(file)})` : ''}`)\n }\n if (unique.size > 10) console.log(`[OpenAPI] ... and ${unique.size - 10} more`)\n }\n if (stderr) {\n for (const line of String(stderr).trim().split('\\n').slice(0, 3)) {\n console.log(`[OpenAPI] ${line}`)\n }\n }\n }\n return null\n } finally {\n // Shut down esbuild's persistent Go service so it does not deadlock at\n // process exit when a plugin request is still in flight.\n try { await esbuild.stop() } catch {}\n // Clean up old files from previous tsx-based approach\n for (const file of ['_openapi-register.mjs', '_openapi-loader.mjs', '_next-stub.cjs']) {\n try { fs.unlinkSync(path.join(cacheDir, file)) } catch {}\n }\n }\n}\n\n/**\n * Build OpenAPI paths from discovered routes.\n * Extracts basic operation info from route files statically.\n */\nfunction buildOpenApiPaths(routes: ApiRouteInfo[]): Record<string, any> {\n const paths: Record<string, any> = {}\n\n for (const route of routes) {\n const pathEntry: Record<string, any> = {}\n\n // Try to extract OpenAPI specs from source\n const openApiSpec = parseOpenApiFromSource(route.path)\n\n for (const method of route.methods) {\n const methodLower = method.toLowerCase()\n const spec = openApiSpec?.[method]\n\n // Generate a default operationId if not found\n const pathSegments = route.openApiPath\n .replace(/^\\/api\\//, '')\n .replace(/\\{[^}]+\\}/g, 'by_id')\n .split('/')\n .filter(Boolean)\n .join('_')\n const defaultOperationId = `${methodLower}_${pathSegments}`\n\n pathEntry[methodLower] = {\n operationId: spec?.operationId || defaultOperationId,\n summary: spec?.summary || `${method} ${route.openApiPath}`,\n description: spec?.description || `${method} operation for ${route.openApiPath}`,\n tags: spec?.tags || [route.openApiPath.split('/')[2] || 'api'],\n responses: {\n '200': {\n description: 'Successful response',\n },\n },\n }\n }\n\n if (Object.keys(pathEntry).length > 0) {\n paths[route.openApiPath] = pathEntry\n }\n }\n\n return paths\n}\n\n/**\n * Generate the OpenAPI JSON file.\n */\nexport async function generateOpenApi(options: GenerateOpenApiOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'openapi.generated.json')\n const checksumFile = path.join(outputDir, 'openapi.generated.checksum')\n\n // Ensure output directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n // Find all API routes\n const routes = await findApiRoutes(resolver)\n\n if (!quiet) {\n console.log(`[OpenAPI] Found ${routes.length} API route files`)\n }\n\n // Determine project root (cli package is at packages/cli/src/lib/generators/)\n // Try esbuild bundle approach first \u2014 produces full requestBody/response schemas\n let doc: Record<string, any> | null = await generateOpenApiViaBundle(routes, resolver, quiet)\n\n // Fallback to static regex approach (extracts operationId/summary/tags but no schemas)\n if (!doc) {\n if (!quiet) {\n console.log('[OpenAPI] Falling back to static regex approach')\n }\n const paths = buildOpenApiPaths(routes)\n doc = {\n openapi: '3.1.0',\n info: {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n },\n servers: [\n { url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' },\n ],\n paths,\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: 'Send an `Authorization: Bearer <token>` header with a valid API token.',\n },\n },\n },\n }\n }\n\n const output = JSON.stringify(doc, null, 2)\n const checksum = calculateChecksum(output)\n\n // Check if unchanged\n const existingChecksums = readChecksumRecord(checksumFile)\n if (existingChecksums && existingChecksums.content === checksum && fs.existsSync(outFile)) {\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (unchanged): ${outFile}`)\n }\n return result\n }\n\n // Write the file\n fs.writeFileSync(outFile, output)\n writeChecksumRecord(checksumFile, { content: checksum, structure: '' })\n\n result.filesWritten.push(outFile)\n\n if (!quiet) {\n logGenerationResult(outFile, true)\n const pathCount = Object.keys(doc.paths || {}).length\n console.log(`[OpenAPI] Generated ${pathCount} API paths`)\n }\n\n return result\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * OpenAPI JSON Generator\n *\n * Generates a static openapi.generated.json file at build time.\n * This allows CLI tools (like MCP dev server) to access API endpoint\n * information without requiring a running Next.js app.\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ModuleEntry, PackageResolver } from '../resolver'\nimport { isModuleRouteFile } from './scanner'\nimport {\n calculateChecksum,\n calculateStructureChecksum,\n readChecksumRecord,\n writeChecksumRecord,\n logGenerationResult,\n type GeneratorResult,\n createGeneratorResult,\n} from '../utils'\n\nexport interface GenerateOpenApiOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\ninterface ApiRouteInfo {\n path: string\n methods: HttpMethod[]\n openApiPath: string\n}\n\ninterface OpenApiInputManifest {\n version: 1\n inputPaths: string[]\n}\n\ninterface OpenApiInputContext {\n enabled: ModuleEntry[]\n apiRoots: string[]\n moduleIdentity: Array<{\n id: string\n from: string\n appBase: string\n pkgBase: string\n }>\n}\n\ninterface OpenApiBundleResult {\n doc: Record<string, any> | null\n inputPaths: string[]\n}\n\nconst OPENAPI_INPUT_MANIFEST_VERSION = 1\n\nfunction createOpenApiInputContext(resolver: PackageResolver): OpenApiInputContext {\n const enabled = resolver.loadEnabledModules()\n const apiRoots: string[] = []\n const moduleIdentity = enabled.map((entry) => {\n const roots = resolver.getModulePaths(entry)\n apiRoots.push(path.join(roots.appBase, 'api'), path.join(roots.pkgBase, 'api'))\n return {\n id: entry.id,\n from: entry.from ?? '@open-mercato/core',\n appBase: path.resolve(roots.appBase),\n pkgBase: path.resolve(roots.pkgBase),\n }\n })\n return { enabled, apiRoots, moduleIdentity }\n}\n\nfunction readOpenApiInputManifest(filePath: string): OpenApiInputManifest | null {\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Partial<OpenApiInputManifest>\n if (\n parsed.version !== OPENAPI_INPUT_MANIFEST_VERSION\n || !Array.isArray(parsed.inputPaths)\n || parsed.inputPaths.some((entry) => typeof entry !== 'string')\n ) {\n return null\n }\n return {\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n inputPaths: Array.from(new Set(parsed.inputPaths.map((entry) => path.resolve(entry))))\n .sort((a, b) => a.localeCompare(b)),\n }\n } catch {\n return null\n }\n}\n\nfunction trackedPathRecord(filePath: string): string {\n try {\n const stat = fs.statSync(filePath)\n if (stat.isFile()) {\n return `${path.resolve(filePath)}:${calculateChecksum(fs.readFileSync(filePath, 'utf8'))}`\n }\n return `${path.resolve(filePath)}:${stat.size}:${stat.mtimeMs}`\n } catch {\n return `missing:${path.resolve(filePath)}`\n }\n}\n\nfunction calculateOpenApiInputFingerprint(\n resolver: PackageResolver,\n context: OpenApiInputContext,\n manifest: OpenApiInputManifest,\n): string {\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const configPaths = [\n resolver.getModulesConfigPath(),\n path.join(rootDir, 'package.json'),\n path.join(rootDir, 'yarn.lock'),\n path.join(rootDir, 'package-lock.json'),\n path.join(rootDir, 'pnpm-lock.yaml'),\n path.join(rootDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(appDir, 'package.json'),\n path.join(appDir, 'tsconfig.json'),\n ]\n const trackedRecords = [...manifest.inputPaths, ...configPaths]\n .map(trackedPathRecord)\n .sort((a, b) => a.localeCompare(b))\n return calculateChecksum(JSON.stringify({\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n modules: context.moduleIdentity,\n routeStructure: calculateStructureChecksum(context.apiRoots),\n trackedRecords,\n environment: {\n node: process.version,\n nodeEnv: process.env.NODE_ENV ?? '',\n publicAppUrl: process.env.NEXT_PUBLIC_APP_URL ?? '',\n },\n }))\n}\n\nfunction resolveExistingPath(paths: string[]): string | null {\n for (const candidate of paths) {\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\n/**\n * Find all API route files and extract their OpenAPI specs.\n */\nasync function findApiRoutes(\n resolver: PackageResolver,\n enabled: ModuleEntry[],\n): Promise<ApiRouteInfo[]> {\n const routes: ApiRouteInfo[] = []\n\n for (const entry of enabled) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n\n const apiApp = path.join(roots.appBase, 'api')\n const apiPkg = path.join(roots.pkgBase, 'api')\n\n // Scan route files\n const routeFiles: Array<{ relativePath: string; fullPath: string }> = []\n\n const walkDir = (dir: string, rel: string[] = []) => {\n if (!fs.existsSync(dir)) return\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n if (e.isDirectory()) {\n if (e.name === '__tests__' || e.name === '__mocks__') continue\n walkDir(path.join(dir, e.name), [...rel, e.name])\n } else if (e.isFile() && isModuleRouteFile(e.name)) {\n routeFiles.push({\n relativePath: [...rel].join('/'),\n fullPath: path.join(dir, e.name),\n })\n }\n }\n }\n\n // Scan package first, then app (app overrides)\n if (fs.existsSync(apiPkg)) walkDir(apiPkg)\n if (fs.existsSync(apiApp)) walkDir(apiApp)\n\n // Process unique routes (later app files overwrite earlier package files)\n const filesByRelativePath = new Map<string, string>()\n for (const { relativePath, fullPath } of routeFiles) {\n filesByRelativePath.set(relativePath, fullPath)\n }\n\n for (const [relativePath, fullPath] of filesByRelativePath) {\n\n // Build API path\n const routeSegs = relativePath ? relativePath.split('/') : []\n const apiPath = `/api/${modId}${routeSegs.length ? '/' + routeSegs.join('/') : ''}`\n // Convert [param] to {param} for OpenAPI format\n .replace(/\\[([^\\]]+)\\]/g, '{$1}')\n\n routes.push({\n path: fullPath,\n methods: await detectMethods(fullPath),\n openApiPath: apiPath,\n })\n }\n }\n\n return routes\n}\n\n/**\n * Detect which HTTP methods are exported from a route file.\n */\nasync function detectMethods(filePath: string): Promise<HttpMethod[]> {\n const methods: HttpMethod[] = []\n const content = fs.readFileSync(filePath, 'utf-8')\n\n const methodPatterns: HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n for (const method of methodPatterns) {\n // Check for export { GET }, export const GET, export async function GET\n const patterns = [\n new RegExp(`export\\\\s+(const|async\\\\s+function|function)\\\\s+${method}\\\\b`),\n new RegExp(`export\\\\s*\\\\{[^}]*\\\\b${method}\\\\b[^}]*\\\\}`),\n ]\n if (patterns.some((p) => p.test(content))) {\n methods.push(method)\n }\n }\n\n return methods\n}\n\n/**\n * Parse openApi export from route file source code statically.\n * This extracts basic operation info without needing to compile the file.\n */\nfunction parseOpenApiFromSource(filePath: string): Record<string, any> | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n\n // Check if file exports openApi\n if (!content.includes('export const openApi') && !content.includes('export { openApi')) {\n return null\n }\n\n // Extract operationId, summary, description from the source\n const result: Record<string, any> = {}\n const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n\n for (const method of methods) {\n // Look for method specs in the openApi object\n // Pattern: GET: { operationId: '...', summary: '...', ... }\n const methodPattern = new RegExp(\n `${method}\\\\s*:\\\\s*\\\\{([^}]+(?:\\\\{[^}]*\\\\}[^}]*)*)\\\\}`,\n 's'\n )\n const methodMatch = content.match(methodPattern)\n\n if (methodMatch) {\n const methodContent = methodMatch[1]\n const spec: Record<string, any> = {}\n\n // Extract operationId\n const opIdMatch = methodContent.match(/operationId\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (opIdMatch) spec.operationId = opIdMatch[1]\n\n // Extract summary\n const summaryMatch = methodContent.match(/summary\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (summaryMatch) spec.summary = summaryMatch[1]\n\n // Extract description\n const descMatch = methodContent.match(/description\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descMatch) spec.description = descMatch[1]\n\n // Extract tags\n const tagsMatch = methodContent.match(/tags\\s*:\\s*\\[([^\\]]*)\\]/)\n if (tagsMatch) {\n const tagsContent = tagsMatch[1]\n const tags = tagsContent.match(/['\"]([^'\"]+)['\"]/g)\n if (tags) {\n spec.tags = tags.map(t => t.replace(/['\"]/g, ''))\n }\n }\n\n if (Object.keys(spec).length > 0) {\n result[method] = spec\n }\n }\n }\n\n return Object.keys(result).length > 0 ? result : null\n } catch {\n return null\n }\n}\n\n/**\n * Generate a complete OpenAPI document by bundling route files with esbuild\n * and executing the bundle to call buildOpenApiDocument from @open-mercato/shared.\n *\n * esbuild compiles TypeScript with legacy decorator support (reads experimentalDecorators\n * from tsconfig.json), avoiding the TC39 decorator mismatch that breaks tsx-based imports.\n * External packages (zod, mikro-orm, etc.) are resolved from node_modules at runtime.\n */\nasync function generateOpenApiViaBundle(\n routes: ApiRouteInfo[],\n resolver: PackageResolver,\n quiet: boolean\n): Promise<OpenApiBundleResult> {\n let esbuild: typeof import('esbuild')\n try {\n esbuild = await import('esbuild')\n } catch {\n if (!quiet) console.log('[OpenAPI] esbuild not available, skipping bundle approach')\n return { doc: null, inputPaths: [] }\n }\n\n const { execFileSync } = await import('node:child_process')\n\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const sharedPackageRoot = resolver.getPackageRoot('@open-mercato/shared')\n const corePackageRoot = resolver.getPackageRoot('@open-mercato/core')\n const tsconfigPath = resolveExistingPath([\n path.join(appDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(rootDir, 'tsconfig.json'),\n ])\n const generatorPath = path.join(sharedPackageRoot, 'src', 'lib', 'openapi', 'generator.ts')\n const coreGeneratedRoot = path.join(corePackageRoot, 'generated')\n\n if (!fs.existsSync(generatorPath)) {\n if (!quiet) {\n console.log(`[OpenAPI] Generator source not found at ${generatorPath}, skipping bundle approach`)\n }\n return { doc: null, inputPaths: [] }\n }\n\n const cacheDir = path.join(rootDir, 'node_modules', '.cache')\n if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true })\n\n const bundlePath = path.join(cacheDir, '_openapi-bundle.mjs')\n let inputPaths: string[] = []\n\n // Build the entry script that imports all routes and calls buildOpenApiDocument\n const importLines: string[] = [\n `import { buildOpenApiDocument } from ${JSON.stringify(generatorPath)};`,\n ]\n const routeMapLines: string[] = []\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i]\n importLines.push(`import * as R${i} from ${JSON.stringify(route.path)};`)\n // Use [param] format so normalizePath in buildOpenApiDocument extracts path params\n const bracketPath = route.openApiPath.replace(/\\{([^}]+)\\}/g, '[$1]')\n routeMapLines.push(` [${JSON.stringify(bracketPath)}, R${i}],`)\n }\n\n const entryScript = `${importLines.join('\\n')}\n\nconst routeEntries = [\n${routeMapLines.join('\\n')}\n];\n\nconst modules = new Map();\nfor (const [apiPath, mod] of routeEntries) {\n const moduleId = apiPath.replace(/^\\\\/api\\\\//, '').split('/')[0];\n if (!modules.has(moduleId)) modules.set(moduleId, { id: moduleId, apis: [] });\n modules.get(moduleId).apis.push({\n path: apiPath,\n handlers: mod,\n metadata: mod.metadata,\n });\n}\n\nconst doc = buildOpenApiDocument([...modules.values()], {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n servers: [{ url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' }],\n});\n\n// Deep-clone to break shared object references before serializing.\n// The zodToJsonSchema memo cache returns the same object instance for\n// fields like currencyCode that appear on both parent and child schemas.\n// A naive WeakSet-based circular-ref guard would drop the second occurrence,\n// causing properties to vanish from the generated spec (while the field\n// still appears in the 'required' array, since those are plain strings).\nconst deepClone = (v, ancestors = []) => {\n if (v === null || typeof v !== 'object') return v;\n if (typeof v === 'bigint') return Number(v);\n if (typeof v === 'function') return undefined;\n if (ancestors.includes(v)) return undefined; // true circular ref\n const next = [...ancestors, v];\n if (Array.isArray(v)) return v.map((item) => deepClone(item, next));\n const out = {};\n for (const [k, val] of Object.entries(v)) {\n const cloned = deepClone(val, next);\n if (cloned !== undefined) out[k] = cloned;\n }\n return out;\n};\nprocess.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>\n typeof v === 'bigint' ? Number(v) : v\n));\n`\n\n // Plugin: stub next/* imports (not available outside Next.js app context)\n const stubNextPlugin = {\n name: 'stub-next',\n setup(build: any) {\n build.onResolve({ filter: /^next($|\\/)/ }, () => ({\n path: 'next-stub',\n namespace: 'next-stub',\n }))\n build.onLoad({ filter: /.*/, namespace: 'next-stub' }, () => ({\n contents: [\n 'const p = new Proxy(function(){}, {',\n ' get(_, k) { return k === \"__esModule\" ? true : k === \"default\" ? p : p; },',\n ' apply() { return p; },',\n ' construct() { return p; },',\n '});',\n 'export default p;',\n 'export const NextRequest = p, NextResponse = p, headers = p, cookies = p;',\n 'export const redirect = p, notFound = p, useRouter = p, usePathname = p;',\n 'export const useSearchParams = p, permanentRedirect = p, revalidatePath = p;',\n ].join('\\n'),\n loader: 'js' as const,\n }))\n },\n }\n\n // Plugin: resolve workspace imports, aliases, and subpath imports\n const resolveProjectImportsPlugin = {\n name: 'resolve-project-imports',\n setup(build: any) {\n // @open-mercato/<pkg>/<path> \u2192 packageRoot/src/<path>.ts\n build.onResolve({ filter: /^@open-mercato\\// }, (args: any) => {\n const withoutScope = args.path.slice('@open-mercato/'.length)\n const slashIdx = withoutScope.indexOf('/')\n const pkg = slashIdx === -1 ? withoutScope : withoutScope.slice(0, slashIdx)\n const rest = slashIdx === -1 ? '' : withoutScope.slice(slashIdx + 1)\n const packageName = `@open-mercato/${pkg}`\n const packageRoot = resolver.getPackageRoot(packageName)\n\n const base = rest\n ? path.join(packageRoot, 'src', rest)\n : path.join(packageRoot, 'src', 'index')\n\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/.mercato/* \u2192 app/.mercato/* (tsconfig paths)\n build.onResolve({ filter: /^@\\/\\.mercato\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length) // '.mercato/generated/...'\n const base = path.join(appDir, rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx', '']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/* \u2192 app/src/* (tsconfig paths)\n build.onResolve({ filter: /^@\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length)\n const base = path.join(appDir, 'src', rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // #generated/* \u2192 core package generated/* (Node subpath imports)\n build.onResolve({ filter: /^#generated\\// }, (args: any) => {\n const rest = args.path.slice('#generated/'.length)\n const base = path.join(coreGeneratedRoot, rest)\n for (const ext of ['.ts', '/index.ts']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n },\n }\n\n // Plugin: externalize installed packages, stub missing ones\n const nodeBuiltins = new Set([\n 'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',\n 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2',\n 'https', 'module', 'net', 'os', 'path', 'perf_hooks', 'process',\n 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder',\n 'sys', 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'wasi',\n 'worker_threads', 'zlib', 'async_hooks', 'diagnostics_channel', 'inspector',\n 'trace_events',\n ])\n const externalNonWorkspacePlugin = {\n name: 'external-non-workspace',\n setup(build: any) {\n build.onResolve({ filter: /^[^./]/ }, (args: any) => {\n if (path.isAbsolute(args.path)) return undefined\n if (args.path.startsWith('@open-mercato/')) return undefined\n if (args.path.startsWith('@/')) return undefined\n if (args.path.startsWith('#generated/')) return undefined\n if (args.path.startsWith('next')) return undefined\n // Let esbuild handle Node builtins (with or without node: prefix)\n if (args.path.startsWith('node:')) return undefined\n const topLevel = args.path.split('/')[0]\n if (nodeBuiltins.has(topLevel)) return undefined\n\n // Extract package name (handle scoped packages like @mikro-orm/core)\n const pkgName = args.path.startsWith('@')\n ? args.path.split('/').slice(0, 2).join('/')\n : topLevel\n const pkgDir = path.join(rootDir, 'node_modules', pkgName)\n if (fs.existsSync(pkgDir)) return { external: true }\n\n // Package not installed \u2014 provide CJS stub (allows any named import)\n return { path: args.path, namespace: 'missing-pkg' }\n })\n build.onLoad({ filter: /.*/, namespace: 'missing-pkg' }, () => ({\n contents: 'var h={get:(_,k)=>k===\"__esModule\"?true:p};var p=new Proxy(function(){return p},{get:h.get,apply:()=>p,construct:()=>p});module.exports=p;',\n loader: 'js' as const,\n }))\n },\n }\n\n try {\n const buildResult = await esbuild.build({\n stdin: {\n contents: entryScript,\n resolveDir: appDir,\n sourcefile: 'openapi-entry.ts',\n loader: 'ts',\n },\n bundle: true,\n metafile: true,\n absWorkingDir: rootDir,\n format: 'esm',\n platform: 'node',\n target: 'node18',\n outfile: bundlePath,\n write: true,\n ...(tsconfigPath ? { tsconfig: tsconfigPath } : {}),\n logLevel: 'silent',\n jsx: 'automatic',\n plugins: [stubNextPlugin, resolveProjectImportsPlugin, externalNonWorkspacePlugin],\n })\n\n inputPaths = Object.keys(buildResult.metafile?.inputs ?? {})\n .filter((inputPath) => !inputPath.startsWith('<'))\n .map((inputPath) => path.resolve(rootDir, inputPath))\n .filter((inputPath) => fs.existsSync(inputPath))\n .sort((a, b) => a.localeCompare(b))\n\n const stdout = execFileSync(process.execPath, [bundlePath], {\n timeout: 60_000,\n maxBuffer: 20 * 1024 * 1024,\n encoding: 'utf-8',\n env: { ...process.env, NODE_NO_WARNINGS: '1' },\n cwd: rootDir,\n })\n\n const lastLine = stdout.trim().split('\\n').pop()!\n const doc = JSON.parse(lastLine) as Record<string, any>\n\n if (!quiet) {\n const pathCount = Object.keys(doc.paths || {}).length\n const withBody = Object.values(doc.paths || {}).reduce((n: number, methods: any) => {\n for (const m of Object.values(methods)) {\n if ((m as any)?.requestBody) n++\n }\n return n\n }, 0)\n console.log(`[OpenAPI] Bundle approach: ${pathCount} paths, ${withBody} with requestBody schemas`)\n }\n\n return { doc, inputPaths }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err)\n const stderr = (err as any)?.stderr\n const esbuildErrors = (err as any)?.errors as Array<{ text: string; location?: { file: string } }> | undefined\n if (!quiet) {\n console.log(`[OpenAPI] Bundle approach failed, will use static fallback: ${errMsg.split('\\n')[0]}`)\n if (esbuildErrors?.length) {\n const unique = new Map<string, string>()\n for (const e of esbuildErrors) {\n const key = e.text\n if (!unique.has(key)) unique.set(key, e.location?.file ?? '')\n }\n for (const [text, file] of [...unique.entries()].slice(0, 10)) {\n console.log(`[OpenAPI] ${text}${file ? ` (${path.basename(file)})` : ''}`)\n }\n if (unique.size > 10) console.log(`[OpenAPI] ... and ${unique.size - 10} more`)\n }\n if (stderr) {\n for (const line of String(stderr).trim().split('\\n').slice(0, 3)) {\n console.log(`[OpenAPI] ${line}`)\n }\n }\n }\n return { doc: null, inputPaths }\n } finally {\n // Shut down esbuild's persistent Go service so it does not deadlock at\n // process exit when a plugin request is still in flight.\n try { await esbuild.stop() } catch {}\n // Clean up old files from previous tsx-based approach\n for (const file of ['_openapi-register.mjs', '_openapi-loader.mjs', '_next-stub.cjs']) {\n try { fs.unlinkSync(path.join(cacheDir, file)) } catch {}\n }\n }\n}\n\n/**\n * Build OpenAPI paths from discovered routes.\n * Extracts basic operation info from route files statically.\n */\nfunction buildOpenApiPaths(routes: ApiRouteInfo[]): Record<string, any> {\n const paths: Record<string, any> = {}\n\n for (const route of routes) {\n const pathEntry: Record<string, any> = {}\n\n // Try to extract OpenAPI specs from source\n const openApiSpec = parseOpenApiFromSource(route.path)\n\n for (const method of route.methods) {\n const methodLower = method.toLowerCase()\n const spec = openApiSpec?.[method]\n\n // Generate a default operationId if not found\n const pathSegments = route.openApiPath\n .replace(/^\\/api\\//, '')\n .replace(/\\{[^}]+\\}/g, 'by_id')\n .split('/')\n .filter(Boolean)\n .join('_')\n const defaultOperationId = `${methodLower}_${pathSegments}`\n\n pathEntry[methodLower] = {\n operationId: spec?.operationId || defaultOperationId,\n summary: spec?.summary || `${method} ${route.openApiPath}`,\n description: spec?.description || `${method} operation for ${route.openApiPath}`,\n tags: spec?.tags || [route.openApiPath.split('/')[2] || 'api'],\n responses: {\n '200': {\n description: 'Successful response',\n },\n },\n }\n }\n\n if (Object.keys(pathEntry).length > 0) {\n paths[route.openApiPath] = pathEntry\n }\n }\n\n return paths\n}\n\n/**\n * Generate the OpenAPI JSON file.\n */\nexport async function generateOpenApi(options: GenerateOpenApiOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'openapi.generated.json')\n const checksumFile = path.join(outputDir, 'openapi.generated.checksum')\n const inputManifestFile = path.join(outputDir, 'openapi.generated.inputs.json')\n\n // Ensure output directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n const inputContext = createOpenApiInputContext(resolver)\n const existingChecksums = readChecksumRecord(checksumFile)\n const existingManifest = readOpenApiInputManifest(inputManifestFile)\n\n if (\n existingChecksums?.structure\n && existingManifest\n && fs.existsSync(outFile)\n && calculateChecksum(fs.readFileSync(outFile, 'utf8')) === existingChecksums.content\n && calculateOpenApiInputFingerprint(resolver, inputContext, existingManifest) === existingChecksums.structure\n ) {\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (inputs unchanged): ${outFile}`)\n }\n return result\n }\n\n // Find all API routes\n const routes = await findApiRoutes(resolver, inputContext.enabled)\n\n if (!quiet) {\n console.log(`[OpenAPI] Found ${routes.length} API route files`)\n }\n\n // Determine project root (cli package is at packages/cli/src/lib/generators/)\n // Try esbuild bundle approach first \u2014 produces full requestBody/response schemas\n const bundleResult = await generateOpenApiViaBundle(routes, resolver, quiet)\n let doc: Record<string, any> | null = bundleResult.doc\n\n // Fallback to static regex approach (extracts operationId/summary/tags but no schemas)\n if (!doc) {\n if (!quiet) {\n console.log('[OpenAPI] Falling back to static regex approach')\n }\n const paths = buildOpenApiPaths(routes)\n doc = {\n openapi: '3.1.0',\n info: {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n },\n servers: [\n { url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' },\n ],\n paths,\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: 'Send an `Authorization: Bearer <token>` header with a valid API token.',\n },\n },\n },\n }\n }\n\n const output = JSON.stringify(doc, null, 2)\n const checksum = calculateChecksum(output)\n let structureChecksum = ''\n\n if (bundleResult.doc && bundleResult.inputPaths.length > 0) {\n const manifest: OpenApiInputManifest = {\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n inputPaths: Array.from(new Set(bundleResult.inputPaths)).sort((a, b) => a.localeCompare(b)),\n }\n fs.writeFileSync(inputManifestFile, `${JSON.stringify(manifest, null, 2)}\\n`)\n structureChecksum = calculateOpenApiInputFingerprint(resolver, inputContext, manifest)\n } else {\n try { fs.unlinkSync(inputManifestFile) } catch {}\n }\n\n // Check if unchanged\n const existingOutputMatches = fs.existsSync(outFile)\n && calculateChecksum(fs.readFileSync(outFile, 'utf8')) === checksum\n if (existingChecksums && existingChecksums.content === checksum && existingOutputMatches) {\n if (existingChecksums.structure !== structureChecksum) {\n writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum })\n }\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (unchanged): ${outFile}`)\n }\n return result\n }\n\n // Write the file\n fs.writeFileSync(outFile, output)\n writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum })\n\n result.filesWritten.push(outFile)\n\n if (!quiet) {\n logGenerationResult(outFile, true)\n const pathCount = Object.keys(doc.paths || {}).length\n console.log(`[OpenAPI] Generated ${pathCount} API paths`)\n }\n\n return result\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -10,12 +10,13 @@ function startInProcessGenerateWatcher(options) {
|
|
|
10
10
|
const quiet = options.quiet === true;
|
|
11
11
|
const pollMs = resolvePollMs(options.pollMs);
|
|
12
12
|
const skipInitial = options.skipInitial === true;
|
|
13
|
-
const { computeStructureChecksum, runGenerators } = options;
|
|
13
|
+
const { changeSignal, computeStructureChecksum, runGenerators } = options;
|
|
14
14
|
let stopping = false;
|
|
15
15
|
let pollTimer = null;
|
|
16
16
|
let running = false;
|
|
17
17
|
let pendingReason = null;
|
|
18
18
|
let previousChecksum = "";
|
|
19
|
+
let observedChangeVersion = -1;
|
|
19
20
|
let doneResolve = null;
|
|
20
21
|
const done = new Promise((resolve) => {
|
|
21
22
|
doneResolve = resolve;
|
|
@@ -52,7 +53,13 @@ function startInProcessGenerateWatcher(options) {
|
|
|
52
53
|
void (async () => {
|
|
53
54
|
if (stopping) return;
|
|
54
55
|
try {
|
|
56
|
+
const changeVersion = changeSignal?.currentVersion() ?? 0;
|
|
57
|
+
if (changeSignal && !changeSignal.usesPollingFallback() && changeVersion === observedChangeVersion) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
55
60
|
const nextChecksum = await computeStructureChecksum();
|
|
61
|
+
observedChangeVersion = changeVersion;
|
|
62
|
+
await changeSignal?.refresh();
|
|
56
63
|
if (nextChecksum !== previousChecksum) {
|
|
57
64
|
previousChecksum = nextChecksum;
|
|
58
65
|
await runOnce("structure change");
|
|
@@ -69,15 +76,18 @@ function startInProcessGenerateWatcher(options) {
|
|
|
69
76
|
}
|
|
70
77
|
void (async () => {
|
|
71
78
|
try {
|
|
79
|
+
await changeSignal?.refresh();
|
|
80
|
+
const initialChangeVersion = changeSignal?.currentVersion() ?? 0;
|
|
72
81
|
if (!skipInitial) {
|
|
73
82
|
await runOnce("initial");
|
|
74
83
|
}
|
|
75
84
|
previousChecksum = await computeStructureChecksum();
|
|
85
|
+
observedChangeVersion = initialChangeVersion;
|
|
76
86
|
if (!quiet) {
|
|
77
87
|
if (skipInitial) {
|
|
78
88
|
logger.log("[generate:watch] Skipping initial regeneration and watching the current generated state.");
|
|
79
89
|
}
|
|
80
|
-
logger.log(`[generate:watch] Watching structural module files
|
|
90
|
+
logger.log(`[generate:watch] Watching structural module files with a ${pollMs}ms debounce (in-process).`);
|
|
81
91
|
}
|
|
82
92
|
scheduleNext();
|
|
83
93
|
} catch (error) {
|
|
@@ -96,6 +106,7 @@ function startInProcessGenerateWatcher(options) {
|
|
|
96
106
|
clearTimeout(pollTimer);
|
|
97
107
|
pollTimer = null;
|
|
98
108
|
}
|
|
109
|
+
await changeSignal?.close();
|
|
99
110
|
if (doneResolve) {
|
|
100
111
|
doneResolve();
|
|
101
112
|
doneResolve = null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/in-process-generate-watcher.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * In-process generate watcher.\n *\n *
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * In-process generate watcher.\n *\n * Coalesces filesystem events on a configurable interval, then verifies them\n * with the existing structural fingerprint before invoking the generator.\n * If filesystem watching is unavailable, it falls back to fingerprint polling.\n * The polling loop is identical to the legacy standalone watcher; the only\n * difference is that it now runs inside whatever process calls it\n * (typically `mercato server dev`), so the dev runtime no longer needs a\n * sidecar `mercato generate watch` Node process.\n *\n * Contract preserved from the prior standalone watcher:\n * - Default debounce/fallback poll interval 1000 ms (minimum 250 ms).\n * - One initial generator run unless `skipInitial` is true.\n * - Concurrent regeneration requests are coalesced (running + pending).\n * - Generator errors are logged but never crash the watcher.\n * - The polling timer uses `.unref()` so it never blocks process exit.\n */\n\nexport type GenerateWatcherLogger = Pick<Console, 'log' | 'error'>\n\nexport type GenerateWatcherChangeSignal = {\n /** Monotonic event generation. Changes indicate that a checksum may be stale. */\n currentVersion(): number\n /** Refresh filesystem subscriptions after module configuration changes. */\n refresh(): Promise<void> | void\n /** When true, preserve the legacy full-checksum-on-every-poll behavior. */\n usesPollingFallback(): boolean\n /** Close filesystem subscriptions. Idempotent. */\n close(): Promise<void> | void\n}\n\nexport type GenerateWatcherOptions = {\n /**\n * Function that returns the current structural fingerprint of the module\n * tree. The watcher re-runs `runGenerators` whenever this value changes.\n */\n computeStructureChecksum: () => Promise<string> | string\n /** Optional event signal that avoids full checksum work during idle polls. */\n changeSignal?: GenerateWatcherChangeSignal\n /**\n * Function that performs the actual regeneration work. Called once on\n * startup (unless `skipInitial`) and again whenever the checksum changes.\n * The `reason` argument is suitable for logging (`'initial'`,\n * `'structure change'`, `'queued change'`).\n */\n runGenerators: (reason: string) => Promise<void>\n /** Poll interval in milliseconds. Defaults to 1000. Clamped to >= 250. */\n pollMs?: number\n /** Skip the initial regeneration on startup. Defaults to false. */\n skipInitial?: boolean\n /** Suppress informational logs. Errors are always logged. */\n quiet?: boolean\n /** Logger override. Defaults to `console`. */\n logger?: GenerateWatcherLogger\n}\n\nexport type GenerateWatcherHandle = {\n /** Resolves when the watcher loop has stopped (after `close()`). */\n readonly done: Promise<void>\n /** Stop the polling loop and resolve `done`. Idempotent. */\n close(): Promise<void>\n}\n\nconst MIN_POLL_MS = 250\nconst DEFAULT_POLL_MS = 1000\n\nfunction resolvePollMs(value: number | undefined): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULT_POLL_MS\n const numeric = Math.floor(value)\n return numeric >= MIN_POLL_MS ? numeric : DEFAULT_POLL_MS\n}\n\n/**\n * Start an in-process generate watcher. The returned handle exposes a\n * `close()` to stop polling and a `done` promise that resolves once the\n * watcher loop has finished.\n */\nexport function startInProcessGenerateWatcher(\n options: GenerateWatcherOptions,\n): GenerateWatcherHandle {\n const logger = options.logger ?? console\n const quiet = options.quiet === true\n const pollMs = resolvePollMs(options.pollMs)\n const skipInitial = options.skipInitial === true\n const { changeSignal, computeStructureChecksum, runGenerators } = options\n\n let stopping = false\n let pollTimer: ReturnType<typeof setTimeout> | null = null\n let running = false\n let pendingReason: string | null = null\n let previousChecksum = ''\n let observedChangeVersion = -1\n let doneResolve: (() => void) | null = null\n const done = new Promise<void>((resolve) => {\n doneResolve = resolve\n })\n\n async function runOnce(reason: string): Promise<void> {\n if (running) {\n pendingReason = reason\n return\n }\n running = true\n try {\n if (!quiet) {\n logger.log(`[generate:watch] Regenerating (${reason})...`)\n }\n await runGenerators(reason)\n if (!quiet) {\n logger.log('[generate:watch] Generators completed.')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n logger.error(`[generate:watch] Generation failed: ${message}`)\n } finally {\n running = false\n if (pendingReason && !stopping) {\n const queued = pendingReason\n pendingReason = null\n await runOnce(queued)\n }\n }\n }\n\n function scheduleNext(): void {\n if (stopping) return\n pollTimer = setTimeout(() => {\n void (async () => {\n if (stopping) return\n try {\n const changeVersion = changeSignal?.currentVersion() ?? 0\n if (\n changeSignal\n && !changeSignal.usesPollingFallback()\n && changeVersion === observedChangeVersion\n ) {\n return\n }\n const nextChecksum = await computeStructureChecksum()\n observedChangeVersion = changeVersion\n await changeSignal?.refresh()\n if (nextChecksum !== previousChecksum) {\n previousChecksum = nextChecksum\n await runOnce('structure change')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n logger.error(`[generate:watch] Poll cycle failed: ${message}`)\n } finally {\n if (!stopping) scheduleNext()\n }\n })()\n }, pollMs)\n pollTimer.unref?.()\n }\n\n void (async () => {\n try {\n await changeSignal?.refresh()\n const initialChangeVersion = changeSignal?.currentVersion() ?? 0\n if (!skipInitial) {\n await runOnce('initial')\n }\n previousChecksum = await computeStructureChecksum()\n observedChangeVersion = initialChangeVersion\n if (!quiet) {\n if (skipInitial) {\n logger.log('[generate:watch] Skipping initial regeneration and watching the current generated state.')\n }\n logger.log(`[generate:watch] Watching structural module files with a ${pollMs}ms debounce (in-process).`)\n }\n scheduleNext()\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n logger.error(`[generate:watch] Initial setup failed: ${message}`)\n // Even if the initial bootstrap fails, schedule polling so a later\n // checksum recovery still picks up the next change on disk.\n scheduleNext()\n }\n })()\n\n async function close(): Promise<void> {\n if (stopping) {\n await done\n return\n }\n stopping = true\n if (pollTimer) {\n clearTimeout(pollTimer)\n pollTimer = null\n }\n await changeSignal?.close()\n if (doneResolve) {\n doneResolve()\n doneResolve = null\n }\n }\n\n return {\n done,\n close,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAgEA,MAAM,cAAc;AACpB,MAAM,kBAAkB;AAExB,SAAS,cAAc,OAAmC;AACxD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,QAAM,UAAU,KAAK,MAAM,KAAK;AAChC,SAAO,WAAW,cAAc,UAAU;AAC5C;AAOO,SAAS,8BACd,SACuB;AACvB,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,QAAQ,QAAQ,UAAU;AAChC,QAAM,SAAS,cAAc,QAAQ,MAAM;AAC3C,QAAM,cAAc,QAAQ,gBAAgB;AAC5C,QAAM,EAAE,cAAc,0BAA0B,cAAc,IAAI;AAElE,MAAI,WAAW;AACf,MAAI,YAAkD;AACtD,MAAI,UAAU;AACd,MAAI,gBAA+B;AACnC,MAAI,mBAAmB;AACvB,MAAI,wBAAwB;AAC5B,MAAI,cAAmC;AACvC,QAAM,OAAO,IAAI,QAAc,CAAC,YAAY;AAC1C,kBAAc;AAAA,EAChB,CAAC;AAED,iBAAe,QAAQ,QAA+B;AACpD,QAAI,SAAS;AACX,sBAAgB;AAChB;AAAA,IACF;AACA,cAAU;AACV,QAAI;AACF,UAAI,CAAC,OAAO;AACV,eAAO,IAAI,kCAAkC,MAAM,MAAM;AAAA,MAC3D;AACA,YAAM,cAAc,MAAM;AAC1B,UAAI,CAAC,OAAO;AACV,eAAO,IAAI,wCAAwC;AAAA,MACrD;AAAA,IACF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,MAAM,uCAAuC,OAAO,EAAE;AAAA,IAC/D,UAAE;AACA,gBAAU;AACV,UAAI,iBAAiB,CAAC,UAAU;AAC9B,cAAM,SAAS;AACf,wBAAgB;AAChB,cAAM,QAAQ,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,WAAS,eAAqB;AAC5B,QAAI,SAAU;AACd,gBAAY,WAAW,MAAM;AAC3B,YAAM,YAAY;AAChB,YAAI,SAAU;AACd,YAAI;AACF,gBAAM,gBAAgB,cAAc,eAAe,KAAK;AACxD,cACE,gBACG,CAAC,aAAa,oBAAoB,KAClC,kBAAkB,uBACrB;AACA;AAAA,UACF;AACA,gBAAM,eAAe,MAAM,yBAAyB;AACpD,kCAAwB;AACxB,gBAAM,cAAc,QAAQ;AAC5B,cAAI,iBAAiB,kBAAkB;AACrC,+BAAmB;AACnB,kBAAM,QAAQ,kBAAkB;AAAA,UAClC;AAAA,QACF,SAAS,OAAO;AACd,gBAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,iBAAO,MAAM,uCAAuC,OAAO,EAAE;AAAA,QAC/D,UAAE;AACA,cAAI,CAAC,SAAU,cAAa;AAAA,QAC9B;AAAA,MACF,GAAG;AAAA,IACL,GAAG,MAAM;AACT,cAAU,QAAQ;AAAA,EACpB;AAEA,QAAM,YAAY;AAChB,QAAI;AACF,YAAM,cAAc,QAAQ;AAC5B,YAAM,uBAAuB,cAAc,eAAe,KAAK;AAC/D,UAAI,CAAC,aAAa;AAChB,cAAM,QAAQ,SAAS;AAAA,MACzB;AACA,yBAAmB,MAAM,yBAAyB;AAClD,8BAAwB;AACxB,UAAI,CAAC,OAAO;AACV,YAAI,aAAa;AACf,iBAAO,IAAI,0FAA0F;AAAA,QACvG;AACA,eAAO,IAAI,4DAA4D,MAAM,2BAA2B;AAAA,MAC1G;AACA,mBAAa;AAAA,IACf,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,MAAM,0CAA0C,OAAO,EAAE;AAGhE,mBAAa;AAAA,IACf;AAAA,EACF,GAAG;AAEH,iBAAe,QAAuB;AACpC,QAAI,UAAU;AACZ,YAAM;AACN;AAAA,IACF;AACA,eAAW;AACX,QAAI,WAAW;AACb,mBAAa,SAAS;AACtB,kBAAY;AAAA,IACd;AACA,UAAM,cAAc,MAAM;AAC1B,QAAI,aAAa;AACf,kBAAY;AACZ,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|