@open-mercato/shared 0.9.1-develop.7476.1.342138d35e → 0.9.1-develop.7496.1.3346415f94
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 +1 -1
- package/dist/lib/bootstrap/dynamicLoader.js +46 -6
- package/dist/lib/bootstrap/dynamicLoader.js.map +2 -2
- package/dist/lib/bootstrap/next-subpath-resolve-hook-worker.js +6 -0
- package/dist/lib/bootstrap/next-subpath-resolve-hook-worker.js.map +7 -0
- package/dist/lib/bootstrap/next-subpath-resolve-hook.js +62 -0
- package/dist/lib/bootstrap/next-subpath-resolve-hook.js.map +7 -0
- package/dist/lib/crud/ids.js +13 -1
- package/dist/lib/crud/ids.js.map +2 -2
- package/dist/lib/openapi/generator.js +84 -67
- package/dist/lib/openapi/generator.js.map +2 -2
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/modules/registry.js.map +2 -2
- package/package.json +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.appDi.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.appModuleOverrides.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.cacheRecovery.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.commandInterceptors.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.externalSubpath.test.ts +141 -0
- package/src/lib/bootstrap/__tests__/dynamicLoader.tsconfig.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/next-subpath-resolve-hook.test.ts +174 -0
- package/src/lib/bootstrap/dynamicLoader.ts +63 -5
- package/src/lib/bootstrap/next-subpath-resolve-hook-worker.ts +3 -0
- package/src/lib/bootstrap/next-subpath-resolve-hook.ts +130 -0
- package/src/lib/crud/__tests__/ids.test.ts +34 -1
- package/src/lib/crud/ids.ts +24 -0
- package/src/lib/openapi/__tests__/optional-path-params.test.ts +102 -0
- package/src/lib/openapi/generator.ts +106 -77
- package/src/modules/registry.ts +5 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -13,7 +13,7 @@ import { CLIENT_ONLY_STUB_NAMESPACE, createClientOnlyStubPlugin } from "./client
|
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import fs from "node:fs";
|
|
15
15
|
import crypto from "node:crypto";
|
|
16
|
-
import { createRequire } from "node:module";
|
|
16
|
+
import { createRequire, isBuiltin } from "node:module";
|
|
17
17
|
import { pathToFileURL } from "node:url";
|
|
18
18
|
let activeBootstrapLoads = 0;
|
|
19
19
|
let esbuildRuntime = null;
|
|
@@ -54,7 +54,33 @@ class GeneratedFileNotFoundError extends Error {
|
|
|
54
54
|
this.filePath = filePath;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
function
|
|
57
|
+
function splitBareSpecifier(specifier) {
|
|
58
|
+
const segments = specifier.split("/");
|
|
59
|
+
const nameLength = specifier.startsWith("@") ? 2 : 1;
|
|
60
|
+
if (segments.length <= nameLength || segments.slice(0, nameLength).some((segment) => !segment)) return null;
|
|
61
|
+
return {
|
|
62
|
+
packageName: segments.slice(0, nameLength).join("/"),
|
|
63
|
+
subpath: segments.slice(nameLength).join("/")
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function rewriteLegacySubpathSpecifier(specifier, appRequire, onRewrite) {
|
|
67
|
+
if (isBuiltin(specifier)) return specifier;
|
|
68
|
+
const parts = splitBareSpecifier(specifier);
|
|
69
|
+
if (!parts || path.posix.extname(parts.subpath)) return specifier;
|
|
70
|
+
try {
|
|
71
|
+
const manifestPath = appRequire.resolve(`${parts.packageName}/package.json`);
|
|
72
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
73
|
+
if (manifest.exports != null) return specifier;
|
|
74
|
+
const resolvedFile = appRequire.resolve(specifier);
|
|
75
|
+
const relativeFile = path.relative(path.dirname(manifestPath), resolvedFile);
|
|
76
|
+
if (!relativeFile || relativeFile.startsWith("..") || path.isAbsolute(relativeFile)) return specifier;
|
|
77
|
+
onRewrite(manifestPath);
|
|
78
|
+
return `${parts.packageName}/${relativeFile.split(path.sep).join("/")}`;
|
|
79
|
+
} catch {
|
|
80
|
+
return specifier;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function createCliBundlePlugins(appRoot, options = {}) {
|
|
58
84
|
const aliasPlugin = {
|
|
59
85
|
name: "alias-resolver",
|
|
60
86
|
setup(build) {
|
|
@@ -75,6 +101,16 @@ function createCliBundlePlugins(appRoot) {
|
|
|
75
101
|
});
|
|
76
102
|
}
|
|
77
103
|
};
|
|
104
|
+
const appRequire = createRequire(path.join(appRoot, "package.json"));
|
|
105
|
+
const externalSpecifierCache = /* @__PURE__ */ new Map();
|
|
106
|
+
const onLegacySubpathRewrite = options.onLegacySubpathRewrite ?? (() => void 0);
|
|
107
|
+
const resolveExternalSpecifier = (specifier) => {
|
|
108
|
+
const cached = externalSpecifierCache.get(specifier);
|
|
109
|
+
if (cached !== void 0) return cached;
|
|
110
|
+
const resolved = rewriteLegacySubpathSpecifier(specifier, appRequire, onLegacySubpathRewrite);
|
|
111
|
+
externalSpecifierCache.set(specifier, resolved);
|
|
112
|
+
return resolved;
|
|
113
|
+
};
|
|
78
114
|
const externalNonJsonPlugin = {
|
|
79
115
|
name: "external-non-json",
|
|
80
116
|
setup(build) {
|
|
@@ -85,13 +121,13 @@ function createCliBundlePlugins(appRoot) {
|
|
|
85
121
|
if (args.path.endsWith(".json")) {
|
|
86
122
|
return null;
|
|
87
123
|
}
|
|
88
|
-
return { path: args.path, external: true };
|
|
124
|
+
return { path: resolveExternalSpecifier(args.path), external: true };
|
|
89
125
|
});
|
|
90
126
|
}
|
|
91
127
|
};
|
|
92
128
|
return [createClientOnlyStubPlugin(), aliasPlugin, externalNonJsonPlugin];
|
|
93
129
|
}
|
|
94
|
-
const DYNAMIC_LOADER_CACHE_VERSION =
|
|
130
|
+
const DYNAMIC_LOADER_CACHE_VERSION = 5;
|
|
95
131
|
function cacheMetadataPath(jsPath) {
|
|
96
132
|
return `${jsPath}.cache.json`;
|
|
97
133
|
}
|
|
@@ -260,6 +296,7 @@ async function compileAppSourceFileWithActiveEsbuild(tsPath, options) {
|
|
|
260
296
|
}
|
|
261
297
|
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
|
262
298
|
const esbuild = await getEsbuildRuntime();
|
|
299
|
+
const rewrittenPackageManifests = /* @__PURE__ */ new Set();
|
|
263
300
|
const result = await esbuild.build({
|
|
264
301
|
entryPoints: [tsPath],
|
|
265
302
|
outfile: outFile,
|
|
@@ -270,7 +307,9 @@ async function compileAppSourceFileWithActiveEsbuild(tsPath, options) {
|
|
|
270
307
|
platform: "node",
|
|
271
308
|
target: "node18",
|
|
272
309
|
tsconfig: appTsconfig,
|
|
273
|
-
plugins: createCliBundlePlugins(appRoot
|
|
310
|
+
plugins: createCliBundlePlugins(appRoot, {
|
|
311
|
+
onLegacySubpathRewrite: (manifestPath) => rewrittenPackageManifests.add(manifestPath)
|
|
312
|
+
}),
|
|
274
313
|
// Allow JSON imports
|
|
275
314
|
loader: { ".json": "json" }
|
|
276
315
|
});
|
|
@@ -280,7 +319,8 @@ async function compileAppSourceFileWithActiveEsbuild(tsPath, options) {
|
|
|
280
319
|
outputHash: contentHash(fs.readFileSync(outFile)),
|
|
281
320
|
dependencies: {
|
|
282
321
|
...collectDependencyHashes(appRoot, result.metafile.inputs),
|
|
283
|
-
...hashFilesRelativeTo(appRoot, tsconfigPaths)
|
|
322
|
+
...hashFilesRelativeTo(appRoot, tsconfigPaths),
|
|
323
|
+
...hashFilesRelativeTo(appRoot, [...rewrittenPackageManifests])
|
|
284
324
|
}
|
|
285
325
|
};
|
|
286
326
|
fs.writeFileSync(metadataPath, JSON.stringify(metadata));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/bootstrap/dynamicLoader.ts"],
|
|
4
|
-
"sourcesContent": ["import { asValue } from 'awilix'\nimport type { BootstrapData } from './types'\nimport type { AppDiRegistrar } from '../di/container'\nimport { findAppRoot, type AppRoot } from './appResolver'\nimport { registerEntityIds } from '../encryption/entityIds'\nimport { createLogger } from '../logger'\nimport {\n applyModuleOverridesFromEnabledModules,\n type ModuleEntryWithOverrides,\n} from '../../modules/overrides'\nimport {\n ensureMikroOrmV7GeneratedCacheCompatibility,\n recoverMikroOrmV7GeneratedCacheFromImportError,\n} from './generatedCacheRecovery'\nimport { CLIENT_ONLY_STUB_NAMESPACE, createClientOnlyStubPlugin } from './clientOnlyModules'\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport crypto from 'node:crypto'\nimport { createRequire } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\nlet activeBootstrapLoads = 0\nlet esbuildRuntime: typeof import('esbuild') | null = null\nlet esbuildStopPromise: Promise<void> | null = null\n\nconst logger = createLogger('shared').child({ component: 'bootstrap' })\n\nasync function getEsbuildRuntime(): Promise<typeof import('esbuild')> {\n if (esbuildStopPromise) await esbuildStopPromise\n if (esbuildRuntime) return esbuildRuntime\n\n const loadedRuntime = await import('esbuild')\n esbuildRuntime ??= loadedRuntime\n return esbuildRuntime\n}\n\nasync function withEsbuildLifecycle<T>(load: () => Promise<T>): Promise<T> {\n activeBootstrapLoads += 1\n\n try {\n return await load()\n } finally {\n activeBootstrapLoads -= 1\n if (activeBootstrapLoads === 0 && esbuildRuntime) {\n // esbuild keeps a helper process alive after build(). Bootstrap compilation\n // is a bounded phase, so release it once every concurrent loader is done.\n // A later build() call transparently starts a fresh helper process.\n const runtimeToStop = esbuildRuntime\n esbuildRuntime = null\n const stopPromise = runtimeToStop.stop().catch((err) => {\n logger.warn('Failed to stop the bootstrap compiler service', { err })\n })\n esbuildStopPromise = stopPromise\n try {\n await stopPromise\n } finally {\n if (esbuildStopPromise === stopPromise) esbuildStopPromise = null\n }\n }\n }\n}\n\n/**\n * Thrown when an expected generated source file is absent.\n *\n * Optional registries treat this as the supported compatibility case (an app\n * that never generated the file), which is what makes it distinguishable from\n * a file that exists but fails to compile or import.\n */\nclass GeneratedFileNotFoundError extends Error {\n readonly filePath: string\n\n constructor(filePath: string) {\n super(`Generated file not found: ${filePath}`)\n this.name = 'GeneratedFileNotFoundError'\n this.filePath = filePath\n }\n}\n\n/**\n * esbuild plugins for the CLI bundle, in resolution order. The client-only stub must come\n * first so it wins over the alias and external plugins for `*.client` dynamic imports.\n *\n * Exported so the wiring itself is testable: a test that only exercises\n * `createClientOnlyStubPlugin` in isolation stays green if the plugin is dropped from this\n * list, which would silently reintroduce #4623.\n */\nexport function createCliBundlePlugins(appRoot: string): import('esbuild').Plugin[] {\n // Plugin to resolve the @/ alias the way the app tsconfig maps it:\n // `@/.mercato/*` to the app root, every other `@/*` to the app's src/ directory.\n const aliasPlugin: import('esbuild').Plugin = {\n name: 'alias-resolver',\n setup(build) {\n build.onResolve({ filter: /^@\\// }, (args) => {\n const rest = args.path.slice('@/'.length)\n const bases = rest.startsWith('.mercato/')\n ? [path.join(appRoot, rest)]\n : [path.join(appRoot, 'src', rest), path.join(appRoot, rest)]\n for (const base of bases) {\n if (fs.existsSync(base) && fs.statSync(base).isFile()) {\n return { path: base }\n }\n for (const suffix of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + suffix)) {\n return { path: base + suffix }\n }\n }\n }\n // Nothing matched \u2014 hand esbuild the literal mapping so it reports the\n // missing file against the path the app author actually wrote.\n return { path: path.join(appRoot, rest) }\n })\n },\n }\n\n // Plugin to mark non-JSON package imports as external\n const externalNonJsonPlugin: import('esbuild').Plugin = {\n name: 'external-non-json',\n setup(build) {\n // Mark all package imports as external EXCEPT JSON files\n // Filter matches paths that don't start with . or / (package imports like @open-mercato/shared)\n build.onResolve({ filter: /^[^./]/ }, (args) => {\n // Skip Windows absolute paths (e.g., C:\\...) - they're local files, not packages\n if (/^[a-zA-Z]:/.test(args.path)) {\n return null // Let esbuild handle it\n }\n // If it's a JSON file, let esbuild bundle it\n if (args.path.endsWith('.json')) {\n return null // Let esbuild handle it\n }\n // Otherwise mark as external\n return { path: args.path, external: true }\n })\n },\n }\n\n return [createClientOnlyStubPlugin(), aliasPlugin, externalNonJsonPlugin]\n}\n\nconst DYNAMIC_LOADER_CACHE_VERSION = 4\n\ntype DynamicLoaderCacheMetadata = {\n version: number\n inputHash: string\n outputHash: string\n dependencies: Record<string, string>\n}\n\nfunction cacheMetadataPath(jsPath: string): string {\n return `${jsPath}.cache.json`\n}\n\nfunction contentHash(content: Buffer | string): string {\n return crypto.createHash('sha256').update(content).digest('hex')\n}\n\nfunction parseJsonConfig(content: string): unknown {\n let normalized = ''\n let inString = false\n let escaped = false\n\n for (let index = 0; index < content.length; index += 1) {\n const character = content[index]\n const nextCharacter = content[index + 1]\n\n if (inString) {\n normalized += character\n if (escaped) {\n escaped = false\n } else if (character === '\\\\') {\n escaped = true\n } else if (character === '\"') {\n inString = false\n }\n continue\n }\n\n if (character === '\"') {\n inString = true\n normalized += character\n continue\n }\n\n if (character === '/' && nextCharacter === '/') {\n while (index < content.length && content[index] !== '\\n') index += 1\n normalized += '\\n'\n continue\n }\n\n if (character === '/' && nextCharacter === '*') {\n index += 2\n while (index < content.length && !(content[index] === '*' && content[index + 1] === '/')) {\n index += 1\n }\n index += 1\n continue\n }\n\n if (character === ',') {\n let lookahead = index + 1\n while (lookahead < content.length && /\\s/.test(content[lookahead])) lookahead += 1\n if (content[lookahead] === '}' || content[lookahead] === ']') continue\n }\n\n normalized += character\n }\n\n return JSON.parse(normalized)\n}\n\nfunction resolveExistingConfigPath(candidate: string): string | null {\n for (const configPath of [candidate, `${candidate}.json`, path.join(candidate, 'tsconfig.json')]) {\n if (fs.existsSync(configPath) && fs.statSync(configPath).isFile()) return configPath\n }\n return null\n}\n\nfunction resolvePackageConfig(configPath: string, reference: string): string | null {\n try {\n const resolved = createRequire(pathToFileURL(configPath)).resolve(reference)\n return path.extname(resolved) === '.json' ? resolved : null\n } catch {\n return null\n }\n}\n\nfunction resolveExtendedConfig(configPath: string, reference: string): string {\n if (path.isAbsolute(reference) || reference.startsWith('.')) {\n const resolved = resolveExistingConfigPath(path.resolve(path.dirname(configPath), reference))\n if (resolved) return resolved\n } else {\n for (const packageReference of [reference, `${reference}/tsconfig.json`]) {\n const resolved = resolvePackageConfig(configPath, packageReference)\n if (resolved) return resolved\n }\n }\n\n throw new Error(`[internal] TypeScript config extends target not found: ${reference}`)\n}\n\nfunction collectTsconfigPaths(entryPath: string, visited: Set<string> = new Set()): string[] {\n const configPath = path.resolve(entryPath)\n if (visited.has(configPath)) return []\n visited.add(configPath)\n\n const parsed = parseJsonConfig(fs.readFileSync(configPath, 'utf8'))\n if (typeof parsed !== 'object' || parsed === null || !('extends' in parsed)) return [configPath]\n\n const extendsValue = parsed.extends\n const references = typeof extendsValue === 'string'\n ? [extendsValue]\n : Array.isArray(extendsValue) && extendsValue.every((value) => typeof value === 'string')\n ? extendsValue\n : []\n\n return [\n ...references.flatMap((reference) => collectTsconfigPaths(\n resolveExtendedConfig(configPath, reference),\n visited,\n )),\n configPath,\n ]\n}\n\nfunction hashFilesRelativeTo(appRoot: string, filePaths: string[]): Record<string, string> {\n return Object.fromEntries(filePaths.map((filePath) => [\n path.relative(appRoot, filePath).split(path.sep).join('/'),\n contentHash(fs.readFileSync(filePath)),\n ]))\n}\n\nfunction cacheInputHash(tsPath: string, appRoot: string, tsconfigPaths: string[]): string {\n const hash = crypto.createHash('sha256')\n hash.update(JSON.stringify({\n version: DYNAMIC_LOADER_CACHE_VERSION,\n sourceHash: contentHash(fs.readFileSync(tsPath)),\n tsconfigHashes: hashFilesRelativeTo(appRoot, tsconfigPaths),\n }))\n return hash.digest('hex')\n}\n\nfunction dependenciesAreValid(appRoot: string, dependencies: Record<string, string>): boolean {\n return Object.entries(dependencies).every(([relativePath, expectedHash]) => {\n const dependencyPath = path.resolve(appRoot, relativePath)\n return fs.existsSync(dependencyPath)\n && contentHash(fs.readFileSync(dependencyPath)) === expectedHash\n })\n}\n\nfunction collectDependencyHashes(\n appRoot: string,\n inputs: Record<string, unknown>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.keys(inputs)\n .filter((inputPath) => !inputPath.startsWith(`${CLIENT_ONLY_STUB_NAMESPACE}:`))\n .map((inputPath) => {\n const absolutePath = path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(appRoot, inputPath)\n const relativePath = path.relative(appRoot, absolutePath).split(path.sep).join('/')\n return [relativePath, contentHash(fs.readFileSync(absolutePath))]\n })\n .sort(([left], [right]) => left.localeCompare(right)),\n )\n}\n\nfunction readCacheMetadata(metadataPath: string): DynamicLoaderCacheMetadata | null {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(metadataPath, 'utf8'))\n if (\n typeof parsed === 'object'\n && parsed !== null\n && 'version' in parsed\n && parsed.version === DYNAMIC_LOADER_CACHE_VERSION\n && 'inputHash' in parsed\n && typeof parsed.inputHash === 'string'\n && 'outputHash' in parsed\n && typeof parsed.outputHash === 'string'\n && 'dependencies' in parsed\n && typeof parsed.dependencies === 'object'\n && parsed.dependencies !== null\n && Object.values(parsed.dependencies).every((hash) => typeof hash === 'string')\n ) {\n return {\n version: parsed.version,\n inputHash: parsed.inputHash,\n outputHash: parsed.outputHash,\n dependencies: parsed.dependencies as Record<string, string>,\n }\n }\n } catch {\n return null\n }\n return null\n}\n\nfunction cacheIsValid(\n appRoot: string,\n jsPath: string,\n metadataPath: string,\n expectedInputHash: string,\n): boolean {\n if (!fs.existsSync(jsPath)) return false\n const metadata = readCacheMetadata(metadataPath)\n if (!metadata || metadata.inputHash !== expectedInputHash) return false\n return contentHash(fs.readFileSync(jsPath)) === metadata.outputHash\n && dependenciesAreValid(appRoot, metadata.dependencies)\n}\n\n/**\n * Options for `compileAndImport`.\n *\n * Both paths default to the generated-registry layout (`<appRoot>/.mercato/generated/<file>.ts`\n * compiled to a `.mjs` sibling). Sources that live elsewhere in the app \u2014 `src/di.ts` \u2014 MUST pass\n * both explicitly: the default app root is derived by walking three directories up from the source,\n * which only holds inside `.mercato/generated`.\n */\ntype CompileAndImportOptions = {\n appRoot?: string\n outFile?: string\n allowRecovery?: boolean\n}\n\n/**\n * Options for `compileAppSourceFile`.\n *\n * `appRoot` anchors the tsconfig, the `@/` alias resolution and the dependency\n * cache; `outFile` is the absolute path of the artifact to write. `format`\n * selects the module system of that artifact \u2014 `'cjs'` exists for the Jest\n * runtime, which cannot `import()` an ESM sibling.\n */\nexport type CompileAppSourceOptions = {\n appRoot: string\n outFile: string\n format?: 'esm' | 'cjs'\n}\n\n/**\n * Compile one app-owned TypeScript source and its relative import graph into a\n * single JavaScript artifact, leaving every package import external.\n *\n * This is the only supported way to load app source (`apps/<app>/src/**`,\n * `.mercato/generated/**`) from a plain Node process. Those files are never\n * compiled to `dist`, and Node's own type stripping cannot load them: it\n * requires explicit file extensions on relative specifiers and rejects the\n * decorator and enum syntax the entities and DI files use.\n *\n * The artifact is cached against the content of the entry, its whole bundled\n * dependency graph, and the tsconfig chain, so an edit anywhere in the graph\n * invalidates it.\n *\n * The build runs inside the shared esbuild lifecycle. Callers outside a\n * bootstrap load \u2014 the generated-registry loader compiling an `@app` module \u2014\n * would otherwise hold a build on a service another scope is entitled to\n * `stop()`, and would leave the helper process running afterwards. Nesting is\n * safe: the scope only releases the service when the last participant exits.\n */\nexport async function compileAppSourceFile(\n tsPath: string,\n options: CompileAppSourceOptions,\n): Promise<string> {\n return withEsbuildLifecycle(() => compileAppSourceFileWithActiveEsbuild(tsPath, options))\n}\n\nasync function compileAppSourceFileWithActiveEsbuild(\n tsPath: string,\n options: CompileAppSourceOptions,\n): Promise<string> {\n const { appRoot, outFile } = options\n const format = options.format ?? 'esm'\n const appTsconfig = path.join(appRoot, 'tsconfig.json')\n const metadataPath = cacheMetadataPath(outFile)\n\n const tsExists = fs.existsSync(tsPath)\n const tsconfigExists = fs.existsSync(appTsconfig)\n\n if (!tsExists) {\n throw new GeneratedFileNotFoundError(tsPath)\n }\n if (!tsconfigExists) {\n throw new Error(`App TypeScript config not found: ${appTsconfig}`)\n }\n\n const tsconfigPaths = collectTsconfigPaths(appTsconfig)\n const expectedInputHash = cacheInputHash(tsPath, appRoot, tsconfigPaths)\n\n if (cacheIsValid(appRoot, outFile, metadataPath, expectedInputHash)) {\n return outFile\n }\n\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n // Dynamically import esbuild only when needed\n const esbuild = await getEsbuildRuntime()\n\n // Use esbuild.build with bundling to handle JSON imports\n const result = await esbuild.build({\n entryPoints: [tsPath],\n outfile: outFile,\n absWorkingDir: appRoot,\n bundle: true,\n metafile: true,\n format,\n platform: 'node',\n target: 'node18',\n tsconfig: appTsconfig,\n plugins: createCliBundlePlugins(appRoot),\n // Allow JSON imports\n loader: { '.json': 'json' },\n })\n const metadata: DynamicLoaderCacheMetadata = {\n version: DYNAMIC_LOADER_CACHE_VERSION,\n inputHash: expectedInputHash,\n outputHash: contentHash(fs.readFileSync(outFile)),\n dependencies: {\n ...collectDependencyHashes(appRoot, result.metafile.inputs),\n ...hashFilesRelativeTo(appRoot, tsconfigPaths),\n },\n }\n fs.writeFileSync(metadataPath, JSON.stringify(metadata))\n\n return outFile\n}\n\n/**\n * Compile a TypeScript file to JavaScript using esbuild bundler.\n * This bundles the file and all its dependencies, handling JSON imports properly.\n * The compiled file is written next to the source file with a .mjs extension unless\n * `outFile` says otherwise.\n */\nasync function compileAndImport(\n tsPath: string,\n options: CompileAndImportOptions = {},\n): Promise<Record<string, unknown>> {\n const allowRecovery = options.allowRecovery ?? true\n const jsPath = options.outFile ?? tsPath.replace(/\\.ts$/, '.mjs')\n const appRoot = options.appRoot ?? path.dirname(path.dirname(path.dirname(tsPath)))\n\n await compileAppSourceFile(tsPath, { appRoot, outFile: jsPath })\n\n // Import the compiled JavaScript\n try {\n const outputHash = contentHash(fs.readFileSync(jsPath))\n const fileUrl = `${pathToFileURL(jsPath).href}?cache=${outputHash}`\n return await import(fileUrl)\n } catch (error) {\n if (!allowRecovery) {\n throw error\n }\n\n const recovered = recoverMikroOrmV7GeneratedCacheFromImportError(appRoot, error)\n if (!recovered.applied) {\n throw error\n }\n\n return compileAndImport(tsPath, { ...options, allowRecovery: false })\n }\n}\n\n\n/**\n * Registers an app-owned generated value on the request container.\n *\n * The app registers these statically from `src/di.ts`, which `createRequestContainer`\n * reaches through the `@/` alias \u2014 and that alias only exists under the bundler.\n * A CLI or MCP process runs plain Node, so the import fails, the failure is\n * swallowed, and the value is simply absent with no diagnostic. Routing it through\n * a registrar built from the same generated file keeps both processes in step.\n */\nfunction appValueRegistrar(key: string, value: unknown): BootstrapData['diRegistrars'][number] {\n return (container) => {\n container.register({ [key]: asValue(value) })\n }\n}\n\n/**\n * Load a generated registry that older apps may not have generated yet.\n *\n * An absent source file is the supported compatibility case and resolves to\n * `fallback` quietly. Any other failure \u2014 a compile error, a broken import, a\n * runtime throw at module scope \u2014 still resolves to `fallback` so bootstrap\n * keeps working, but is reported at error level: a registry that silently\n * degrades to nothing is exactly how command interceptors stopped applying in\n * worker/CLI processes (#4327, #4491).\n */\nasync function loadOptionalGeneratedModule(\n tsPath: string,\n fallback: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n try {\n return await compileAndImport(tsPath)\n } catch (error) {\n if (error instanceof GeneratedFileNotFoundError) {\n logger.debug('Optional generated registry not present, using empty fallback', {\n file: path.basename(tsPath),\n })\n return fallback\n }\n\n logger.error('Failed to load generated registry, continuing without its entries', {\n file: path.basename(tsPath),\n filePath: tsPath,\n err: error,\n })\n return fallback\n }\n}\n\nfunction resolveAppRootOrThrow(appRoot?: string): AppRoot {\n const resolved: AppRoot | null = appRoot\n ? {\n generatedDir: path.join(appRoot, '.mercato', 'generated'),\n appDir: appRoot,\n mercatoDir: path.join(appRoot, '.mercato'),\n }\n : findAppRoot()\n\n if (!resolved) {\n throw new Error(\n 'Could not find app root with .mercato/generated directory. ' +\n 'Make sure you run this command from within a Next.js app directory, ' +\n 'or run \"yarn mercato generate\" first to create the generated files.',\n )\n }\n\n return resolved\n}\n\n/**\n * Load the app-level DI registrar (`src/di.ts`) for the dynamic bootstrap path.\n *\n * The Next.js runtime imports `@/di` statically from its own `src/bootstrap.ts` and hands the\n * registrar to `createBootstrap`. Worker, scheduler and CLI processes bootstrap through\n * `bootstrapFromAppRoot` instead, where the `@/` alias does not exist \u2014 so without this the app's\n * DI registrations silently never ran there, and every request container paid a failed\n * `import('@/di')` resolution (the compatibility fallback in `lib/di/container.ts`).\n *\n * An absent `src/di.ts` is the supported case and resolves to `null` quietly. A file that exists\n * but cannot be compiled, imported, or does not export `register` is reported at error level and\n * still resolves to `null`, so a broken app DI module degrades the same way a broken generated\n * registry does (#4327, #4491) instead of taking the whole process down.\n */\nasync function loadAppDiRegistrar(appDir: string): Promise<AppDiRegistrar | null> {\n const tsPath = path.join(appDir, 'src', 'di.ts')\n if (!fs.existsSync(tsPath)) {\n logger.debug('App-level DI module not present, skipping its registrations', { filePath: tsPath })\n return null\n }\n\n try {\n const appDiModule = await compileAndImport(tsPath, {\n appRoot: appDir,\n outFile: path.join(appDir, '.mercato', 'generated', 'app-di.compiled.mjs'),\n })\n const register = appDiModule.register\n if (typeof register !== 'function') {\n logger.error('App-level DI module exports no register(); its registrations are skipped', {\n filePath: tsPath,\n })\n return null\n }\n return register as AppDiRegistrar\n } catch (error) {\n logger.error('Failed to load the app-level DI module; its registrations are skipped', {\n filePath: tsPath,\n err: error,\n })\n return null\n }\n}\n\n/**\n * Override domains whose applier is not registered by `registerBuiltInModuleOverrideAppliers()`\n * but by importing a domain package for its side effect. `bootstrap-common.ts` does this with a\n * static import right before it dispatches; the dynamic bootstrap path has no bundler to lean on,\n * so it resolves the same modules here \u2014 lazily, and only when an app actually declares the\n * domain, so `@open-mercato/shared` keeps its rule of never taking a runtime dependency on a\n * domain package (soft-optional coupling, `packages/core/AGENTS.md` \u2192 Cross-Module Coupling).\n */\nconst OPTIONAL_OVERRIDE_APPLIER_MODULES: Record<string, string> = {\n ai: '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-overrides',\n}\n\n/**\n * Import the side-effect module that registers the applier for every declared override domain\n * that has no built-in one. A domain package the app does not install is not an error \u2014 there\n * is nothing for that domain to apply to \u2014 so a failed resolution is logged and skipped, and the\n * dispatcher's own \"domain not yet wired\" warning still fires behind it.\n */\nasync function ensureOptionalOverrideAppliers(enabledModules: ModuleEntryWithOverrides[]): Promise<void> {\n for (const [domain, specifier] of Object.entries(OPTIONAL_OVERRIDE_APPLIER_MODULES)) {\n const declared = enabledModules.some((entry) => {\n const overrides = entry?.overrides as Record<string, unknown> | undefined\n return Boolean(overrides && overrides[domain])\n })\n if (!declared) continue\n try {\n await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ specifier)\n } catch (error) {\n logger.debug('Optional override applier module is not installed; the domain has nothing to apply to', {\n domain,\n specifier,\n err: error,\n })\n }\n }\n}\n\n/**\n * Dispatch `entry.overrides` declared in the app's `src/modules.ts` for the dynamic\n * bootstrap path.\n *\n * The Next.js runtime imports `enabledModules` statically from its own `src/modules.ts` and\n * calls `applyModuleOverridesFromEnabledModules` from `bootstrap-common.ts` before any registry\n * first-loads. Worker, scheduler and CLI processes bootstrap through `bootstrapFromAppRoot`\n * instead, which only ever compiled the generated `modules.cli.generated.ts` \u2014 so an app's\n * `entry.overrides` (encryption maps, ACL features, CLI commands, workers, event subscribers,\n * setup, \u2026) silently never applied there. `seed-encryption` seeding the base encryption maps\n * instead of the app's `overrides.encryption.maps` was the concrete symptom (#5582).\n *\n * An app layout with no `src/modules.ts` at all is logged and skipped \u2014 that is a real\n * compatibility case, handled the same way an absent `src/di.ts` is. A file that is *present*\n * but fails to compile or import is not: it throws, matching how this same function treats\n * every other mandatory input and how the Next.js runtime treats this same file (a static\n * import in `bootstrap-common.ts`). Degrading there would put `seed-encryption` back on the\n * base encryption maps while still printing success \u2014 #5582's outcome, only quieter.\n */\nasync function loadAppModuleOverrides(appDir: string): Promise<void> {\n const tsPath = path.join(appDir, 'src', 'modules.ts')\n if (!fs.existsSync(tsPath)) {\n logger.debug('App-level modules file not present, skipping entry.overrides dispatch', { filePath: tsPath })\n return\n }\n\n let enabledModules: unknown\n try {\n const appModulesModule = await compileAndImport(tsPath, {\n appRoot: appDir,\n outFile: path.join(appDir, '.mercato', 'generated', 'app-modules-overrides.compiled.mjs'),\n })\n enabledModules = appModulesModule.enabledModules\n } catch (error) {\n throw new Error(\n `[internal] Failed to load the app-level modules file (${tsPath}); entry.overrides cannot be applied. ` +\n 'Refusing to bootstrap with a partial override set.',\n { cause: error },\n )\n }\n\n if (!Array.isArray(enabledModules)) {\n throw new Error(\n `[internal] The app-level modules file (${tsPath}) exports no enabledModules array; ` +\n 'entry.overrides cannot be applied. Refusing to bootstrap with a partial override set.',\n )\n }\n\n await ensureOptionalOverrideAppliers(enabledModules as ModuleEntryWithOverrides[])\n applyModuleOverridesFromEnabledModules(enabledModules as ModuleEntryWithOverrides[])\n}\n\n/**\n * Dynamically load bootstrap data from a resolved app directory.\n *\n * IMPORTANT: This only works in unbundled contexts (CLI, tsx).\n * Do NOT use this in Next.js bundled code - use static imports instead.\n *\n * For CLI context, we skip loading modules.generated.ts which has Next.js dependencies.\n * CLI commands are discovered separately via the CLI module system.\n *\n * @param appRoot - Optional explicit app root path. If not provided, will search from cwd.\n * @returns The loaded bootstrap data\n * @throws Error if app root cannot be found or generated files are missing\n */\nasync function loadBootstrapDataWithActiveEsbuild(appRoot?: string): Promise<BootstrapData> {\n const resolved = resolveAppRootOrThrow(appRoot)\n\n const { generatedDir } = resolved\n\n ensureMikroOrmV7GeneratedCacheCompatibility(resolved.appDir)\n\n // IMPORTANT: Load entity IDs FIRST and register them before loading modules.\n // This is because modules (e.g., ce.ts files) use E.xxx.xxx at module scope,\n // and they need entity IDs to be available when they're imported.\n const entityIdsModule = await compileAndImport(path.join(generatedDir, 'entities.ids.generated.ts'))\n registerEntityIds(entityIdsModule.E as BootstrapData['entityIds'])\n\n // Now load the rest of the generated files.\n // modules.cli.generated.ts excludes Next.js-dependent code (routes, APIs, widgets)\n const [\n modulesModule,\n entitiesModule,\n diModule,\n searchModule,\n commandLoadersModule,\n webResearchModule,\n commandInterceptorsModule,\n workflowsModule,\n ] = await Promise.all([\n compileAndImport(path.join(generatedDir, 'modules.cli.generated.ts')),\n compileAndImport(path.join(generatedDir, 'entities.generated.ts')),\n compileAndImport(path.join(generatedDir, 'di.generated.ts')),\n loadOptionalGeneratedModule(path.join(generatedDir, 'search.generated.ts'), { searchModuleConfigs: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-loaders.generated.ts'), { commandLoaderEntries: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'web-research-adapters.generated.ts'), {\n webResearchAdapterEntries: [],\n }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-interceptors.generated.ts'), {\n commandInterceptorEntries: [],\n }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'workflows.generated.ts'), { allCodeWorkflows: [] }),\n ])\n\n return {\n modules: modulesModule.modules as BootstrapData['modules'],\n entities: entitiesModule.entities as BootstrapData['entities'],\n diRegistrars: [\n ...(diModule.diRegistrars as BootstrapData['diRegistrars']),\n appValueRegistrar('webResearchAdapterEntries', webResearchModule.webResearchAdapterEntries ?? []),\n ],\n entityIds: entityIdsModule.E as BootstrapData['entityIds'],\n // Search configs are needed by workers for indexing\n searchModuleConfigs: (searchModule.searchModuleConfigs ?? []) as BootstrapData['searchModuleConfigs'],\n commandLoaderEntries: (commandLoadersModule.commandLoaderEntries ?? []) as BootstrapData['commandLoaderEntries'],\n // Command interceptors must apply in worker/CLI processes too \u2014 the\n // interceptor registry is per-process, so relying on the Next.js runtime's\n // registration silently no-ops every interceptor for queued/CLI commands\n // (#4327).\n commandInterceptorEntries: (commandInterceptorsModule.commandInterceptorEntries ??\n []) as BootstrapData['commandInterceptorEntries'],\n // Code workflow definitions are needed by workers to resume code-defined instances\n codeWorkflows: (workflowsModule.allCodeWorkflows ?? []) as BootstrapData['codeWorkflows'],\n // Empty UI-related data - not needed for CLI\n dashboardWidgetEntries: [],\n injectionWidgetEntries: [],\n injectionTables: [],\n interceptorEntries: [],\n componentOverrideEntries: [],\n }\n}\n\nexport async function loadBootstrapData(appRoot?: string): Promise<BootstrapData> {\n return withEsbuildLifecycle(() => loadBootstrapDataWithActiveEsbuild(appRoot))\n}\n\n/**\n * Create and execute bootstrap in CLI context.\n *\n * This is a convenience function that finds the app root, loads the generated\n * data dynamically, and runs bootstrap. Use this in CLI entry points.\n *\n * Returns the loaded bootstrap data so the CLI can register modules directly\n * (avoids module resolution issues when importing @open-mercato/cli/mercato).\n *\n * @param appRoot - Optional explicit app root path\n * @returns The loaded bootstrap data (modules, entities, etc.)\n */\nexport async function bootstrapFromAppRoot(appRoot?: string): Promise<BootstrapData> {\n const { createBootstrap, waitForAsyncRegistration } = await import('./factory.js')\n const resolved = resolveAppRootOrThrow(appRoot)\n // All three loads compile through esbuild, so they share one lifecycle scope: without it\n // `loadBootstrapData` releases the esbuild helper process and `loadAppDiRegistrar`\n // silently starts a second one that nothing ever stops.\n const { data, appDiRegistrar } = await withEsbuildLifecycle(async () => {\n // Dispatch the app's `entry.overrides` (src/modules.ts) BEFORE any registry\n // first-loads \u2014 the `bootstrap()` call below runs `registerModules(data.modules)`,\n // and `registerCliModules` in the mercato bin right after this function returns;\n // both read the override side-registry this populates.\n await loadAppModuleOverrides(resolved.appDir)\n return {\n data: await loadBootstrapData(resolved.appDir),\n appDiRegistrar: await loadAppDiRegistrar(resolved.appDir),\n }\n })\n const bootstrap = createBootstrap(data, appDiRegistrar ? { appDiRegistrar } : {})\n bootstrap()\n // In CLI context, wait for async registrations (UI widgets, search configs, etc.)\n await waitForAsyncRegistration()\n\n return data\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { asValue } from 'awilix'\nimport type { BootstrapData } from './types'\nimport type { AppDiRegistrar } from '../di/container'\nimport { findAppRoot, type AppRoot } from './appResolver'\nimport { registerEntityIds } from '../encryption/entityIds'\nimport { createLogger } from '../logger'\nimport {\n applyModuleOverridesFromEnabledModules,\n type ModuleEntryWithOverrides,\n} from '../../modules/overrides'\nimport {\n ensureMikroOrmV7GeneratedCacheCompatibility,\n recoverMikroOrmV7GeneratedCacheFromImportError,\n} from './generatedCacheRecovery'\nimport { CLIENT_ONLY_STUB_NAMESPACE, createClientOnlyStubPlugin } from './clientOnlyModules'\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport crypto from 'node:crypto'\nimport { createRequire, isBuiltin } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\nlet activeBootstrapLoads = 0\nlet esbuildRuntime: typeof import('esbuild') | null = null\nlet esbuildStopPromise: Promise<void> | null = null\n\nconst logger = createLogger('shared').child({ component: 'bootstrap' })\n\nasync function getEsbuildRuntime(): Promise<typeof import('esbuild')> {\n if (esbuildStopPromise) await esbuildStopPromise\n if (esbuildRuntime) return esbuildRuntime\n\n const loadedRuntime = await import('esbuild')\n esbuildRuntime ??= loadedRuntime\n return esbuildRuntime\n}\n\nasync function withEsbuildLifecycle<T>(load: () => Promise<T>): Promise<T> {\n activeBootstrapLoads += 1\n\n try {\n return await load()\n } finally {\n activeBootstrapLoads -= 1\n if (activeBootstrapLoads === 0 && esbuildRuntime) {\n // esbuild keeps a helper process alive after build(). Bootstrap compilation\n // is a bounded phase, so release it once every concurrent loader is done.\n // A later build() call transparently starts a fresh helper process.\n const runtimeToStop = esbuildRuntime\n esbuildRuntime = null\n const stopPromise = runtimeToStop.stop().catch((err) => {\n logger.warn('Failed to stop the bootstrap compiler service', { err })\n })\n esbuildStopPromise = stopPromise\n try {\n await stopPromise\n } finally {\n if (esbuildStopPromise === stopPromise) esbuildStopPromise = null\n }\n }\n }\n}\n\n/**\n * Thrown when an expected generated source file is absent.\n *\n * Optional registries treat this as the supported compatibility case (an app\n * that never generated the file), which is what makes it distinguishable from\n * a file that exists but fails to compile or import.\n */\nclass GeneratedFileNotFoundError extends Error {\n readonly filePath: string\n\n constructor(filePath: string) {\n super(`Generated file not found: ${filePath}`)\n this.name = 'GeneratedFileNotFoundError'\n this.filePath = filePath\n }\n}\n\nfunction splitBareSpecifier(specifier: string): { packageName: string; subpath: string } | null {\n const segments = specifier.split('/')\n const nameLength = specifier.startsWith('@') ? 2 : 1\n if (segments.length <= nameLength || segments.slice(0, nameLength).some((segment) => !segment)) return null\n return {\n packageName: segments.slice(0, nameLength).join('/'),\n subpath: segments.slice(nameLength).join('/'),\n }\n}\n\n/**\n * Rewrites an externalized `pkg/subpath` specifier to the file Node's ESM resolver can load\n * when `pkg` publishes no `exports` map (#6993). Builtins, packages with `exports`, subpaths\n * that already carry an extension and anything that fails to resolve keep the original\n * specifier, so the bundle never gets worse than before.\n */\nfunction rewriteLegacySubpathSpecifier(\n specifier: string,\n appRequire: NodeRequire,\n onRewrite: (manifestPath: string) => void,\n): string {\n if (isBuiltin(specifier)) return specifier\n const parts = splitBareSpecifier(specifier)\n if (!parts || path.posix.extname(parts.subpath)) return specifier\n try {\n const manifestPath = appRequire.resolve(`${parts.packageName}/package.json`)\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as { exports?: unknown }\n if (manifest.exports != null) return specifier\n const resolvedFile = appRequire.resolve(specifier)\n const relativeFile = path.relative(path.dirname(manifestPath), resolvedFile)\n if (!relativeFile || relativeFile.startsWith('..') || path.isAbsolute(relativeFile)) return specifier\n onRewrite(manifestPath)\n return `${parts.packageName}/${relativeFile.split(path.sep).join('/')}`\n } catch {\n return specifier\n }\n}\n\n/**\n * esbuild plugins for the CLI bundle, in resolution order. The client-only stub must come\n * first so it wins over the alias and external plugins for `*.client` dynamic imports.\n *\n * Exported so the wiring itself is testable: a test that only exercises\n * `createClientOnlyStubPlugin` in isolation stays green if the plugin is dropped from this\n * list, which would silently reintroduce #4623.\n */\nexport function createCliBundlePlugins(\n appRoot: string,\n options: { onLegacySubpathRewrite?: (manifestPath: string) => void } = {},\n): import('esbuild').Plugin[] {\n // Plugin to resolve the @/ alias the way the app tsconfig maps it:\n // `@/.mercato/*` to the app root, every other `@/*` to the app's src/ directory.\n const aliasPlugin: import('esbuild').Plugin = {\n name: 'alias-resolver',\n setup(build) {\n build.onResolve({ filter: /^@\\// }, (args) => {\n const rest = args.path.slice('@/'.length)\n const bases = rest.startsWith('.mercato/')\n ? [path.join(appRoot, rest)]\n : [path.join(appRoot, 'src', rest), path.join(appRoot, rest)]\n for (const base of bases) {\n if (fs.existsSync(base) && fs.statSync(base).isFile()) {\n return { path: base }\n }\n for (const suffix of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + suffix)) {\n return { path: base + suffix }\n }\n }\n }\n // Nothing matched \u2014 hand esbuild the literal mapping so it reports the\n // missing file against the path the app author actually wrote.\n return { path: path.join(appRoot, rest) }\n })\n },\n }\n\n // Node's ESM resolver only maps an extensionless package subpath (`next/link`) when the\n // package publishes an `exports` map; legacy packages need the real file path instead.\n const appRequire = createRequire(path.join(appRoot, 'package.json'))\n const externalSpecifierCache = new Map<string, string>()\n const onLegacySubpathRewrite = options.onLegacySubpathRewrite ?? (() => undefined)\n const resolveExternalSpecifier = (specifier: string): string => {\n const cached = externalSpecifierCache.get(specifier)\n if (cached !== undefined) return cached\n const resolved = rewriteLegacySubpathSpecifier(specifier, appRequire, onLegacySubpathRewrite)\n externalSpecifierCache.set(specifier, resolved)\n return resolved\n }\n\n // Plugin to mark non-JSON package imports as external\n const externalNonJsonPlugin: import('esbuild').Plugin = {\n name: 'external-non-json',\n setup(build) {\n // Mark all package imports as external EXCEPT JSON files\n // Filter matches paths that don't start with . or / (package imports like @open-mercato/shared)\n build.onResolve({ filter: /^[^./]/ }, (args) => {\n // Skip Windows absolute paths (e.g., C:\\...) - they're local files, not packages\n if (/^[a-zA-Z]:/.test(args.path)) {\n return null // Let esbuild handle it\n }\n // If it's a JSON file, let esbuild bundle it\n if (args.path.endsWith('.json')) {\n return null // Let esbuild handle it\n }\n // Otherwise mark as external\n return { path: resolveExternalSpecifier(args.path), external: true }\n })\n },\n }\n\n return [createClientOnlyStubPlugin(), aliasPlugin, externalNonJsonPlugin]\n}\n\nconst DYNAMIC_LOADER_CACHE_VERSION = 5\n\ntype DynamicLoaderCacheMetadata = {\n version: number\n inputHash: string\n outputHash: string\n dependencies: Record<string, string>\n}\n\nfunction cacheMetadataPath(jsPath: string): string {\n return `${jsPath}.cache.json`\n}\n\nfunction contentHash(content: Buffer | string): string {\n return crypto.createHash('sha256').update(content).digest('hex')\n}\n\nfunction parseJsonConfig(content: string): unknown {\n let normalized = ''\n let inString = false\n let escaped = false\n\n for (let index = 0; index < content.length; index += 1) {\n const character = content[index]\n const nextCharacter = content[index + 1]\n\n if (inString) {\n normalized += character\n if (escaped) {\n escaped = false\n } else if (character === '\\\\') {\n escaped = true\n } else if (character === '\"') {\n inString = false\n }\n continue\n }\n\n if (character === '\"') {\n inString = true\n normalized += character\n continue\n }\n\n if (character === '/' && nextCharacter === '/') {\n while (index < content.length && content[index] !== '\\n') index += 1\n normalized += '\\n'\n continue\n }\n\n if (character === '/' && nextCharacter === '*') {\n index += 2\n while (index < content.length && !(content[index] === '*' && content[index + 1] === '/')) {\n index += 1\n }\n index += 1\n continue\n }\n\n if (character === ',') {\n let lookahead = index + 1\n while (lookahead < content.length && /\\s/.test(content[lookahead])) lookahead += 1\n if (content[lookahead] === '}' || content[lookahead] === ']') continue\n }\n\n normalized += character\n }\n\n return JSON.parse(normalized)\n}\n\nfunction resolveExistingConfigPath(candidate: string): string | null {\n for (const configPath of [candidate, `${candidate}.json`, path.join(candidate, 'tsconfig.json')]) {\n if (fs.existsSync(configPath) && fs.statSync(configPath).isFile()) return configPath\n }\n return null\n}\n\nfunction resolvePackageConfig(configPath: string, reference: string): string | null {\n try {\n const resolved = createRequire(pathToFileURL(configPath)).resolve(reference)\n return path.extname(resolved) === '.json' ? resolved : null\n } catch {\n return null\n }\n}\n\nfunction resolveExtendedConfig(configPath: string, reference: string): string {\n if (path.isAbsolute(reference) || reference.startsWith('.')) {\n const resolved = resolveExistingConfigPath(path.resolve(path.dirname(configPath), reference))\n if (resolved) return resolved\n } else {\n for (const packageReference of [reference, `${reference}/tsconfig.json`]) {\n const resolved = resolvePackageConfig(configPath, packageReference)\n if (resolved) return resolved\n }\n }\n\n throw new Error(`[internal] TypeScript config extends target not found: ${reference}`)\n}\n\nfunction collectTsconfigPaths(entryPath: string, visited: Set<string> = new Set()): string[] {\n const configPath = path.resolve(entryPath)\n if (visited.has(configPath)) return []\n visited.add(configPath)\n\n const parsed = parseJsonConfig(fs.readFileSync(configPath, 'utf8'))\n if (typeof parsed !== 'object' || parsed === null || !('extends' in parsed)) return [configPath]\n\n const extendsValue = parsed.extends\n const references = typeof extendsValue === 'string'\n ? [extendsValue]\n : Array.isArray(extendsValue) && extendsValue.every((value) => typeof value === 'string')\n ? extendsValue\n : []\n\n return [\n ...references.flatMap((reference) => collectTsconfigPaths(\n resolveExtendedConfig(configPath, reference),\n visited,\n )),\n configPath,\n ]\n}\n\nfunction hashFilesRelativeTo(appRoot: string, filePaths: string[]): Record<string, string> {\n return Object.fromEntries(filePaths.map((filePath) => [\n path.relative(appRoot, filePath).split(path.sep).join('/'),\n contentHash(fs.readFileSync(filePath)),\n ]))\n}\n\nfunction cacheInputHash(tsPath: string, appRoot: string, tsconfigPaths: string[]): string {\n const hash = crypto.createHash('sha256')\n hash.update(JSON.stringify({\n version: DYNAMIC_LOADER_CACHE_VERSION,\n sourceHash: contentHash(fs.readFileSync(tsPath)),\n tsconfigHashes: hashFilesRelativeTo(appRoot, tsconfigPaths),\n }))\n return hash.digest('hex')\n}\n\nfunction dependenciesAreValid(appRoot: string, dependencies: Record<string, string>): boolean {\n return Object.entries(dependencies).every(([relativePath, expectedHash]) => {\n const dependencyPath = path.resolve(appRoot, relativePath)\n return fs.existsSync(dependencyPath)\n && contentHash(fs.readFileSync(dependencyPath)) === expectedHash\n })\n}\n\nfunction collectDependencyHashes(\n appRoot: string,\n inputs: Record<string, unknown>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.keys(inputs)\n .filter((inputPath) => !inputPath.startsWith(`${CLIENT_ONLY_STUB_NAMESPACE}:`))\n .map((inputPath) => {\n const absolutePath = path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(appRoot, inputPath)\n const relativePath = path.relative(appRoot, absolutePath).split(path.sep).join('/')\n return [relativePath, contentHash(fs.readFileSync(absolutePath))]\n })\n .sort(([left], [right]) => left.localeCompare(right)),\n )\n}\n\nfunction readCacheMetadata(metadataPath: string): DynamicLoaderCacheMetadata | null {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(metadataPath, 'utf8'))\n if (\n typeof parsed === 'object'\n && parsed !== null\n && 'version' in parsed\n && parsed.version === DYNAMIC_LOADER_CACHE_VERSION\n && 'inputHash' in parsed\n && typeof parsed.inputHash === 'string'\n && 'outputHash' in parsed\n && typeof parsed.outputHash === 'string'\n && 'dependencies' in parsed\n && typeof parsed.dependencies === 'object'\n && parsed.dependencies !== null\n && Object.values(parsed.dependencies).every((hash) => typeof hash === 'string')\n ) {\n return {\n version: parsed.version,\n inputHash: parsed.inputHash,\n outputHash: parsed.outputHash,\n dependencies: parsed.dependencies as Record<string, string>,\n }\n }\n } catch {\n return null\n }\n return null\n}\n\nfunction cacheIsValid(\n appRoot: string,\n jsPath: string,\n metadataPath: string,\n expectedInputHash: string,\n): boolean {\n if (!fs.existsSync(jsPath)) return false\n const metadata = readCacheMetadata(metadataPath)\n if (!metadata || metadata.inputHash !== expectedInputHash) return false\n return contentHash(fs.readFileSync(jsPath)) === metadata.outputHash\n && dependenciesAreValid(appRoot, metadata.dependencies)\n}\n\n/**\n * Options for `compileAndImport`.\n *\n * Both paths default to the generated-registry layout (`<appRoot>/.mercato/generated/<file>.ts`\n * compiled to a `.mjs` sibling). Sources that live elsewhere in the app \u2014 `src/di.ts` \u2014 MUST pass\n * both explicitly: the default app root is derived by walking three directories up from the source,\n * which only holds inside `.mercato/generated`.\n */\ntype CompileAndImportOptions = {\n appRoot?: string\n outFile?: string\n allowRecovery?: boolean\n}\n\n/**\n * Options for `compileAppSourceFile`.\n *\n * `appRoot` anchors the tsconfig, the `@/` alias resolution and the dependency\n * cache; `outFile` is the absolute path of the artifact to write. `format`\n * selects the module system of that artifact \u2014 `'cjs'` exists for the Jest\n * runtime, which cannot `import()` an ESM sibling.\n */\nexport type CompileAppSourceOptions = {\n appRoot: string\n outFile: string\n format?: 'esm' | 'cjs'\n}\n\n/**\n * Compile one app-owned TypeScript source and its relative import graph into a\n * single JavaScript artifact, leaving every package import external.\n *\n * This is the only supported way to load app source (`apps/<app>/src/**`,\n * `.mercato/generated/**`) from a plain Node process. Those files are never\n * compiled to `dist`, and Node's own type stripping cannot load them: it\n * requires explicit file extensions on relative specifiers and rejects the\n * decorator and enum syntax the entities and DI files use.\n *\n * The artifact is cached against the content of the entry, its whole bundled\n * dependency graph, and the tsconfig chain, so an edit anywhere in the graph\n * invalidates it.\n *\n * The build runs inside the shared esbuild lifecycle. Callers outside a\n * bootstrap load \u2014 the generated-registry loader compiling an `@app` module \u2014\n * would otherwise hold a build on a service another scope is entitled to\n * `stop()`, and would leave the helper process running afterwards. Nesting is\n * safe: the scope only releases the service when the last participant exits.\n */\nexport async function compileAppSourceFile(\n tsPath: string,\n options: CompileAppSourceOptions,\n): Promise<string> {\n return withEsbuildLifecycle(() => compileAppSourceFileWithActiveEsbuild(tsPath, options))\n}\n\nasync function compileAppSourceFileWithActiveEsbuild(\n tsPath: string,\n options: CompileAppSourceOptions,\n): Promise<string> {\n const { appRoot, outFile } = options\n const format = options.format ?? 'esm'\n const appTsconfig = path.join(appRoot, 'tsconfig.json')\n const metadataPath = cacheMetadataPath(outFile)\n\n const tsExists = fs.existsSync(tsPath)\n const tsconfigExists = fs.existsSync(appTsconfig)\n\n if (!tsExists) {\n throw new GeneratedFileNotFoundError(tsPath)\n }\n if (!tsconfigExists) {\n throw new Error(`App TypeScript config not found: ${appTsconfig}`)\n }\n\n const tsconfigPaths = collectTsconfigPaths(appTsconfig)\n const expectedInputHash = cacheInputHash(tsPath, appRoot, tsconfigPaths)\n\n if (cacheIsValid(appRoot, outFile, metadataPath, expectedInputHash)) {\n return outFile\n }\n\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n // Dynamically import esbuild only when needed\n const esbuild = await getEsbuildRuntime()\n\n const rewrittenPackageManifests = new Set<string>()\n // Use esbuild.build with bundling to handle JSON imports\n const result = await esbuild.build({\n entryPoints: [tsPath],\n outfile: outFile,\n absWorkingDir: appRoot,\n bundle: true,\n metafile: true,\n format,\n platform: 'node',\n target: 'node18',\n tsconfig: appTsconfig,\n plugins: createCliBundlePlugins(appRoot, {\n onLegacySubpathRewrite: (manifestPath) => rewrittenPackageManifests.add(manifestPath),\n }),\n // Allow JSON imports\n loader: { '.json': 'json' },\n })\n const metadata: DynamicLoaderCacheMetadata = {\n version: DYNAMIC_LOADER_CACHE_VERSION,\n inputHash: expectedInputHash,\n outputHash: contentHash(fs.readFileSync(outFile)),\n dependencies: {\n ...collectDependencyHashes(appRoot, result.metafile.inputs),\n ...hashFilesRelativeTo(appRoot, tsconfigPaths),\n ...hashFilesRelativeTo(appRoot, [...rewrittenPackageManifests]),\n },\n }\n fs.writeFileSync(metadataPath, JSON.stringify(metadata))\n\n return outFile\n}\n\n/**\n * Compile a TypeScript file to JavaScript using esbuild bundler.\n * This bundles the file and all its dependencies, handling JSON imports properly.\n * The compiled file is written next to the source file with a .mjs extension unless\n * `outFile` says otherwise.\n */\nasync function compileAndImport(\n tsPath: string,\n options: CompileAndImportOptions = {},\n): Promise<Record<string, unknown>> {\n const allowRecovery = options.allowRecovery ?? true\n const jsPath = options.outFile ?? tsPath.replace(/\\.ts$/, '.mjs')\n const appRoot = options.appRoot ?? path.dirname(path.dirname(path.dirname(tsPath)))\n\n await compileAppSourceFile(tsPath, { appRoot, outFile: jsPath })\n\n // Import the compiled JavaScript\n try {\n const outputHash = contentHash(fs.readFileSync(jsPath))\n const fileUrl = `${pathToFileURL(jsPath).href}?cache=${outputHash}`\n return await import(fileUrl)\n } catch (error) {\n if (!allowRecovery) {\n throw error\n }\n\n const recovered = recoverMikroOrmV7GeneratedCacheFromImportError(appRoot, error)\n if (!recovered.applied) {\n throw error\n }\n\n return compileAndImport(tsPath, { ...options, allowRecovery: false })\n }\n}\n\n\n/**\n * Registers an app-owned generated value on the request container.\n *\n * The app registers these statically from `src/di.ts`, which `createRequestContainer`\n * reaches through the `@/` alias \u2014 and that alias only exists under the bundler.\n * A CLI or MCP process runs plain Node, so the import fails, the failure is\n * swallowed, and the value is simply absent with no diagnostic. Routing it through\n * a registrar built from the same generated file keeps both processes in step.\n */\nfunction appValueRegistrar(key: string, value: unknown): BootstrapData['diRegistrars'][number] {\n return (container) => {\n container.register({ [key]: asValue(value) })\n }\n}\n\n/**\n * Load a generated registry that older apps may not have generated yet.\n *\n * An absent source file is the supported compatibility case and resolves to\n * `fallback` quietly. Any other failure \u2014 a compile error, a broken import, a\n * runtime throw at module scope \u2014 still resolves to `fallback` so bootstrap\n * keeps working, but is reported at error level: a registry that silently\n * degrades to nothing is exactly how command interceptors stopped applying in\n * worker/CLI processes (#4327, #4491).\n */\nasync function loadOptionalGeneratedModule(\n tsPath: string,\n fallback: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n try {\n return await compileAndImport(tsPath)\n } catch (error) {\n if (error instanceof GeneratedFileNotFoundError) {\n logger.debug('Optional generated registry not present, using empty fallback', {\n file: path.basename(tsPath),\n })\n return fallback\n }\n\n logger.error('Failed to load generated registry, continuing without its entries', {\n file: path.basename(tsPath),\n filePath: tsPath,\n err: error,\n })\n return fallback\n }\n}\n\nfunction resolveAppRootOrThrow(appRoot?: string): AppRoot {\n const resolved: AppRoot | null = appRoot\n ? {\n generatedDir: path.join(appRoot, '.mercato', 'generated'),\n appDir: appRoot,\n mercatoDir: path.join(appRoot, '.mercato'),\n }\n : findAppRoot()\n\n if (!resolved) {\n throw new Error(\n 'Could not find app root with .mercato/generated directory. ' +\n 'Make sure you run this command from within a Next.js app directory, ' +\n 'or run \"yarn mercato generate\" first to create the generated files.',\n )\n }\n\n return resolved\n}\n\n/**\n * Load the app-level DI registrar (`src/di.ts`) for the dynamic bootstrap path.\n *\n * The Next.js runtime imports `@/di` statically from its own `src/bootstrap.ts` and hands the\n * registrar to `createBootstrap`. Worker, scheduler and CLI processes bootstrap through\n * `bootstrapFromAppRoot` instead, where the `@/` alias does not exist \u2014 so without this the app's\n * DI registrations silently never ran there, and every request container paid a failed\n * `import('@/di')` resolution (the compatibility fallback in `lib/di/container.ts`).\n *\n * An absent `src/di.ts` is the supported case and resolves to `null` quietly. A file that exists\n * but cannot be compiled, imported, or does not export `register` is reported at error level and\n * still resolves to `null`, so a broken app DI module degrades the same way a broken generated\n * registry does (#4327, #4491) instead of taking the whole process down.\n */\nasync function loadAppDiRegistrar(appDir: string): Promise<AppDiRegistrar | null> {\n const tsPath = path.join(appDir, 'src', 'di.ts')\n if (!fs.existsSync(tsPath)) {\n logger.debug('App-level DI module not present, skipping its registrations', { filePath: tsPath })\n return null\n }\n\n try {\n const appDiModule = await compileAndImport(tsPath, {\n appRoot: appDir,\n outFile: path.join(appDir, '.mercato', 'generated', 'app-di.compiled.mjs'),\n })\n const register = appDiModule.register\n if (typeof register !== 'function') {\n logger.error('App-level DI module exports no register(); its registrations are skipped', {\n filePath: tsPath,\n })\n return null\n }\n return register as AppDiRegistrar\n } catch (error) {\n logger.error('Failed to load the app-level DI module; its registrations are skipped', {\n filePath: tsPath,\n err: error,\n })\n return null\n }\n}\n\n/**\n * Override domains whose applier is not registered by `registerBuiltInModuleOverrideAppliers()`\n * but by importing a domain package for its side effect. `bootstrap-common.ts` does this with a\n * static import right before it dispatches; the dynamic bootstrap path has no bundler to lean on,\n * so it resolves the same modules here \u2014 lazily, and only when an app actually declares the\n * domain, so `@open-mercato/shared` keeps its rule of never taking a runtime dependency on a\n * domain package (soft-optional coupling, `packages/core/AGENTS.md` \u2192 Cross-Module Coupling).\n */\nconst OPTIONAL_OVERRIDE_APPLIER_MODULES: Record<string, string> = {\n ai: '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-overrides',\n}\n\n/**\n * Import the side-effect module that registers the applier for every declared override domain\n * that has no built-in one. A domain package the app does not install is not an error \u2014 there\n * is nothing for that domain to apply to \u2014 so a failed resolution is logged and skipped, and the\n * dispatcher's own \"domain not yet wired\" warning still fires behind it.\n */\nasync function ensureOptionalOverrideAppliers(enabledModules: ModuleEntryWithOverrides[]): Promise<void> {\n for (const [domain, specifier] of Object.entries(OPTIONAL_OVERRIDE_APPLIER_MODULES)) {\n const declared = enabledModules.some((entry) => {\n const overrides = entry?.overrides as Record<string, unknown> | undefined\n return Boolean(overrides && overrides[domain])\n })\n if (!declared) continue\n try {\n await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ specifier)\n } catch (error) {\n logger.debug('Optional override applier module is not installed; the domain has nothing to apply to', {\n domain,\n specifier,\n err: error,\n })\n }\n }\n}\n\n/**\n * Dispatch `entry.overrides` declared in the app's `src/modules.ts` for the dynamic\n * bootstrap path.\n *\n * The Next.js runtime imports `enabledModules` statically from its own `src/modules.ts` and\n * calls `applyModuleOverridesFromEnabledModules` from `bootstrap-common.ts` before any registry\n * first-loads. Worker, scheduler and CLI processes bootstrap through `bootstrapFromAppRoot`\n * instead, which only ever compiled the generated `modules.cli.generated.ts` \u2014 so an app's\n * `entry.overrides` (encryption maps, ACL features, CLI commands, workers, event subscribers,\n * setup, \u2026) silently never applied there. `seed-encryption` seeding the base encryption maps\n * instead of the app's `overrides.encryption.maps` was the concrete symptom (#5582).\n *\n * An app layout with no `src/modules.ts` at all is logged and skipped \u2014 that is a real\n * compatibility case, handled the same way an absent `src/di.ts` is. A file that is *present*\n * but fails to compile or import is not: it throws, matching how this same function treats\n * every other mandatory input and how the Next.js runtime treats this same file (a static\n * import in `bootstrap-common.ts`). Degrading there would put `seed-encryption` back on the\n * base encryption maps while still printing success \u2014 #5582's outcome, only quieter.\n */\nasync function loadAppModuleOverrides(appDir: string): Promise<void> {\n const tsPath = path.join(appDir, 'src', 'modules.ts')\n if (!fs.existsSync(tsPath)) {\n logger.debug('App-level modules file not present, skipping entry.overrides dispatch', { filePath: tsPath })\n return\n }\n\n let enabledModules: unknown\n try {\n const appModulesModule = await compileAndImport(tsPath, {\n appRoot: appDir,\n outFile: path.join(appDir, '.mercato', 'generated', 'app-modules-overrides.compiled.mjs'),\n })\n enabledModules = appModulesModule.enabledModules\n } catch (error) {\n throw new Error(\n `[internal] Failed to load the app-level modules file (${tsPath}); entry.overrides cannot be applied. ` +\n 'Refusing to bootstrap with a partial override set.',\n { cause: error },\n )\n }\n\n if (!Array.isArray(enabledModules)) {\n throw new Error(\n `[internal] The app-level modules file (${tsPath}) exports no enabledModules array; ` +\n 'entry.overrides cannot be applied. Refusing to bootstrap with a partial override set.',\n )\n }\n\n await ensureOptionalOverrideAppliers(enabledModules as ModuleEntryWithOverrides[])\n applyModuleOverridesFromEnabledModules(enabledModules as ModuleEntryWithOverrides[])\n}\n\n/**\n * Dynamically load bootstrap data from a resolved app directory.\n *\n * IMPORTANT: This only works in unbundled contexts (CLI, tsx).\n * Do NOT use this in Next.js bundled code - use static imports instead.\n *\n * For CLI context, we skip loading modules.generated.ts which has Next.js dependencies.\n * CLI commands are discovered separately via the CLI module system.\n *\n * @param appRoot - Optional explicit app root path. If not provided, will search from cwd.\n * @returns The loaded bootstrap data\n * @throws Error if app root cannot be found or generated files are missing\n */\nasync function loadBootstrapDataWithActiveEsbuild(appRoot?: string): Promise<BootstrapData> {\n const resolved = resolveAppRootOrThrow(appRoot)\n\n const { generatedDir } = resolved\n\n ensureMikroOrmV7GeneratedCacheCompatibility(resolved.appDir)\n\n // IMPORTANT: Load entity IDs FIRST and register them before loading modules.\n // This is because modules (e.g., ce.ts files) use E.xxx.xxx at module scope,\n // and they need entity IDs to be available when they're imported.\n const entityIdsModule = await compileAndImport(path.join(generatedDir, 'entities.ids.generated.ts'))\n registerEntityIds(entityIdsModule.E as BootstrapData['entityIds'])\n\n // Now load the rest of the generated files.\n // modules.cli.generated.ts excludes Next.js-dependent code (routes, APIs, widgets)\n const [\n modulesModule,\n entitiesModule,\n diModule,\n searchModule,\n commandLoadersModule,\n webResearchModule,\n commandInterceptorsModule,\n workflowsModule,\n ] = await Promise.all([\n compileAndImport(path.join(generatedDir, 'modules.cli.generated.ts')),\n compileAndImport(path.join(generatedDir, 'entities.generated.ts')),\n compileAndImport(path.join(generatedDir, 'di.generated.ts')),\n loadOptionalGeneratedModule(path.join(generatedDir, 'search.generated.ts'), { searchModuleConfigs: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-loaders.generated.ts'), { commandLoaderEntries: [] }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'web-research-adapters.generated.ts'), {\n webResearchAdapterEntries: [],\n }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'command-interceptors.generated.ts'), {\n commandInterceptorEntries: [],\n }),\n loadOptionalGeneratedModule(path.join(generatedDir, 'workflows.generated.ts'), { allCodeWorkflows: [] }),\n ])\n\n return {\n modules: modulesModule.modules as BootstrapData['modules'],\n entities: entitiesModule.entities as BootstrapData['entities'],\n diRegistrars: [\n ...(diModule.diRegistrars as BootstrapData['diRegistrars']),\n appValueRegistrar('webResearchAdapterEntries', webResearchModule.webResearchAdapterEntries ?? []),\n ],\n entityIds: entityIdsModule.E as BootstrapData['entityIds'],\n // Search configs are needed by workers for indexing\n searchModuleConfigs: (searchModule.searchModuleConfigs ?? []) as BootstrapData['searchModuleConfigs'],\n commandLoaderEntries: (commandLoadersModule.commandLoaderEntries ?? []) as BootstrapData['commandLoaderEntries'],\n // Command interceptors must apply in worker/CLI processes too \u2014 the\n // interceptor registry is per-process, so relying on the Next.js runtime's\n // registration silently no-ops every interceptor for queued/CLI commands\n // (#4327).\n commandInterceptorEntries: (commandInterceptorsModule.commandInterceptorEntries ??\n []) as BootstrapData['commandInterceptorEntries'],\n // Code workflow definitions are needed by workers to resume code-defined instances\n codeWorkflows: (workflowsModule.allCodeWorkflows ?? []) as BootstrapData['codeWorkflows'],\n // Empty UI-related data - not needed for CLI\n dashboardWidgetEntries: [],\n injectionWidgetEntries: [],\n injectionTables: [],\n interceptorEntries: [],\n componentOverrideEntries: [],\n }\n}\n\nexport async function loadBootstrapData(appRoot?: string): Promise<BootstrapData> {\n return withEsbuildLifecycle(() => loadBootstrapDataWithActiveEsbuild(appRoot))\n}\n\n/**\n * Create and execute bootstrap in CLI context.\n *\n * This is a convenience function that finds the app root, loads the generated\n * data dynamically, and runs bootstrap. Use this in CLI entry points.\n *\n * Returns the loaded bootstrap data so the CLI can register modules directly\n * (avoids module resolution issues when importing @open-mercato/cli/mercato).\n *\n * @param appRoot - Optional explicit app root path\n * @returns The loaded bootstrap data (modules, entities, etc.)\n */\nexport async function bootstrapFromAppRoot(appRoot?: string): Promise<BootstrapData> {\n const { createBootstrap, waitForAsyncRegistration } = await import('./factory.js')\n const resolved = resolveAppRootOrThrow(appRoot)\n // All three loads compile through esbuild, so they share one lifecycle scope: without it\n // `loadBootstrapData` releases the esbuild helper process and `loadAppDiRegistrar`\n // silently starts a second one that nothing ever stops.\n const { data, appDiRegistrar } = await withEsbuildLifecycle(async () => {\n // Dispatch the app's `entry.overrides` (src/modules.ts) BEFORE any registry\n // first-loads \u2014 the `bootstrap()` call below runs `registerModules(data.modules)`,\n // and `registerCliModules` in the mercato bin right after this function returns;\n // both read the override side-registry this populates.\n await loadAppModuleOverrides(resolved.appDir)\n return {\n data: await loadBootstrapData(resolved.appDir),\n appDiRegistrar: await loadAppDiRegistrar(resolved.appDir),\n }\n })\n const bootstrap = createBootstrap(data, appDiRegistrar ? { appDiRegistrar } : {})\n bootstrap()\n // In CLI context, wait for async registrations (UI widgets, search configs, etc.)\n await waitForAsyncRegistration()\n\n return data\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/bootstrap/next-subpath-resolve-hook-worker.ts"],
|
|
4
|
+
"sourcesContent": ["import { resolveNextSubpathAsync } from './next-subpath-resolve-hook'\n\nexport const resolve = resolveNextSubpathAsync\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,+BAA+B;AAEjC,MAAM,UAAU;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as nodeModule from "node:module";
|
|
2
|
+
const NEXT_BARE_SUBPATH = /^next\/[A-Za-z0-9_-]+$/;
|
|
3
|
+
let installed = false;
|
|
4
|
+
function isModuleNotFound(error) {
|
|
5
|
+
return Boolean(error) && typeof error === "object" && error.code === "ERR_MODULE_NOT_FOUND";
|
|
6
|
+
}
|
|
7
|
+
function resolveNextSubpath(specifier, context, nextResolve) {
|
|
8
|
+
if (!NEXT_BARE_SUBPATH.test(specifier)) return nextResolve(specifier, context);
|
|
9
|
+
try {
|
|
10
|
+
return nextResolve(specifier, context);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (!isModuleNotFound(error)) throw error;
|
|
13
|
+
try {
|
|
14
|
+
return nextResolve(`${specifier}.js`, context);
|
|
15
|
+
} catch {
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function resolveNextSubpathAsync(specifier, context, nextResolve) {
|
|
21
|
+
if (!NEXT_BARE_SUBPATH.test(specifier)) return nextResolve(specifier, context);
|
|
22
|
+
try {
|
|
23
|
+
return await nextResolve(specifier, context);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (!isModuleNotFound(error)) throw error;
|
|
26
|
+
try {
|
|
27
|
+
return await nextResolve(`${specifier}.js`, context);
|
|
28
|
+
} catch {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function runtimeRegisterHooks() {
|
|
34
|
+
const candidate = nodeModule.registerHooks;
|
|
35
|
+
return typeof candidate === "function" ? candidate : void 0;
|
|
36
|
+
}
|
|
37
|
+
function runtimeRegisterHookModule() {
|
|
38
|
+
const candidate = nodeModule.register;
|
|
39
|
+
return typeof candidate === "function" ? candidate : void 0;
|
|
40
|
+
}
|
|
41
|
+
function installNextSubpathResolveHook(registerHooks = runtimeRegisterHooks(), registerHookModule = runtimeRegisterHookModule()) {
|
|
42
|
+
if (installed) return false;
|
|
43
|
+
if (typeof registerHooks === "function") {
|
|
44
|
+
registerHooks({ resolve: resolveNextSubpath });
|
|
45
|
+
} else if (typeof registerHookModule === "function") {
|
|
46
|
+
registerHookModule(new URL("./next-subpath-resolve-hook-worker.js", import.meta.url), import.meta.url);
|
|
47
|
+
} else {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
installed = true;
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
function resetNextSubpathResolveHookForTests() {
|
|
54
|
+
installed = false;
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
installNextSubpathResolveHook,
|
|
58
|
+
resetNextSubpathResolveHookForTests,
|
|
59
|
+
resolveNextSubpath,
|
|
60
|
+
resolveNextSubpathAsync
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=next-subpath-resolve-hook.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/bootstrap/next-subpath-resolve-hook.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Node ESM resolution for `next/<subpath>` outside the Next bundler (#6118, #7102).\n *\n * Installed by the `mercato` CLI entry, so every CLI command and worker it\n * runs can load package dists that import `next/dynamic`, `next/link`,\n * `next/server` \u2026 The `next/dynamic` imports in particular MUST keep the bare\n * specifier: Next's `next_dynamic` compiler transform only matches it exactly.\n *\n * `mercato ai_assistant mcp:serve-http` (and `mcp:serve`, `mcp:dev`,\n * `mcp:list-tools`) run in plain Node, and the AI API operation runner loads\n * API route modules with a runtime `import()`. Those modules import\n * `NextResponse` from `'next/server'`: a bare package subpath that only a\n * bundler resolves, because `next` ships no `exports` map and Node's ESM\n * resolver does no extension guessing. Every route with that import (287 of\n * them on the 0.7.0 packages) therefore fails to load with\n * `ERR_MODULE_NOT_FOUND \u2026 node_modules/next/server`, and every tool backed by\n * such a route returns \"Failed to load route module\".\n *\n * `next/server.js`, `next/headers.js`, `next/navigation.js` \u2026 do exist as files,\n * which is why `@open-mercato/shared` imports `'next/headers.js'`. Rather than\n * rewriting several hundred imports across every package (and every\n * third-party module), this hook retries a failed bare `next/<subpath>` with\n * the `.js` suffix. It only runs in the processes that install it, only for\n * `next/*` specifiers, and only after the normal resolution failed, so it\n * becomes a no-op the day `next` publishes an `exports` map.\n */\nimport * as nodeModule from 'node:module'\n\ntype ResolveContext = Record<string, unknown>\ntype ResolveResult = { url: string; format?: string | null | undefined; shortCircuit?: boolean }\ntype NextResolve = (specifier: string, context?: ResolveContext) => ResolveResult\ntype AsyncNextResolve = (specifier: string, context?: ResolveContext) => ResolveResult | Promise<ResolveResult>\n\n/** Bare `next/<one segment>` specifiers, e.g. `next/server`, `next/headers`. */\nconst NEXT_BARE_SUBPATH = /^next\\/[A-Za-z0-9_-]+$/\n\nlet installed = false\n\nfunction isModuleNotFound(error: unknown): boolean {\n return Boolean(error) && typeof error === 'object' && (error as { code?: unknown }).code === 'ERR_MODULE_NOT_FOUND'\n}\n\n/**\n * The resolve hook itself. Exported so it can be tested without touching the\n * process-global hook chain.\n */\nexport function resolveNextSubpath(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve,\n): ResolveResult {\n if (!NEXT_BARE_SUBPATH.test(specifier)) return nextResolve(specifier, context)\n try {\n return nextResolve(specifier, context)\n } catch (error) {\n if (!isModuleNotFound(error)) throw error\n try {\n return nextResolve(`${specifier}.js`, context)\n } catch {\n // Neither form resolves (Next is not installed at all): surface the\n // original error, which names the specifier the caller wrote.\n throw error\n }\n }\n}\n\nexport async function resolveNextSubpathAsync(\n specifier: string,\n context: ResolveContext,\n nextResolve: AsyncNextResolve,\n): Promise<ResolveResult> {\n if (!NEXT_BARE_SUBPATH.test(specifier)) return nextResolve(specifier, context)\n try {\n return await nextResolve(specifier, context)\n } catch (error) {\n if (!isModuleNotFound(error)) throw error\n try {\n return await nextResolve(`${specifier}.js`, context)\n } catch {\n throw error\n }\n }\n}\n\ntype RegisterHooks = (hooks: { resolve: typeof resolveNextSubpath }) => unknown\ntype RegisterHookModule = (specifier: string | URL, parentURL?: string | URL) => unknown\n\n/**\n * `module.registerHooks` exists from Node 22.15. It is read off the namespace\n * rather than imported by name: in the published ESM build a named import of an\n * export the running Node lacks fails while the module links, before the check\n * in `installNextSubpathResolveHook` can run, and the package still declares\n * `node >= 22.0.0`.\n */\nfunction runtimeRegisterHooks(): RegisterHooks | undefined {\n const candidate = (nodeModule as unknown as { registerHooks?: unknown }).registerHooks\n return typeof candidate === 'function' ? (candidate as RegisterHooks) : undefined\n}\n\nfunction runtimeRegisterHookModule(): RegisterHookModule | undefined {\n const candidate = (nodeModule as unknown as { register?: unknown }).register\n return typeof candidate === 'function' ? (candidate as RegisterHookModule) : undefined\n}\n\n/**\n * Install the hook once per process. Returns `true` when it was installed by\n * this call, `false` when it already was or when the runtime has neither\n * registration API. Node 22.15+ uses the synchronous hook API; earlier\n * supported Node 22 releases use the asynchronous hook API.\n */\nexport function installNextSubpathResolveHook(\n registerHooks: RegisterHooks | null | undefined = runtimeRegisterHooks(),\n registerHookModule: RegisterHookModule | null | undefined = runtimeRegisterHookModule(),\n): boolean {\n if (installed) return false\n if (typeof registerHooks === 'function') {\n registerHooks({ resolve: resolveNextSubpath })\n } else if (typeof registerHookModule === 'function') {\n registerHookModule(new URL('./next-subpath-resolve-hook-worker.js', import.meta.url), import.meta.url)\n } else {\n return false\n }\n installed = true\n return true\n}\n\n/** Test seam: forget that the hook was installed. */\nexport function resetNextSubpathResolveHookForTests(): void {\n installed = false\n}\n"],
|
|
5
|
+
"mappings": "AA0BA,YAAY,gBAAgB;AAQ5B,MAAM,oBAAoB;AAE1B,IAAI,YAAY;AAEhB,SAAS,iBAAiB,OAAyB;AACjD,SAAO,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAa,MAA6B,SAAS;AAC/F;AAMO,SAAS,mBACd,WACA,SACA,aACe;AACf,MAAI,CAAC,kBAAkB,KAAK,SAAS,EAAG,QAAO,YAAY,WAAW,OAAO;AAC7E,MAAI;AACF,WAAO,YAAY,WAAW,OAAO;AAAA,EACvC,SAAS,OAAO;AACd,QAAI,CAAC,iBAAiB,KAAK,EAAG,OAAM;AACpC,QAAI;AACF,aAAO,YAAY,GAAG,SAAS,OAAO,OAAO;AAAA,IAC/C,QAAQ;AAGN,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAsB,wBACpB,WACA,SACA,aACwB;AACxB,MAAI,CAAC,kBAAkB,KAAK,SAAS,EAAG,QAAO,YAAY,WAAW,OAAO;AAC7E,MAAI;AACF,WAAO,MAAM,YAAY,WAAW,OAAO;AAAA,EAC7C,SAAS,OAAO;AACd,QAAI,CAAC,iBAAiB,KAAK,EAAG,OAAM;AACpC,QAAI;AACF,aAAO,MAAM,YAAY,GAAG,SAAS,OAAO,OAAO;AAAA,IACrD,QAAQ;AACN,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAYA,SAAS,uBAAkD;AACzD,QAAM,YAAa,WAAsD;AACzE,SAAO,OAAO,cAAc,aAAc,YAA8B;AAC1E;AAEA,SAAS,4BAA4D;AACnE,QAAM,YAAa,WAAiD;AACpE,SAAO,OAAO,cAAc,aAAc,YAAmC;AAC/E;AAQO,SAAS,8BACd,gBAAkD,qBAAqB,GACvE,qBAA4D,0BAA0B,GAC7E;AACT,MAAI,UAAW,QAAO;AACtB,MAAI,OAAO,kBAAkB,YAAY;AACvC,kBAAc,EAAE,SAAS,mBAAmB,CAAC;AAAA,EAC/C,WAAW,OAAO,uBAAuB,YAAY;AACnD,uBAAmB,IAAI,IAAI,yCAAyC,YAAY,GAAG,GAAG,YAAY,GAAG;AAAA,EACvG,OAAO;AACL,WAAO;AAAA,EACT;AACA,cAAY;AACZ,SAAO;AACT;AAGO,SAAS,sCAA4C;AAC1D,cAAY;AACd;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/lib/crud/ids.js
CHANGED
|
@@ -40,6 +40,16 @@ function parseIdsParam(raw, maxIds = MAX_IDS_PER_REQUEST) {
|
|
|
40
40
|
const parsed = normalizeIdList(values);
|
|
41
41
|
return parsed.slice(0, safeMax);
|
|
42
42
|
}
|
|
43
|
+
const UUID_SHAPE_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
44
|
+
function splitIdListParam(raw) {
|
|
45
|
+
if (typeof raw !== "string") return [];
|
|
46
|
+
return raw.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
47
|
+
}
|
|
48
|
+
function isUuidListParam(raw) {
|
|
49
|
+
if (raw === void 0) return true;
|
|
50
|
+
if (typeof raw !== "string") return false;
|
|
51
|
+
return splitIdListParam(raw).every((value) => UUID_SHAPE_REGEX.test(value));
|
|
52
|
+
}
|
|
43
53
|
function isIdsParamProvided(raw) {
|
|
44
54
|
const occurrences = Array.isArray(raw) ? raw : [raw];
|
|
45
55
|
return occurrences.some((value) => typeof value === "string" && value.trim().length > 0);
|
|
@@ -69,7 +79,9 @@ function mergeIdFilter(existingFilters, parsedIds, options) {
|
|
|
69
79
|
export {
|
|
70
80
|
MAX_IDS_PER_REQUEST,
|
|
71
81
|
isIdsParamProvided,
|
|
82
|
+
isUuidListParam,
|
|
72
83
|
mergeIdFilter,
|
|
73
|
-
parseIdsParam
|
|
84
|
+
parseIdsParam,
|
|
85
|
+
splitIdListParam
|
|
74
86
|
};
|
|
75
87
|
//# sourceMappingURL=ids.js.map
|
package/dist/lib/crud/ids.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/crud/ids.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Where } from '@open-mercato/shared/lib/query/types'\nimport { toQueryValueList } from './query-params'\n\nexport const MAX_IDS_PER_REQUEST = 200\n\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\nfunction isUuid(value: unknown): value is string {\n return typeof value === 'string' && UUID_REGEX.test(value)\n}\n\nfunction normalizeIdList(values: string[]): string[] {\n if (values.length === 0) return values\n const deduped = new Set<string>()\n for (const value of values) {\n const trimmed = value.trim()\n if (!trimmed || !isUuid(trimmed)) continue\n deduped.add(trimmed)\n }\n return Array.from(deduped)\n}\n\nfunction readExistingIds(filter: unknown): string[] | null {\n if (typeof filter === 'string') {\n return isUuid(filter) ? [filter] : null\n }\n if (Array.isArray(filter)) {\n return normalizeIdList(\n filter.filter((value): value is string => typeof value === 'string'),\n )\n }\n if (!filter || typeof filter !== 'object') return null\n\n const operators = filter as Record<string, unknown>\n if (isUuid(operators.$eq)) return [operators.$eq]\n\n if (Array.isArray(operators.$in)) {\n return normalizeIdList(\n operators.$in.filter((value): value is string => typeof value === 'string'),\n )\n }\n\n return null\n}\n\nexport function parseIdsParam(raw: unknown, maxIds: number = MAX_IDS_PER_REQUEST): string[] {\n const values = toQueryValueList(raw)\n if (values.length === 0) return []\n const safeMax = Number.isFinite(maxIds) && maxIds > 0 ? Math.floor(maxIds) : MAX_IDS_PER_REQUEST\n const parsed = normalizeIdList(values)\n return parsed.slice(0, safeMax)\n}\n\n/**\n * Whether an `?ids=` param was supplied at all (a non-empty string, or repeated\n * `?ids=` occurrences), regardless of whether any value survived UUID\n * validation. Lets a caller tell \"no ids filter requested\" apart from \"ids\n * filter requested but every value was malformed\" \u2014 the latter must match\n * nothing, not fall back to the full list (#4143 Finding 3).\n */\nexport function isIdsParamProvided(raw: unknown): boolean {\n const occurrences = Array.isArray(raw) ? raw : [raw]\n return occurrences.some((value) => typeof value === 'string' && value.trim().length > 0)\n}\n\nexport function mergeIdFilter<Fields extends Record<string, unknown>>(\n existingFilters: Where<Fields>,\n parsedIds: string[],\n options?: { idsParamProvided?: boolean },\n): Where<Fields> {\n if (parsedIds.length === 0) {\n // The `?ids=` param was supplied but nothing survived UUID validation.\n // Match nothing, mirroring a valid-but-unknown id returning zero rows,\n // rather than silently dropping the filter and returning the full list\n // (record-count side channel \u2014 #4143 Finding 3).\n if (options?.idsParamProvided) {\n return { ...existingFilters, id: { $in: [] } }\n }\n return existingFilters\n }\n\n const existingFilter = (existingFilters as Record<string, unknown>).id\n const existingIds = readExistingIds(existingFilter)\n\n if (!existingIds) {\n // No existing narrowing \u2014 safe to install the user-supplied `$in`.\n if (existingFilter === undefined || existingFilter === null) {\n return { ...existingFilters, id: { $in: parsedIds } }\n }\n // Existing `id` filter is in a shape we do not recognise. Fail closed:\n // preserve the existing filter instead of widening to `parsedIds`. Adding\n // a new recognised shape to `readExistingIds` is preferable to silently\n // dropping a narrowing that another caller put in place.\n return existingFilters\n }\n\n const allowed = new Set(parsedIds)\n const intersection = existingIds.filter((id) => allowed.has(id))\n return {\n ...existingFilters,\n id: { $in: intersection },\n }\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,wBAAwB;AAE1B,MAAM,sBAAsB;AAEnC,MAAM,aAAa;AAEnB,SAAS,OAAO,OAAiC;AAC/C,SAAO,OAAO,UAAU,YAAY,WAAW,KAAK,KAAK;AAC3D;AAEA,SAAS,gBAAgB,QAA4B;AACnD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,SAAS,QAAQ;AAC1B,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,WAAW,CAAC,OAAO,OAAO,EAAG;AAClC,YAAQ,IAAI,OAAO;AAAA,EACrB;AACA,SAAO,MAAM,KAAK,OAAO;AAC3B;AAEA,SAAS,gBAAgB,QAAkC;AACzD,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO,OAAO,MAAM,IAAI,CAAC,MAAM,IAAI;AAAA,EACrC;AACA,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO;AAAA,MACL,OAAO,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAAA,IACrE;AAAA,EACF;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAElD,QAAM,YAAY;AAClB,MAAI,OAAO,UAAU,GAAG,EAAG,QAAO,CAAC,UAAU,GAAG;AAEhD,MAAI,MAAM,QAAQ,UAAU,GAAG,GAAG;AAChC,WAAO;AAAA,MACL,UAAU,IAAI,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAAA,IAC5E;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,KAAc,SAAiB,qBAA+B;AAC1F,QAAM,SAAS,iBAAiB,GAAG;AACnC,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,QAAM,UAAU,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,KAAK,MAAM,MAAM,IAAI;AAC7E,QAAM,SAAS,gBAAgB,MAAM;AACrC,SAAO,OAAO,MAAM,GAAG,OAAO;AAChC;AASO,SAAS,mBAAmB,KAAuB;AACxD,QAAM,cAAc,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG;AACnD,SAAO,YAAY,KAAK,CAAC,UAAU,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,CAAC;AACzF;AAEO,SAAS,cACd,iBACA,WACA,SACe;AACf,MAAI,UAAU,WAAW,GAAG;AAK1B,QAAI,SAAS,kBAAkB;AAC7B,aAAO,EAAE,GAAG,iBAAiB,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAkB,gBAA4C;AACpE,QAAM,cAAc,gBAAgB,cAAc;AAElD,MAAI,CAAC,aAAa;AAEhB,QAAI,mBAAmB,UAAa,mBAAmB,MAAM;AAC3D,aAAO,EAAE,GAAG,iBAAiB,IAAI,EAAE,KAAK,UAAU,EAAE;AAAA,IACtD;AAKA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,IAAI,IAAI,SAAS;AACjC,QAAM,eAAe,YAAY,OAAO,CAAC,OAAO,QAAQ,IAAI,EAAE,CAAC;AAC/D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,IAAI,EAAE,KAAK,aAAa;AAAA,EAC1B;AACF;",
|
|
4
|
+
"sourcesContent": ["import type { Where } from '@open-mercato/shared/lib/query/types'\nimport { toQueryValueList } from './query-params'\n\nexport const MAX_IDS_PER_REQUEST = 200\n\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\nfunction isUuid(value: unknown): value is string {\n return typeof value === 'string' && UUID_REGEX.test(value)\n}\n\nfunction normalizeIdList(values: string[]): string[] {\n if (values.length === 0) return values\n const deduped = new Set<string>()\n for (const value of values) {\n const trimmed = value.trim()\n if (!trimmed || !isUuid(trimmed)) continue\n deduped.add(trimmed)\n }\n return Array.from(deduped)\n}\n\nfunction readExistingIds(filter: unknown): string[] | null {\n if (typeof filter === 'string') {\n return isUuid(filter) ? [filter] : null\n }\n if (Array.isArray(filter)) {\n return normalizeIdList(\n filter.filter((value): value is string => typeof value === 'string'),\n )\n }\n if (!filter || typeof filter !== 'object') return null\n\n const operators = filter as Record<string, unknown>\n if (isUuid(operators.$eq)) return [operators.$eq]\n\n if (Array.isArray(operators.$in)) {\n return normalizeIdList(\n operators.$in.filter((value): value is string => typeof value === 'string'),\n )\n }\n\n return null\n}\n\nexport function parseIdsParam(raw: unknown, maxIds: number = MAX_IDS_PER_REQUEST): string[] {\n const values = toQueryValueList(raw)\n if (values.length === 0) return []\n const safeMax = Number.isFinite(maxIds) && maxIds > 0 ? Math.floor(maxIds) : MAX_IDS_PER_REQUEST\n const parsed = normalizeIdList(values)\n return parsed.slice(0, safeMax)\n}\n\nconst UUID_SHAPE_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n/**\n * Splits a comma-separated id list query param into its trimmed, non-empty entries.\n */\nexport function splitIdListParam(raw: unknown): string[] {\n if (typeof raw !== 'string') return []\n return raw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n}\n\n/**\n * Whether every entry of a comma-separated id list query param is UUID-shaped, so it can be\n * bound to a uuid column without a database error. Use it to reject a malformed or mixed list\n * with a 400 instead of dropping the bad entries and widening the result set (#7265).\n */\nexport function isUuidListParam(raw: unknown): boolean {\n if (raw === undefined) return true\n if (typeof raw !== 'string') return false\n return splitIdListParam(raw).every((value) => UUID_SHAPE_REGEX.test(value))\n}\n\n/**\n * Whether an `?ids=` param was supplied at all (a non-empty string, or repeated\n * `?ids=` occurrences), regardless of whether any value survived UUID\n * validation. Lets a caller tell \"no ids filter requested\" apart from \"ids\n * filter requested but every value was malformed\" \u2014 the latter must match\n * nothing, not fall back to the full list (#4143 Finding 3).\n */\nexport function isIdsParamProvided(raw: unknown): boolean {\n const occurrences = Array.isArray(raw) ? raw : [raw]\n return occurrences.some((value) => typeof value === 'string' && value.trim().length > 0)\n}\n\nexport function mergeIdFilter<Fields extends Record<string, unknown>>(\n existingFilters: Where<Fields>,\n parsedIds: string[],\n options?: { idsParamProvided?: boolean },\n): Where<Fields> {\n if (parsedIds.length === 0) {\n // The `?ids=` param was supplied but nothing survived UUID validation.\n // Match nothing, mirroring a valid-but-unknown id returning zero rows,\n // rather than silently dropping the filter and returning the full list\n // (record-count side channel \u2014 #4143 Finding 3).\n if (options?.idsParamProvided) {\n return { ...existingFilters, id: { $in: [] } }\n }\n return existingFilters\n }\n\n const existingFilter = (existingFilters as Record<string, unknown>).id\n const existingIds = readExistingIds(existingFilter)\n\n if (!existingIds) {\n // No existing narrowing \u2014 safe to install the user-supplied `$in`.\n if (existingFilter === undefined || existingFilter === null) {\n return { ...existingFilters, id: { $in: parsedIds } }\n }\n // Existing `id` filter is in a shape we do not recognise. Fail closed:\n // preserve the existing filter instead of widening to `parsedIds`. Adding\n // a new recognised shape to `readExistingIds` is preferable to silently\n // dropping a narrowing that another caller put in place.\n return existingFilters\n }\n\n const allowed = new Set(parsedIds)\n const intersection = existingIds.filter((id) => allowed.has(id))\n return {\n ...existingFilters,\n id: { $in: intersection },\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,wBAAwB;AAE1B,MAAM,sBAAsB;AAEnC,MAAM,aAAa;AAEnB,SAAS,OAAO,OAAiC;AAC/C,SAAO,OAAO,UAAU,YAAY,WAAW,KAAK,KAAK;AAC3D;AAEA,SAAS,gBAAgB,QAA4B;AACnD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,SAAS,QAAQ;AAC1B,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,WAAW,CAAC,OAAO,OAAO,EAAG;AAClC,YAAQ,IAAI,OAAO;AAAA,EACrB;AACA,SAAO,MAAM,KAAK,OAAO;AAC3B;AAEA,SAAS,gBAAgB,QAAkC;AACzD,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO,OAAO,MAAM,IAAI,CAAC,MAAM,IAAI;AAAA,EACrC;AACA,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO;AAAA,MACL,OAAO,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAAA,IACrE;AAAA,EACF;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAElD,QAAM,YAAY;AAClB,MAAI,OAAO,UAAU,GAAG,EAAG,QAAO,CAAC,UAAU,GAAG;AAEhD,MAAI,MAAM,QAAQ,UAAU,GAAG,GAAG;AAChC,WAAO;AAAA,MACL,UAAU,IAAI,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAAA,IAC5E;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,KAAc,SAAiB,qBAA+B;AAC1F,QAAM,SAAS,iBAAiB,GAAG;AACnC,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,QAAM,UAAU,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,KAAK,MAAM,MAAM,IAAI;AAC7E,QAAM,SAAS,gBAAgB,MAAM;AACrC,SAAO,OAAO,MAAM,GAAG,OAAO;AAChC;AAEA,MAAM,mBAAmB;AAKlB,SAAS,iBAAiB,KAAwB;AACvD,MAAI,OAAO,QAAQ,SAAU,QAAO,CAAC;AACrC,SAAO,IACJ,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AACvC;AAOO,SAAS,gBAAgB,KAAuB;AACrD,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,SAAO,iBAAiB,GAAG,EAAE,MAAM,CAAC,UAAU,iBAAiB,KAAK,KAAK,CAAC;AAC5E;AASO,SAAS,mBAAmB,KAAuB;AACxD,QAAM,cAAc,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG;AACnD,SAAO,YAAY,KAAK,CAAC,UAAU,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,CAAC;AACzF;AAEO,SAAS,cACd,iBACA,WACA,SACe;AACf,MAAI,UAAU,WAAW,GAAG;AAK1B,QAAI,SAAS,kBAAkB;AAC7B,aAAO,EAAE,GAAG,iBAAiB,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAkB,gBAA4C;AACpE,QAAM,cAAc,gBAAgB,cAAc;AAElD,MAAI,CAAC,aAAa;AAEhB,QAAI,mBAAmB,UAAa,mBAAmB,MAAM;AAC3D,aAAO,EAAE,GAAG,iBAAiB,IAAI,EAAE,KAAK,UAAU,EAAE;AAAA,IACtD;AAKA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,IAAI,IAAI,SAAS;AACjC,QAAM,eAAe,YAAY,OAAO,CAAC,OAAO,QAAQ,IAAI,EAAE,CAAC;AAC/D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,IAAI,EAAE,KAAK,aAAa;AAAA,EAC1B;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|