@happyvertical/smrt-core 0.37.0 → 0.37.1
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/dist/consumer-plugin/index.js.map +1 -1
- package/dist/manifest/discover-smrt-packages.d.ts +10 -0
- package/dist/manifest/discover-smrt-packages.d.ts.map +1 -1
- package/dist/manifest/discover-smrt-packages.js.map +1 -1
- package/dist/manifest/generator.d.ts.map +1 -1
- package/dist/manifest/generator.js +34 -37
- package/dist/manifest/generator.js.map +1 -1
- package/dist/manifest/index.js +2 -2
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/manifest-loader.d.ts +10 -0
- package/dist/manifest/manifest-loader.d.ts.map +1 -1
- package/dist/manifest/manifest-loader.js.map +1 -1
- package/dist/manifest/static-manifest.js +2 -2
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +2 -2
- package/dist/manifest/test-manifest-stub.js +2 -2
- package/dist/manifest/test-manifest-stub.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/migrations/differ.d.ts +104 -13
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +199 -26
- package/dist/migrations/differ.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/ast.js +1 -7
- package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/ast.js.map +1 -0
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/index.js +17 -14
- package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/index.js.map +1 -0
- package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/unescape.js +10 -0
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +22 -20
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/smrt-knowledge.json +7 -7
- package/dist/vite-plugin/index.js +1 -1
- package/package.json +7 -7
- package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js.map +0 -1
- package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js.map +0 -1
- package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js +0 -10
- /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js +0 -0
- /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js +0 -0
- /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sources":["../../src/manifest/generator.ts"],"sourcesContent":["/**\n * Manifest generation orchestrator\n * Consolidates manifest generation logic for both build and test manifests\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, isAbsolute, relative, resolve } from 'node:path';\nimport fg from 'fast-glob';\nimport { ManifestGenerator } from '../scanner/manifest-generator.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\nimport { importWorkspaceModule } from '../utils/import-workspace-module.js';\nimport type { ScannerModule } from '../utils/scanner-module.js';\nimport {\n discoverSmrtPackages,\n resolveManifestPath,\n} from './discover-smrt-packages.js';\nimport { ManifestManager } from './manager.js';\n\nasync function importScanner() {\n return importWorkspaceModule<ScannerModule>({\n packageName: '@happyvertical/smrt-scanner',\n distEntry: 'packages/scanner/dist/index.js',\n sourceEntry: 'packages/scanner/src/index.ts',\n purpose: 'manifest generation',\n });\n}\n\n/**\n * Options for ManifestBuilder.generate()\n *\n * Controls file discovery, scanner configuration, output generation, and metadata injection\n */\nexport interface ManifestBuilderOptions {\n // File Discovery\n include?: string[];\n exclude?: string[];\n followImports?: boolean;\n\n // Scanner Configuration\n baseClasses?: string[];\n loadViteConfig?: boolean;\n discoverExternalPackages?: boolean;\n includeExternalBaseClasses?: boolean;\n includePrivateMethods?: boolean;\n includeStaticMethods?: boolean;\n\n // Output Configuration\n outputDir?: string;\n outputName?: string;\n generateTypeStub?: boolean;\n stubName?: string;\n\n // Metadata\n injectPackageInfo?: boolean;\n moduleType?: string;\n\n // Tree Shaking (External Object Filtering)\n /**\n * @deprecated Tree shaking is no longer needed. The AST scanner no longer includes external objects in the manifest by default.\n */\n treeShake?: boolean;\n\n /**\n * @deprecated Whitelists are no longer needed. The AST scanner no longer includes external objects in the manifest by default.\n */\n externalObjectsWhitelist?: string[];\n}\n\ninterface ScannerConfig {\n baseClasses: string[];\n includePrivateMethods: boolean;\n includeStaticMethods: boolean;\n followImports: boolean;\n smrtDependencies?: string[];\n}\n\ninterface PackageInfo {\n name?: string;\n version?: string;\n}\n\n/**\n * Subset of the smrt-auto-service Vite plugin options we probe when reading\n * baseClasses out of a project's vite.config.ts.\n */\ninterface VitePluginOptions {\n baseClasses?: string[];\n followImports?: boolean;\n}\n\n/**\n * Structural shape of a loaded Vite plugin entry as probed by\n * loadViteConfigBaseClasses(). The plugin may expose its options directly, on\n * `_options`, or via an `api` object/function — all optional and discovered at\n * runtime, so each is modeled as optional here.\n */\ninterface VitePluginProbe {\n name?: string;\n options?: VitePluginOptions;\n _options?: VitePluginOptions;\n api?:\n | { options?: VitePluginOptions }\n | (() => { options?: VitePluginOptions });\n}\n\n/**\n * Orchestrates manifest generation with configurable options\n *\n * Consolidates logic from generate-manifest.js and generate-test-manifest.js\n * into a single, testable, and maintainable service.\n */\nexport class ManifestBuilder {\n /**\n * Generate manifest with specified options\n */\n async generate(\n options: ManifestBuilderOptions = {},\n ): Promise<SmartObjectManifest> {\n // 1. Discover files to scan\n const files = this.discoverFiles(options);\n\n if (files.length === 0) {\n console.log('[smrt] No source files found');\n return this.createEmptyManifest(options);\n }\n\n console.log(`[smrt] Scanning ${files.length} source file(s)...`);\n\n // 2. Configure scanner (baseClasses, external packages, vite config)\n const scannerConfig = await this.configureScanner(options);\n\n // 3. Scan files with OXC scanner\n const scannedManifest = await this.scanAndBuildManifest(\n scannerConfig,\n options,\n );\n\n // 4. Enrich manifest with metadata (smrtDependencies, packageInfo)\n const manifest = this.enrichManifest(\n scannedManifest,\n options,\n scannerConfig,\n );\n\n // 5. Write output files\n this.normalizeFilePaths(manifest);\n await this.writeOutput(manifest, options);\n\n return manifest;\n }\n\n private normalizeFilePaths(manifest: SmartObjectManifest): void {\n const workspaceRoot = this.findWorkspaceRoot(process.cwd());\n\n for (const obj of Object.values(manifest.objects || {})) {\n if (obj.filePath && isAbsolute(obj.filePath)) {\n obj.filePath = relative(workspaceRoot, obj.filePath).replace(\n /\\\\/g,\n '/',\n );\n }\n }\n }\n\n private findWorkspaceRoot(startDir: string): string {\n let current = resolve(startDir);\n\n while (true) {\n if (\n existsSync(resolve(current, 'pnpm-workspace.yaml')) ||\n existsSync(resolve(current, '.git'))\n ) {\n return current;\n }\n\n const parent = dirname(current);\n if (parent === current) {\n return resolve(startDir);\n }\n current = parent;\n }\n }\n\n /**\n * Discover source files based on include/exclude patterns\n */\n private discoverFiles(options: ManifestBuilderOptions): string[] {\n const include = options.include || ['src/**/*.ts'];\n const exclude = options.exclude || ['src/**/*.d.ts', 'node_modules/**'];\n\n return fg.sync(include, {\n absolute: true,\n ignore: exclude,\n });\n }\n\n /**\n * Configure AST scanner with baseClasses, external packages, and vite config\n */\n private async configureScanner(\n options: ManifestBuilderOptions,\n ): Promise<ScannerConfig> {\n let baseClasses = options.baseClasses || [\n 'SmrtObject',\n 'SmrtClass',\n 'SmrtCollection',\n ];\n\n // Load from vite.config.ts if requested\n if (options.loadViteConfig) {\n const viteBaseClasses = await this.loadViteConfigBaseClasses();\n if (viteBaseClasses && viteBaseClasses.length > 0) {\n baseClasses = viteBaseClasses;\n console.log(\n `[smrt] Using baseClasses from vite.config.ts: ${baseClasses.join(', ')}`,\n );\n }\n }\n\n // Discover external SMRT packages\n let smrtDependencies: string[] = [];\n if (options.discoverExternalPackages) {\n console.log('[smrt] Discovering external SMRT packages...');\n smrtDependencies = discoverSmrtPackages();\n console.log(\n `[smrt] Found ${smrtDependencies.length} SMRT package(s): ${smrtDependencies.join(', ')}`,\n );\n\n // Optionally add external base classes\n if (options.includeExternalBaseClasses) {\n const externalClasses =\n await this.loadExternalBaseClasses(smrtDependencies);\n if (externalClasses.length > 0) {\n baseClasses = [...baseClasses, ...externalClasses];\n console.log(\n `[smrt] Added ${externalClasses.length} external base class(es) to scanner`,\n );\n console.log(`[smrt] Total baseClasses: ${baseClasses.length}`);\n }\n }\n }\n\n return {\n baseClasses,\n includePrivateMethods: options.includePrivateMethods ?? false,\n includeStaticMethods: options.includeStaticMethods ?? true,\n followImports: options.followImports ?? false,\n smrtDependencies,\n };\n }\n\n /**\n * Scan files using OxcScanner and build manifest via ManifestAdapter.\n *\n * This replaces the old ASTScanner-based scanFiles() method.\n * Uses the same OXC pipeline as the Vite plugin's scanWithOxc().\n */\n private async scanAndBuildManifest(\n config: ScannerConfig,\n options: ManifestBuilderOptions,\n ): Promise<SmartObjectManifest> {\n const { OxcScanner, ManifestAdapter } = await importScanner();\n\n const scanner = new OxcScanner({\n cwd: process.cwd(),\n include: options.include || ['src/**/*.ts'],\n exclude: options.exclude || ['src/**/*.d.ts', 'node_modules/**'],\n baseClasses: config.baseClasses,\n includePrivateMethods: config.includePrivateMethods,\n includeStaticMethods: config.includeStaticMethods,\n followImports: config.followImports,\n });\n\n const { results, resolved } = await scanner.scanAndResolve();\n\n // Read package.json for metadata\n let packageName: string | undefined;\n let packageVersion: string | undefined;\n let packageJson: { name?: string; version?: string } | undefined;\n try {\n const pkgPath = resolve(process.cwd(), 'package.json');\n const pkgContent = readFileSync(pkgPath, 'utf-8');\n packageJson = JSON.parse(pkgContent);\n packageName = packageJson?.name || undefined;\n packageVersion = packageJson?.version || undefined;\n } catch {\n // package.json not found - continue without packageName\n }\n\n // Convert to manifest format\n const adapter = new ManifestAdapter();\n const manifest = adapter.toManifest(resolved, {\n packageName,\n packageVersion,\n typeAliases: results.typeAliases,\n });\n\n // Set smrtDependencies BEFORE mergeInheritedFields so external packages can be loaded\n if (config.smrtDependencies && config.smrtDependencies.length > 0) {\n manifest.smrtDependencies = config.smrtDependencies;\n }\n\n // Run manifest generation passes (same as Vite plugin path)\n const manifestGen = new ManifestGenerator();\n manifestGen.injectTenantScopedFields(manifest);\n manifestGen.mergeInheritedFields(manifest);\n manifestGen.generateValidationRules(manifest);\n manifestGen.generateSchemas(manifest);\n manifestGen.assertTenantScopedSchemaContract(manifest);\n manifestGen.generateAgentManifests(manifest, packageName, packageJson);\n\n return manifest;\n }\n\n /**\n * Enrich manifest with metadata (moduleType, smrtDependencies, packageInfo).\n *\n * Note: As of Issue #1013, this method no longer merges external package\n * objects into the manifest. Dependencies are referenced via\n * `smrtDependencies` and resolved at runtime by manifest-loader.ts.\n */\n private enrichManifest(\n manifest: SmartObjectManifest,\n options: ManifestBuilderOptions,\n scannerConfig: ScannerConfig,\n ): SmartObjectManifest {\n // Add module type\n manifest.moduleType = options.moduleType || 'smrt';\n\n // Record dependency references (not their objects) so runtime\n // manifest-loader.ts can discover and load them on demand.\n if (\n scannerConfig.smrtDependencies &&\n scannerConfig.smrtDependencies.length > 0\n ) {\n manifest.smrtDependencies = scannerConfig.smrtDependencies;\n }\n\n // Inject package info\n if (options.injectPackageInfo) {\n const packageInfo = this.readPackageJson();\n if (packageInfo.name) {\n manifest.packageName = packageInfo.name;\n console.log(`[smrt] Injected package name: ${packageInfo.name}`);\n } else {\n console.warn(\n '[smrt] Warning: Could not read package.json, packageName will be undefined',\n );\n }\n }\n\n return manifest;\n }\n\n /**\n * Write manifest JSON and optional TypeScript stub\n */\n private async writeOutput(\n manifest: SmartObjectManifest,\n options: ManifestBuilderOptions,\n ): Promise<void> {\n const manager = new ManifestManager(process.cwd());\n const isTest =\n options.outputName?.includes('test') ||\n options.stubName?.includes('test');\n const mode = isTest ? 'dev' : 'build';\n\n // 1. Always write to the unified location via ManifestManager\n manager.write(manifest, mode);\n\n // 2. Legacy/Explicit Output (if requested or for stubs)\n const outputDir = options.outputDir || 'src/manifest';\n const outputName = options.outputName || 'manifest.json';\n\n // Ensure output directory exists for legacy/stubs\n mkdirSync(outputDir, { recursive: true });\n\n // Write JSON manifest to legacy location if different from unified path\n const manifestPath = resolve(outputDir, outputName);\n const unifiedPath = manager.getOutputPath(mode);\n\n if (resolve(manifestPath) !== resolve(unifiedPath)) {\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));\n }\n\n // Write TypeScript stub if requested\n if (options.generateTypeStub) {\n const stubName = options.stubName || 'manifest.ts';\n const tsContent = this.generateTypeStub(manifest, stubName);\n const stubPath = resolve(outputDir, stubName);\n writeFileSync(stubPath, tsContent);\n }\n\n const objectCount = Object.keys(manifest.objects).length;\n console.log(`[smrt] ✅ Generated manifest with ${objectCount} object(s)`);\n console.log(`[smrt] Unified: ${unifiedPath}`);\n }\n\n /**\n * Generate TypeScript stub file with manifest constant\n */\n private generateTypeStub(\n manifest: SmartObjectManifest,\n filename: string,\n ): string {\n const isTestManifest = filename.includes('test');\n\n const comment = isTestManifest\n ? `/**\n * Test manifest stub\n * This file is replaced by generate-test-manifest.js during pretest\n * If tests run without pretest, this empty manifest is used\n *\n * DO NOT EDIT MANUALLY - This file is automatically generated\n */`\n : `/**\n * Auto-generated static manifest\n * Generated at build time from SMRT object scanning\n * DO NOT EDIT - This file is automatically generated\n */`;\n\n const exportName = isTestManifest ? 'testManifest' : 'staticManifest';\n\n // Use relative import for core package (to avoid self-reference during build),\n // package import for all other packages\n const isCorePackage = manifest.packageName === '@happyvertical/smrt-core';\n const importPath = isCorePackage\n ? '../scanner/types.js'\n : '@happyvertical/smrt-core/scanner/types';\n\n return `${comment}\n\nimport type { SmartObjectManifest } from '${importPath}';\n\nexport const ${exportName}: SmartObjectManifest = ${JSON.stringify(manifest, null, 2)} as const;\n\nexport default ${exportName};\n`;\n }\n\n /**\n * Load baseClasses from vite.config.ts\n */\n private async loadViteConfigBaseClasses(): Promise<string[] | null> {\n try {\n const viteConfigPath = resolve(process.cwd(), 'vite.config.ts');\n if (!existsSync(viteConfigPath)) {\n console.log('[smrt] vite.config.ts not found');\n return null;\n }\n\n console.log('[smrt] Found vite.config.ts, attempting to load...');\n\n // Use vite to load config which handles TypeScript\n const { loadConfigFromFile } = await import('vite');\n const loaded = await loadConfigFromFile(\n { command: 'build', mode: 'test' },\n viteConfigPath,\n );\n\n if (!loaded?.config?.plugins) {\n console.log('[smrt] No plugins found in vite config');\n return null;\n }\n\n // Vite's loaded plugins are a recursive PluginOption[] (plugins, arrays,\n // falsy values, promises). We only probe a few optional fields, so model\n // them structurally and narrow defensively instead of using `any`.\n const plugins = loaded.config.plugins as readonly VitePluginProbe[];\n\n console.log(\n '[smrt] Vite config loaded, plugins:',\n plugins.map((p) => p?.name),\n );\n\n // Find smrtPlugin in plugins array\n const smrtPlugin = plugins.find((p) => p?.name === 'smrt-auto-service');\n\n if (!smrtPlugin) {\n console.log(\n '[smrt] smrt-auto-service plugin not found in plugins array',\n );\n return null;\n }\n\n console.log('[smrt] Found smrt-auto-service plugin');\n\n // Try different ways to access options\n const api = smrtPlugin.api;\n let opts: VitePluginOptions | undefined =\n (typeof api === 'object' && api !== null ? api.options : undefined) ||\n smrtPlugin.options ||\n smrtPlugin._options;\n\n if (!opts && typeof api === 'function') {\n try {\n opts = api().options;\n } catch (e) {\n console.log('[smrt] Could not call plugin.api()');\n }\n }\n\n if (opts?.baseClasses) {\n console.log(\n '[smrt] Plugin options:',\n JSON.stringify({\n baseClasses: opts.baseClasses,\n followImports: opts.followImports,\n }),\n );\n return opts.baseClasses;\n }\n\n console.log('[smrt] Could not access plugin options');\n return null;\n } catch (error) {\n console.log(\n '[smrt] Error loading vite.config.ts:',\n error instanceof Error ? error.message : String(error),\n );\n console.log('[smrt] Using default baseClasses');\n return null;\n }\n }\n\n /**\n * Load base classes from external SMRT package manifests\n */\n private async loadExternalBaseClasses(packages: string[]): Promise<string[]> {\n const externalBaseClasses: string[] = [];\n\n for (const pkgName of packages) {\n // Resolve the manifest the same way discovery does (honors `.smrt/` and\n // `src/manifest/`, not just `dist/`) so source-only workspace packages\n // still contribute base classes (#1378).\n const manifestPath = resolveManifestPath(pkgName, process.cwd());\n if (!manifestPath) {\n console.log(`[smrt] ${pkgName}: no SMRT manifest resolved`);\n continue;\n }\n\n try {\n const manifestContent = readFileSync(manifestPath, 'utf-8');\n const manifest: SmartObjectManifest = JSON.parse(manifestContent);\n\n // Extract all class names from this package\n const foundClassNames: string[] = [];\n for (const objDef of Object.values(manifest.objects)) {\n if (objDef.className) {\n const className = objDef.className;\n foundClassNames.push(className);\n externalBaseClasses.push(className);\n }\n }\n\n console.log(\n `[smrt] ${pkgName}: found ${foundClassNames.length} class(es) - ${foundClassNames.join(', ')}`,\n );\n } catch (error) {\n console.log(\n `[smrt] ${pkgName}: manifest not found or invalid - ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n return externalBaseClasses;\n }\n\n /**\n * Read package.json from current working directory\n */\n private readPackageJson(): PackageInfo {\n try {\n const packageJsonPath = resolve(process.cwd(), 'package.json');\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return {\n name: packageJson.name,\n version: packageJson.version,\n };\n } catch (error) {\n return {};\n }\n }\n\n /**\n * Create empty manifest when no files found\n */\n private createEmptyManifest(\n options: ManifestBuilderOptions,\n ): SmartObjectManifest {\n const manifest: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n moduleType: options.moduleType || 'smrt',\n };\n\n if (options.discoverExternalPackages) {\n manifest.smrtDependencies = discoverSmrtPackages();\n }\n\n if (options.injectPackageInfo) {\n const packageInfo = this.readPackageJson();\n if (packageInfo.name) {\n manifest.packageName = packageInfo.name;\n }\n }\n\n return manifest;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generator.js","sources":["../../src/manifest/generator.ts"],"sourcesContent":["/**\n * Manifest generation orchestrator\n * Consolidates manifest generation logic for both build and test manifests\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, isAbsolute, relative, resolve } from 'node:path';\nimport fg from 'fast-glob';\nimport { ManifestGenerator } from '../scanner/manifest-generator.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\nimport { importWorkspaceModule } from '../utils/import-workspace-module.js';\nimport type { ScannerModule } from '../utils/scanner-module.js';\nimport {\n discoverSmrtPackages,\n resolveManifestPath,\n} from './discover-smrt-packages.js';\nimport { ManifestManager } from './manager.js';\n\n// Build-time manifest-generation diagnostics route through the shared logger\n// (S14 / dim-9, #1579) so consumers can control verbosity instead of receiving\n// unconditional stdout writes.\nconst logger = createLogger({ level: 'info' });\n\nasync function importScanner() {\n return importWorkspaceModule<ScannerModule>({\n packageName: '@happyvertical/smrt-scanner',\n distEntry: 'packages/scanner/dist/index.js',\n sourceEntry: 'packages/scanner/src/index.ts',\n purpose: 'manifest generation',\n });\n}\n\n/**\n * Options for ManifestBuilder.generate()\n *\n * Controls file discovery, scanner configuration, output generation, and metadata injection\n */\nexport interface ManifestBuilderOptions {\n // File Discovery\n include?: string[];\n exclude?: string[];\n followImports?: boolean;\n\n // Scanner Configuration\n baseClasses?: string[];\n loadViteConfig?: boolean;\n discoverExternalPackages?: boolean;\n includeExternalBaseClasses?: boolean;\n includePrivateMethods?: boolean;\n includeStaticMethods?: boolean;\n\n // Output Configuration\n outputDir?: string;\n outputName?: string;\n generateTypeStub?: boolean;\n stubName?: string;\n\n // Metadata\n injectPackageInfo?: boolean;\n moduleType?: string;\n\n // Tree Shaking (External Object Filtering)\n /**\n * @deprecated Tree shaking is no longer needed. The AST scanner no longer includes external objects in the manifest by default.\n */\n treeShake?: boolean;\n\n /**\n * @deprecated Whitelists are no longer needed. The AST scanner no longer includes external objects in the manifest by default.\n */\n externalObjectsWhitelist?: string[];\n}\n\ninterface ScannerConfig {\n baseClasses: string[];\n includePrivateMethods: boolean;\n includeStaticMethods: boolean;\n followImports: boolean;\n smrtDependencies?: string[];\n}\n\ninterface PackageInfo {\n name?: string;\n version?: string;\n}\n\n/**\n * Subset of the smrt-auto-service Vite plugin options we probe when reading\n * baseClasses out of a project's vite.config.ts.\n */\ninterface VitePluginOptions {\n baseClasses?: string[];\n followImports?: boolean;\n}\n\n/**\n * Structural shape of a loaded Vite plugin entry as probed by\n * loadViteConfigBaseClasses(). The plugin may expose its options directly, on\n * `_options`, or via an `api` object/function — all optional and discovered at\n * runtime, so each is modeled as optional here.\n */\ninterface VitePluginProbe {\n name?: string;\n options?: VitePluginOptions;\n _options?: VitePluginOptions;\n api?:\n | { options?: VitePluginOptions }\n | (() => { options?: VitePluginOptions });\n}\n\n/**\n * Orchestrates manifest generation with configurable options\n *\n * Consolidates logic from generate-manifest.js and generate-test-manifest.js\n * into a single, testable, and maintainable service.\n */\nexport class ManifestBuilder {\n /**\n * Generate manifest with specified options\n */\n async generate(\n options: ManifestBuilderOptions = {},\n ): Promise<SmartObjectManifest> {\n // 1. Discover files to scan\n const files = this.discoverFiles(options);\n\n if (files.length === 0) {\n logger.info('[smrt] No source files found');\n return this.createEmptyManifest(options);\n }\n\n logger.info(`[smrt] Scanning ${files.length} source file(s)...`);\n\n // 2. Configure scanner (baseClasses, external packages, vite config)\n const scannerConfig = await this.configureScanner(options);\n\n // 3. Scan files with OXC scanner\n const scannedManifest = await this.scanAndBuildManifest(\n scannerConfig,\n options,\n );\n\n // 4. Enrich manifest with metadata (smrtDependencies, packageInfo)\n const manifest = this.enrichManifest(\n scannedManifest,\n options,\n scannerConfig,\n );\n\n // 5. Write output files\n this.normalizeFilePaths(manifest);\n await this.writeOutput(manifest, options);\n\n return manifest;\n }\n\n private normalizeFilePaths(manifest: SmartObjectManifest): void {\n const workspaceRoot = this.findWorkspaceRoot(process.cwd());\n\n for (const obj of Object.values(manifest.objects || {})) {\n if (obj.filePath && isAbsolute(obj.filePath)) {\n obj.filePath = relative(workspaceRoot, obj.filePath).replace(\n /\\\\/g,\n '/',\n );\n }\n }\n }\n\n private findWorkspaceRoot(startDir: string): string {\n let current = resolve(startDir);\n\n while (true) {\n if (\n existsSync(resolve(current, 'pnpm-workspace.yaml')) ||\n existsSync(resolve(current, '.git'))\n ) {\n return current;\n }\n\n const parent = dirname(current);\n if (parent === current) {\n return resolve(startDir);\n }\n current = parent;\n }\n }\n\n /**\n * Discover source files based on include/exclude patterns\n */\n private discoverFiles(options: ManifestBuilderOptions): string[] {\n const include = options.include || ['src/**/*.ts'];\n const exclude = options.exclude || ['src/**/*.d.ts', 'node_modules/**'];\n\n return fg.sync(include, {\n absolute: true,\n ignore: exclude,\n });\n }\n\n /**\n * Configure AST scanner with baseClasses, external packages, and vite config\n */\n private async configureScanner(\n options: ManifestBuilderOptions,\n ): Promise<ScannerConfig> {\n let baseClasses = options.baseClasses || [\n 'SmrtObject',\n 'SmrtClass',\n 'SmrtCollection',\n ];\n\n // Load from vite.config.ts if requested\n if (options.loadViteConfig) {\n const viteBaseClasses = await this.loadViteConfigBaseClasses();\n if (viteBaseClasses && viteBaseClasses.length > 0) {\n baseClasses = viteBaseClasses;\n logger.info(\n `[smrt] Using baseClasses from vite.config.ts: ${baseClasses.join(', ')}`,\n );\n }\n }\n\n // Discover external SMRT packages\n let smrtDependencies: string[] = [];\n if (options.discoverExternalPackages) {\n logger.info('[smrt] Discovering external SMRT packages...');\n smrtDependencies = discoverSmrtPackages();\n logger.info(\n `[smrt] Found ${smrtDependencies.length} SMRT package(s): ${smrtDependencies.join(', ')}`,\n );\n\n // Optionally add external base classes\n if (options.includeExternalBaseClasses) {\n const externalClasses =\n await this.loadExternalBaseClasses(smrtDependencies);\n if (externalClasses.length > 0) {\n baseClasses = [...baseClasses, ...externalClasses];\n logger.info(\n `[smrt] Added ${externalClasses.length} external base class(es) to scanner`,\n );\n logger.info(`[smrt] Total baseClasses: ${baseClasses.length}`);\n }\n }\n }\n\n return {\n baseClasses,\n includePrivateMethods: options.includePrivateMethods ?? false,\n includeStaticMethods: options.includeStaticMethods ?? true,\n followImports: options.followImports ?? false,\n smrtDependencies,\n };\n }\n\n /**\n * Scan files using OxcScanner and build manifest via ManifestAdapter.\n *\n * This replaces the old ASTScanner-based scanFiles() method.\n * Uses the same OXC pipeline as the Vite plugin's scanWithOxc().\n */\n private async scanAndBuildManifest(\n config: ScannerConfig,\n options: ManifestBuilderOptions,\n ): Promise<SmartObjectManifest> {\n const { OxcScanner, ManifestAdapter } = await importScanner();\n\n const scanner = new OxcScanner({\n cwd: process.cwd(),\n include: options.include || ['src/**/*.ts'],\n exclude: options.exclude || ['src/**/*.d.ts', 'node_modules/**'],\n baseClasses: config.baseClasses,\n includePrivateMethods: config.includePrivateMethods,\n includeStaticMethods: config.includeStaticMethods,\n followImports: config.followImports,\n });\n\n const { results, resolved } = await scanner.scanAndResolve();\n\n // Read package.json for metadata\n let packageName: string | undefined;\n let packageVersion: string | undefined;\n let packageJson: { name?: string; version?: string } | undefined;\n try {\n const pkgPath = resolve(process.cwd(), 'package.json');\n const pkgContent = readFileSync(pkgPath, 'utf-8');\n packageJson = JSON.parse(pkgContent);\n packageName = packageJson?.name || undefined;\n packageVersion = packageJson?.version || undefined;\n } catch {\n // package.json not found - continue without packageName\n }\n\n // Convert to manifest format\n const adapter = new ManifestAdapter();\n const manifest = adapter.toManifest(resolved, {\n packageName,\n packageVersion,\n typeAliases: results.typeAliases,\n });\n\n // Set smrtDependencies BEFORE mergeInheritedFields so external packages can be loaded\n if (config.smrtDependencies && config.smrtDependencies.length > 0) {\n manifest.smrtDependencies = config.smrtDependencies;\n }\n\n // Run manifest generation passes (same as Vite plugin path)\n const manifestGen = new ManifestGenerator();\n manifestGen.injectTenantScopedFields(manifest);\n manifestGen.mergeInheritedFields(manifest);\n manifestGen.generateValidationRules(manifest);\n manifestGen.generateSchemas(manifest);\n manifestGen.assertTenantScopedSchemaContract(manifest);\n manifestGen.generateAgentManifests(manifest, packageName, packageJson);\n\n return manifest;\n }\n\n /**\n * Enrich manifest with metadata (moduleType, smrtDependencies, packageInfo).\n *\n * Note: As of Issue #1013, this method no longer merges external package\n * objects into the manifest. Dependencies are referenced via\n * `smrtDependencies` and resolved at runtime by manifest-loader.ts.\n */\n private enrichManifest(\n manifest: SmartObjectManifest,\n options: ManifestBuilderOptions,\n scannerConfig: ScannerConfig,\n ): SmartObjectManifest {\n // Add module type\n manifest.moduleType = options.moduleType || 'smrt';\n\n // Record dependency references (not their objects) so runtime\n // manifest-loader.ts can discover and load them on demand.\n if (\n scannerConfig.smrtDependencies &&\n scannerConfig.smrtDependencies.length > 0\n ) {\n manifest.smrtDependencies = scannerConfig.smrtDependencies;\n }\n\n // Inject package info\n if (options.injectPackageInfo) {\n const packageInfo = this.readPackageJson();\n if (packageInfo.name) {\n manifest.packageName = packageInfo.name;\n logger.info(`[smrt] Injected package name: ${packageInfo.name}`);\n } else {\n logger.warn(\n '[smrt] Warning: Could not read package.json, packageName will be undefined',\n );\n }\n }\n\n return manifest;\n }\n\n /**\n * Write manifest JSON and optional TypeScript stub\n */\n private async writeOutput(\n manifest: SmartObjectManifest,\n options: ManifestBuilderOptions,\n ): Promise<void> {\n const manager = new ManifestManager(process.cwd());\n const isTest =\n options.outputName?.includes('test') ||\n options.stubName?.includes('test');\n const mode = isTest ? 'dev' : 'build';\n\n // 1. Always write to the unified location via ManifestManager\n manager.write(manifest, mode);\n\n // 2. Legacy/Explicit Output (if requested or for stubs)\n const outputDir = options.outputDir || 'src/manifest';\n const outputName = options.outputName || 'manifest.json';\n\n // Ensure output directory exists for legacy/stubs\n mkdirSync(outputDir, { recursive: true });\n\n // Write JSON manifest to legacy location if different from unified path\n const manifestPath = resolve(outputDir, outputName);\n const unifiedPath = manager.getOutputPath(mode);\n\n if (resolve(manifestPath) !== resolve(unifiedPath)) {\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));\n }\n\n // Write TypeScript stub if requested\n if (options.generateTypeStub) {\n const stubName = options.stubName || 'manifest.ts';\n const tsContent = this.generateTypeStub(manifest, stubName);\n const stubPath = resolve(outputDir, stubName);\n writeFileSync(stubPath, tsContent);\n }\n\n const objectCount = Object.keys(manifest.objects).length;\n logger.info(`[smrt] ✅ Generated manifest with ${objectCount} object(s)`);\n logger.info(`[smrt] Unified: ${unifiedPath}`);\n }\n\n /**\n * Generate TypeScript stub file with manifest constant\n */\n private generateTypeStub(\n manifest: SmartObjectManifest,\n filename: string,\n ): string {\n const isTestManifest = filename.includes('test');\n\n const comment = isTestManifest\n ? `/**\n * Test manifest stub\n * This file is replaced by generate-test-manifest.js during pretest\n * If tests run without pretest, this empty manifest is used\n *\n * DO NOT EDIT MANUALLY - This file is automatically generated\n */`\n : `/**\n * Auto-generated static manifest\n * Generated at build time from SMRT object scanning\n * DO NOT EDIT - This file is automatically generated\n */`;\n\n const exportName = isTestManifest ? 'testManifest' : 'staticManifest';\n\n // Use relative import for core package (to avoid self-reference during build),\n // package import for all other packages\n const isCorePackage = manifest.packageName === '@happyvertical/smrt-core';\n const importPath = isCorePackage\n ? '../scanner/types.js'\n : '@happyvertical/smrt-core/scanner/types';\n\n return `${comment}\n\nimport type { SmartObjectManifest } from '${importPath}';\n\nexport const ${exportName}: SmartObjectManifest = ${JSON.stringify(manifest, null, 2)} as const;\n\nexport default ${exportName};\n`;\n }\n\n /**\n * Load baseClasses from vite.config.ts\n */\n private async loadViteConfigBaseClasses(): Promise<string[] | null> {\n try {\n const viteConfigPath = resolve(process.cwd(), 'vite.config.ts');\n if (!existsSync(viteConfigPath)) {\n logger.info('[smrt] vite.config.ts not found');\n return null;\n }\n\n logger.info('[smrt] Found vite.config.ts, attempting to load...');\n\n // Use vite to load config which handles TypeScript\n const { loadConfigFromFile } = await import('vite');\n const loaded = await loadConfigFromFile(\n { command: 'build', mode: 'test' },\n viteConfigPath,\n );\n\n if (!loaded?.config?.plugins) {\n logger.info('[smrt] No plugins found in vite config');\n return null;\n }\n\n // Vite's loaded plugins are a recursive PluginOption[] (plugins, arrays,\n // falsy values, promises). We only probe a few optional fields, so model\n // them structurally and narrow defensively instead of using `any`.\n const plugins = loaded.config.plugins as readonly VitePluginProbe[];\n\n logger.info('[smrt] Vite config loaded', {\n plugins: plugins.map((p) => p?.name),\n });\n\n // Find smrtPlugin in plugins array\n const smrtPlugin = plugins.find((p) => p?.name === 'smrt-auto-service');\n\n if (!smrtPlugin) {\n logger.info(\n '[smrt] smrt-auto-service plugin not found in plugins array',\n );\n return null;\n }\n\n logger.info('[smrt] Found smrt-auto-service plugin');\n\n // Try different ways to access options\n const api = smrtPlugin.api;\n let opts: VitePluginOptions | undefined =\n (typeof api === 'object' && api !== null ? api.options : undefined) ||\n smrtPlugin.options ||\n smrtPlugin._options;\n\n if (!opts && typeof api === 'function') {\n try {\n opts = api().options;\n } catch (e) {\n logger.info('[smrt] Could not call plugin.api()');\n }\n }\n\n if (opts?.baseClasses) {\n logger.info('[smrt] Plugin options', {\n baseClasses: opts.baseClasses,\n followImports: opts.followImports,\n });\n return opts.baseClasses;\n }\n\n logger.info('[smrt] Could not access plugin options');\n return null;\n } catch (error) {\n logger.warn('[smrt] Error loading vite.config.ts', {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.info('[smrt] Using default baseClasses');\n return null;\n }\n }\n\n /**\n * Load base classes from external SMRT package manifests\n */\n private async loadExternalBaseClasses(packages: string[]): Promise<string[]> {\n const externalBaseClasses: string[] = [];\n\n for (const pkgName of packages) {\n // Resolve the manifest the same way discovery does (honors `.smrt/` and\n // `src/manifest/`, not just `dist/`) so source-only workspace packages\n // still contribute base classes (#1378).\n const manifestPath = resolveManifestPath(pkgName, process.cwd());\n if (!manifestPath) {\n logger.info(`[smrt] ${pkgName}: no SMRT manifest resolved`);\n continue;\n }\n\n try {\n const manifestContent = readFileSync(manifestPath, 'utf-8');\n const manifest: SmartObjectManifest = JSON.parse(manifestContent);\n\n // Extract all class names from this package\n const foundClassNames: string[] = [];\n for (const objDef of Object.values(manifest.objects)) {\n if (objDef.className) {\n const className = objDef.className;\n foundClassNames.push(className);\n externalBaseClasses.push(className);\n }\n }\n\n logger.info(\n `[smrt] ${pkgName}: found ${foundClassNames.length} class(es) - ${foundClassNames.join(', ')}`,\n );\n } catch (error) {\n logger.info(\n `[smrt] ${pkgName}: manifest not found or invalid - ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n return externalBaseClasses;\n }\n\n /**\n * Read package.json from current working directory\n */\n private readPackageJson(): PackageInfo {\n try {\n const packageJsonPath = resolve(process.cwd(), 'package.json');\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return {\n name: packageJson.name,\n version: packageJson.version,\n };\n } catch (error) {\n return {};\n }\n }\n\n /**\n * Create empty manifest when no files found\n */\n private createEmptyManifest(\n options: ManifestBuilderOptions,\n ): SmartObjectManifest {\n const manifest: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n moduleType: options.moduleType || 'smrt',\n };\n\n if (options.discoverExternalPackages) {\n manifest.smrtDependencies = discoverSmrtPackages();\n }\n\n if (options.injectPackageInfo) {\n const packageInfo = this.readPackageJson();\n if (packageInfo.name) {\n manifest.packageName = packageInfo.name;\n }\n }\n\n return manifest;\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/manifest/index.js
CHANGED
|
@@ -2,8 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { ManifestGenerator } from "../scanner/manifest-generator.js";
|
|
5
|
-
import "
|
|
6
|
-
import "./discover-smrt-packages.js";
|
|
5
|
+
import { ManifestBuilder } from "./generator.js";
|
|
7
6
|
import { ManifestManager } from "./manager.js";
|
|
8
7
|
import { discoverManifestEntry, findManifestEntryByQualifiedName, loadExternalManifest, loadExternalManifestSync, loadLocalTestManifestSync, loadManifestFromPathSync } from "./manifest-loader.js";
|
|
9
8
|
const EMPTY_STATIC_MANIFEST = {
|
|
@@ -36,6 +35,7 @@ function getManifest() {
|
|
|
36
35
|
return Promise.resolve(manifest);
|
|
37
36
|
}
|
|
38
37
|
export {
|
|
38
|
+
ManifestBuilder,
|
|
39
39
|
ManifestGenerator,
|
|
40
40
|
ManifestManager,
|
|
41
41
|
discoverManifestEntry,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/manifest/index.ts"],"sourcesContent":["/**\n * Static manifest module for runtime use\n * Uses pre-generated manifest from build time instead of runtime scanning\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SmartObjectManifest } from '../scanner/types';\n\n// Re-export utility functions that work with static manifest\nexport { ManifestGenerator } from '../scanner/manifest-generator';\nexport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types';\nexport type { ManifestBuilderOptions } from './generator';\nexport { ManifestBuilder } from './generator';\nexport { ManifestManager } from './manager';\nexport {\n discoverManifestEntry,\n findManifestEntryByQualifiedName,\n loadExternalManifest,\n loadExternalManifestSync,\n loadLocalTestManifestSync,\n loadManifestFromPathSync,\n} from './manifest-loader';\n\nconst EMPTY_STATIC_MANIFEST: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: 0,\n objects: {},\n packageName: '@happyvertical/smrt-core',\n};\n\nfunction loadStaticManifest(): SmartObjectManifest {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const manifestCandidates = [\n join(currentDir, 'static-manifest.json'),\n join(currentDir, '..', 'manifest.json'),\n join(currentDir, '..', '..', 'dist', 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (!existsSync(manifestPath)) {\n continue;\n }\n\n try {\n return JSON.parse(readFileSync(manifestPath, 'utf-8'));\n } catch {\n // Fall through to the next candidate or the empty manifest.\n }\n }\n\n return EMPTY_STATIC_MANIFEST;\n}\n\nexport const manifest = loadStaticManifest();\nexport const staticManifest = manifest;\nexport default manifest;\n\n/**\n * Get manifest data (static at runtime)\n * No longer requires TypeScript compiler or file scanning.\n */\nexport function getManifest() {\n return Promise.resolve(manifest);\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/manifest/index.ts"],"sourcesContent":["/**\n * Static manifest module for runtime use\n * Uses pre-generated manifest from build time instead of runtime scanning\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SmartObjectManifest } from '../scanner/types';\n\n// Re-export utility functions that work with static manifest\nexport { ManifestGenerator } from '../scanner/manifest-generator';\nexport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types';\nexport type { ManifestBuilderOptions } from './generator';\nexport { ManifestBuilder } from './generator';\nexport { ManifestManager } from './manager';\nexport {\n discoverManifestEntry,\n findManifestEntryByQualifiedName,\n loadExternalManifest,\n loadExternalManifestSync,\n loadLocalTestManifestSync,\n loadManifestFromPathSync,\n} from './manifest-loader';\n\nconst EMPTY_STATIC_MANIFEST: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: 0,\n objects: {},\n packageName: '@happyvertical/smrt-core',\n};\n\nfunction loadStaticManifest(): SmartObjectManifest {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const manifestCandidates = [\n join(currentDir, 'static-manifest.json'),\n join(currentDir, '..', 'manifest.json'),\n join(currentDir, '..', '..', 'dist', 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (!existsSync(manifestPath)) {\n continue;\n }\n\n try {\n return JSON.parse(readFileSync(manifestPath, 'utf-8'));\n } catch {\n // Fall through to the next candidate or the empty manifest.\n }\n }\n\n return EMPTY_STATIC_MANIFEST;\n}\n\nexport const manifest = loadStaticManifest();\nexport const staticManifest = manifest;\nexport default manifest;\n\n/**\n * Get manifest data (static at runtime)\n * No longer requires TypeScript compiler or file scanning.\n */\nexport function getManifest() {\n return Promise.resolve(manifest);\n}\n"],"names":[],"mappings":";;;;;;;AA4BA,MAAM,wBAA6C;AAAA,EACjD,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS,CAAA;AAAA,EACT,aAAa;AACf;AAEA,SAAS,qBAA0C;AACjD,QAAM,aAAa,QAAQ,cAAc,YAAY,GAAG,CAAC;AACzD,QAAM,qBAAqB;AAAA,IACzB,KAAK,YAAY,sBAAsB;AAAA,IACvC,KAAK,YAAY,MAAM,eAAe;AAAA,IACtC,KAAK,YAAY,MAAM,MAAM,QAAQ,eAAe;AAAA,EAAA;AAGtD,aAAW,gBAAgB,oBAAoB;AAC7C,QAAI,CAAC,WAAW,YAAY,GAAG;AAC7B;AAAA,IACF;AAEA,QAAI;AACF,aAAO,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAAA,IACvD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,WAAW,mBAAA;AACjB,MAAM,iBAAiB;AAOvB,SAAS,cAAc;AAC5B,SAAO,QAAQ,QAAQ,QAAQ;AACjC;"}
|
|
@@ -179,6 +179,16 @@ export declare function getLoadedManifests(): Array<[string, Manifest]>;
|
|
|
179
179
|
*
|
|
180
180
|
* @param collection - The collection/table name to find siblings for
|
|
181
181
|
* @returns Array of manifest entries that share the same collection
|
|
182
|
+
*
|
|
183
|
+
* Known limitation (#1579, won't-fix): the per-collection result is cached on
|
|
184
|
+
* `globalThis.__smrtSTISiblingCache` after the first call and is not invalidated
|
|
185
|
+
* when a manifest is registered *afterwards* and isn't reachable via
|
|
186
|
+
* `smrtDependencies` (the Release-A self-register path). A sibling registered
|
|
187
|
+
* after first discovery for a given collection can therefore be missed until the
|
|
188
|
+
* cache is cleared. Accepted as low-risk: STI manifests are registered at
|
|
189
|
+
* startup before query traffic, and the few self-register flows that could hit
|
|
190
|
+
* it can reset the cache. Fixing it properly means a registration→cache
|
|
191
|
+
* invalidation hook, which is disproportionate to the exposure.
|
|
182
192
|
*/
|
|
183
193
|
export declare function discoverSTISiblingsSync(collection: string): Array<{
|
|
184
194
|
className: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../../src/manifest/manifest-loader.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../../src/manifest/manifest-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-loader.js","sources":["../../src/manifest/manifest-loader.ts"],"sourcesContent":["/**\n * Manifest Loader - Automatic discovery of external package manifests\n *\n * This module provides automatic loading of SMRT manifests from external packages,\n * solving issue #131 where external package schemas weren't being detected.\n *\n * Architecture:\n * - Build-time: AST scanner generates manifests in dist/manifest.json\n * - Run-time: This module discovers and loads those manifests automatically\n * - Caching: Loaded manifests are cached to avoid repeated imports\n *\n * Flow:\n * 1. Check testManifest (for test classes)\n * 2. Check staticManifest (for core framework classes)\n * 3. Resolve external package manifests from explicit JSON exports\n * 4. Return manifest entry or undefined\n *\n * External manifest loading intentionally follows a pure-ESM JSON contract.\n * Packages are expected to publish a JSON manifest via \"./manifest\" and/or\n * \"./manifest.json\" exports. Runtime discovery does not guess sibling workspace\n * paths or load JavaScript manifest modules.\n */\n\nimport { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { createLogger } from '@happyvertical/logger';\nimport type { SmrtObjectConstructor } from '../registry/types.js';\nimport { ObjectRegistry } from '../registry.js';\nimport type {\n FieldDefinition,\n MethodDefinition,\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types.js';\nimport { parse } from '../utils/json.js';\nimport {\n createQualifiedName,\n isQualifiedName,\n parseQualifiedName,\n} from '../utils/qualified-names.js';\nimport { ManifestManager } from './manager.js';\nimport { getDefaultCompositeSource } from './sources/composite.js';\nimport {\n getLocalTestManifestCache as getLocalTestManifestCacheFromStore,\n getManifestCache as getManifestCacheFromStore,\n getStaticManifestCache as getStaticManifestCacheFromStore,\n getTestManifestCache as getTestManifestCacheFromStore,\n isTestEnvironment as isTestEnvFromStore,\n shouldLoadCoreTestManifest,\n} from './store.js';\n\n/**\n * Extend globalThis to include manifest loader state.\n * Using globalThis ensures all module instances share the same manifest caches,\n * which is critical in monorepos where the same package can be loaded\n * from different paths (e.g., pnpm store vs workspace symlink).\n *\n * @see https://github.com/happyvertical/smrt/issues/543\n */\ndeclare global {\n // eslint-disable-next-line no-var\n var __smrtManifestStatic: SmartObjectManifest | null | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestStaticLoadAttempted: boolean | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestTest: SmartObjectManifest | null | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestTestLoadAttempted: boolean | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestCache: Map<string, SmartObjectManifest> | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestLocalTest: SmartObjectManifest | null | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestCollisions:\n | Map<\n string,\n Array<{\n packageName: string;\n filePath?: string;\n manifestSource: string;\n }>\n >\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtSTISiblingCache:\n | Map<\n string,\n Array<{ className: string; entry: ManifestEntry; packageName?: string }>\n >\n | undefined;\n}\n\n// Use globalThis for cross-module state sharing\n// This ensures loadConfig() in one module instance affects all packages\n\n// ── Cache access (delegates to manifest/store.ts — the single source of\n// truth added in Release B #1133 for globalThis manifest state).\n// manifest-loader.ts keeps its own setters + load-attempted flags below\n// because those are internal to this module's async loader state machine;\n// the read-only getters just forward to store.ts to eliminate drift.\n\nconst getStaticManifestCache = getStaticManifestCacheFromStore;\nconst getTestManifestCache = getTestManifestCacheFromStore;\nconst getLocalTestManifestCache = getLocalTestManifestCacheFromStore;\nconst getManifestCacheMap = getManifestCacheFromStore;\n\nfunction setStaticManifestCache(\n manifest: SmartObjectManifest | null | undefined,\n): void {\n globalThis.__smrtManifestStatic = manifest;\n}\n\nfunction getStaticManifestLoadAttempted(): boolean {\n return globalThis.__smrtManifestStaticLoadAttempted ?? false;\n}\n\nfunction setStaticManifestLoadAttempted(value: boolean): void {\n globalThis.__smrtManifestStaticLoadAttempted = value;\n}\n\nfunction setTestManifestCache(\n manifest: SmartObjectManifest | null | undefined,\n): void {\n globalThis.__smrtManifestTest = manifest;\n}\n\nfunction getTestManifestLoadAttempted(): boolean {\n return globalThis.__smrtManifestTestLoadAttempted ?? false;\n}\n\nfunction setTestManifestLoadAttempted(value: boolean): void {\n globalThis.__smrtManifestTestLoadAttempted = value;\n}\n\nfunction setLocalTestManifestCache(\n manifest: SmartObjectManifest | null | undefined,\n): void {\n globalThis.__smrtManifestLocalTest = manifest;\n}\n\n/**\n * Get the manifest collisions Map from globalThis\n */\nfunction getManifestCollisionsMap(): Map<\n string,\n Array<{ packageName: string; filePath?: string; manifestSource: string }>\n> {\n if (!globalThis.__smrtManifestCollisions) {\n globalThis.__smrtManifestCollisions = new Map();\n }\n return globalThis.__smrtManifestCollisions;\n}\n\n/**\n * Get the STI sibling cache Map from globalThis\n * Caches discoverSTISiblingsSync results per collection to avoid repeated scans\n */\nfunction getSTISiblingCache(): Map<\n string,\n Array<{ className: string; entry: ManifestEntry; packageName?: string }>\n> {\n if (!globalThis.__smrtSTISiblingCache) {\n globalThis.__smrtSTISiblingCache = new Map();\n }\n return globalThis.__smrtSTISiblingCache;\n}\n\n// Create require function once for reuse\nconst require = createRequire(import.meta.url);\n\n/**\n * Cached debug flag evaluated once at module load time.\n * Environment variables don't change at runtime, so this is safe.\n * @see https://github.com/happyvertical/smrt/issues/729\n */\nconst DEBUG_ENABLED =\n process.env.DEBUG_MANIFEST === 'true' ||\n process.env.DEBUG_MANIFEST === '1' ||\n process.env.DEBUG?.includes('manifest') ||\n false;\n\n// The debug traces below are gated by DEBUG_MANIFEST / DEBUG_TEST_ENV, so the\n// logger level must allow debug when either is set (a fixed 'info' would filter\n// them out and silently break those debug switches).\nconst logger = createLogger({\n level: DEBUG_ENABLED || process.env.DEBUG_TEST_ENV ? 'debug' : 'info',\n});\n\n/**\n * Log a debug message only if DEBUG_MANIFEST is enabled.\n * Uses cached boolean check instead of repeated env var access.\n */\nfunction debugLog(message: string): void {\n if (DEBUG_ENABLED) {\n logger.debug(message);\n }\n}\n\n/**\n * Cache for className-to-entry index per manifest.\n * This enables O(1) lookup by className instead of O(n) iteration.\n * @see https://github.com/happyvertical/smrt/issues/729\n */\nconst classNameIndexCache = new WeakMap<\n SmartObjectManifest,\n Map<string, SmartObjectDefinition>\n>();\n\n/**\n * Get or build the className index for a manifest.\n * Index maps lowercase className to entry for O(1) lookup.\n */\nfunction getClassNameIndex(\n manifest: SmartObjectManifest,\n): Map<string, SmartObjectDefinition> {\n let index = classNameIndexCache.get(manifest);\n if (!index) {\n index = new Map<string, SmartObjectDefinition>();\n for (const [key, entry] of Object.entries(manifest.objects)) {\n const name = (entry.className || key).toLowerCase();\n if (!index.has(name)) {\n index.set(name, entry);\n } else {\n const existing = index.get(name)!;\n const existingName = (existing.className || '').toLowerCase();\n const newExtends = (entry.extends || '').toLowerCase();\n const existingExtends = (existing.extends || '').toLowerCase();\n\n // Issue #950: STI child-wins — if new entry extends existing, replace\n if (\n newExtends &&\n (newExtends === existingName || newExtends === name)\n ) {\n index.set(name, entry);\n debugLog(\n `Manifest className '${name}': child '${key}' replaces parent`,\n );\n } else if (\n existingExtends &&\n (existingExtends === (entry.className || key).toLowerCase() ||\n existingExtends === name)\n ) {\n // Existing is already the child, keep it\n debugLog(\n `Manifest className '${name}': keeping child, ignoring parent '${key}'`,\n );\n } else {\n debugLog(\n `Manifest className collision for '${name}': keeping first, ignoring key '${key}'`,\n );\n }\n }\n }\n classNameIndexCache.set(manifest, index);\n }\n return index;\n}\n\n/**\n * Test-environment detection with optional DEBUG_TEST_ENV logging.\n *\n * Delegates to the single source of truth in `store.ts` so the\n * ManifestSource implementations (which also gate on test-env) cannot\n * drift from the legacy sync loader. The logging wrapper stays here\n * because the trace is specific to this module's loader state machine.\n */\nfunction isTestEnvironment(): boolean {\n const result = isTestEnvFromStore();\n\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug('[manifest-loader] isTestEnvironment check', {\n NODE_ENV: process.env.NODE_ENV,\n VITEST: process.env.VITEST,\n JEST_WORKER_ID: process.env.JEST_WORKER_ID,\n result,\n });\n }\n\n return result;\n}\n\nfunction getStaticManifest(): SmartObjectManifest {\n if (!getStaticManifestLoadAttempted()) {\n setStaticManifestLoadAttempted(true);\n try {\n // Try to import the generated static manifest\n const imported = require('./static-manifest.js');\n setStaticManifestCache(imported.staticManifest || imported.default);\n } catch {\n // Fallback to empty manifest if file doesn't exist yet (during build)\n setStaticManifestCache({\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n packageName: '@happyvertical/smrt-core',\n });\n }\n }\n return getStaticManifestCache()!;\n}\n\n/**\n * Lazy-load smrt-core's internal test manifest only for smrt-core's own tests.\n * Consumer packages should never see these fixtures, or they can collide with\n * real external classes during downstream test runs.\n */\nfunction getTestManifest(): SmartObjectManifest | null {\n if (!getTestManifestLoadAttempted()) {\n setTestManifestLoadAttempted(true);\n\n // CRITICAL: Scope the core test manifest to smrt-core's own test suite.\n if (!shouldLoadCoreTestManifest()) {\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug(\n '[manifest-loader] ⚠️ Skipping core test manifest load (not smrt-core test environment)',\n );\n }\n setTestManifestCache(null);\n return null;\n }\n\n try {\n // Dynamically import test manifest to avoid loading in production\n const imported = require('./test-manifest-stub.js');\n const manifest = imported.testManifest || imported.default;\n setTestManifestCache(manifest);\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug(\n `[manifest-loader] ✅ Loaded test manifest (${Object.keys(manifest?.objects || {}).length} objects)`,\n );\n }\n } catch (error) {\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug(\n '[manifest-loader] ⚠️ Test manifest not found (this is normal in production)',\n );\n }\n setTestManifestCache(null);\n }\n }\n return getTestManifestCache();\n}\n\n// Re-export types for convenience\nexport type Manifest = SmartObjectManifest;\nexport type ManifestEntry = SmartObjectDefinition;\nexport type { FieldDefinition, MethodDefinition };\n\n// Note: manifestCache and localTestManifest are now accessed via globalThis helper functions\n// getManifestCacheMap() and getLocalTestManifestCache()/setLocalTestManifestCache()\n\n/**\n * Load local test manifest from current package (synchronous)\n *\n * During test runs, packages can have manifests in two locations:\n * 1. src/manifest/test-manifest.json - Domain packages during development\n * 2. dist/manifest.json - Built packages (consuming apps like praeco)\n *\n * This function attempts to load the manifest from either location.\n *\n * @returns Loaded manifest or null if not found or undefined if not yet attempted\n */\nexport function loadLocalTestManifestSync(): Manifest | null | undefined {\n // Only return cached manifest if it was successfully loaded\n // Don't cache null (failed loads) - allow retries\n const cached = getLocalTestManifestCache();\n if (cached !== undefined && cached !== null) {\n return cached;\n }\n\n // Use ManifestManager for unified local loading\n // This checks: .smrt/manifest.json -> dist/manifest.json\n const manager = new ManifestManager(process.cwd());\n const manifest = manager.loadLocal();\n\n // Fallback location: src/manifest/test-manifest.json\n // This is still used by smrt-core and other packages that generate test manifests here\n const testManifestPath = join(\n process.cwd(),\n 'src/manifest/test-manifest.json',\n );\n\n // If ManifestManager found a manifest, check if it has objects\n // If it has 0 objects but the fallback exists with objects, use the fallback instead\n // This handles the case where dist/manifest.json is the static-manifest.json (0 objects)\n // but src/manifest/test-manifest.json has the real test classes\n if (manifest) {\n const objectCount = Object.keys(manifest.objects).length;\n\n // If manifest has objects, use it\n if (objectCount > 0) {\n setLocalTestManifestCache(manifest);\n debugLog(\n `[manifest-loader] ✅ Loaded local manifest via ManifestManager (${objectCount} objects)`,\n );\n return manifest;\n }\n\n // Manifest has 0 objects - check if fallback has more\n if (existsSync(testManifestPath)) {\n try {\n const testManifest: Manifest = parse(\n readFileSync(testManifestPath, 'utf-8'),\n );\n const testObjectCount = Object.keys(testManifest.objects).length;\n\n if (testObjectCount > 0) {\n setLocalTestManifestCache(testManifest);\n debugLog(\n `[manifest-loader] ✅ Loaded test manifest from ${testManifestPath} (${testObjectCount} objects) - preferred over empty ManifestManager result`,\n );\n return testManifest;\n }\n } catch {\n // Fallback also failed, use the empty manifest\n }\n }\n\n // No better option, cache and use the empty manifest\n setLocalTestManifestCache(manifest);\n debugLog(\n `[manifest-loader] ✅ Loaded local manifest via ManifestManager (${objectCount} objects)`,\n );\n return manifest;\n }\n\n // ManifestManager returned null - check fallback\n if (existsSync(testManifestPath)) {\n try {\n const testManifest: Manifest = parse(\n readFileSync(testManifestPath, 'utf-8'),\n );\n setLocalTestManifestCache(testManifest);\n const objectCount = Object.keys(testManifest.objects).length;\n debugLog(\n `[manifest-loader] ✅ Loaded test manifest from ${testManifestPath} (${objectCount} objects)`,\n );\n return testManifest;\n } catch (error) {\n debugLog(\n `[manifest-loader] ✗ Failed to load test manifest from ${testManifestPath}: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n }\n\n // No manifest found - DON'T cache null, allow retries\n // This is important because the manifest may be generated later\n debugLog(\n '[manifest-loader] ⚠️ No local manifest found (will retry on next call)',\n );\n return null;\n}\n\n/**\n * Extract package name from class constructor\n *\n * Uses the ObjectRegistry (preferred) or fallback methods to determine\n * which package the class belongs to.\n *\n * Search order:\n * 1. ObjectRegistry (packageName injected at build time from manifest) - SKIPPED during initial registration\n * 2. __package__ metadata (build tooling can inject this)\n * 3. require.resolve() (resolves package.json from constructor file location)\n * 4. Error stack trace parsing (fallback, fragile in pnpm workspaces)\n *\n * @param ctor - Class constructor\n * @param skipRegistry - If true, skip checking ObjectRegistry (used during initial registration to avoid circular dependency)\n * @returns Package name (e.g., '@happyvertical/smrt-places') or null\n */\nexport function getPackageName(\n ctor: SmrtObjectConstructor,\n skipRegistry: boolean = false,\n): string | null {\n try {\n // 1. Try ObjectRegistry first (most reliable - from build-time manifest)\n // This solves issue #143 where pnpm workspace symlinks break stack trace parsing\n // CRITICAL: Skip during initial registration to avoid circular dependency (issue #159)\n if (!skipRegistry) {\n const className = ctor.name;\n if (className) {\n const registered = ObjectRegistry.getClass(className);\n if (registered?.packageName) {\n return registered.packageName;\n }\n }\n }\n\n // 2. Check if class has __package__ metadata (could be added by build tooling)\n const packageMeta = (ctor as { __package__?: string }).__package__;\n if (packageMeta) {\n return packageMeta;\n }\n\n // 3. Try require.resolve() to find package.json from constructor location\n // This is more reliable than stack trace parsing for published packages\n try {\n const error = new Error();\n const stack = error.stack || '';\n const stackLines = stack.split('\\n');\n\n // Find the first line with a file path that's NOT from smrt-core\n // Skip manifest-loader, registry, and other smrt-core files\n for (const line of stackLines) {\n const fileMatch = line.match(/\\(([^)]+\\.(?:js|ts))/);\n if (fileMatch) {\n const filePath = fileMatch[1];\n // Skip smrt-core internal files\n if (\n filePath.includes('manifest-loader') ||\n filePath.includes('registry') ||\n filePath.includes('/smrt-core/dist/')\n ) {\n continue; // Skip smrt-core files, look for external package\n }\n\n // Try to resolve package.json from this file\n try {\n // Handle file:// URLs\n const cleanPath = filePath.replace(/^file:\\/\\//, '');\n let dir = dirname(cleanPath);\n // Walk up until we find a package.json\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(dir, 'package.json');\n try {\n if (existsSync(pkgPath)) {\n const pkg = parse<{ name?: string }>(\n readFileSync(pkgPath, 'utf-8'),\n );\n if (pkg.name?.startsWith('@')) {\n return pkg.name;\n }\n }\n } catch {\n // Keep walking up\n }\n const parent = dirname(dir);\n if (parent === dir) break; // Reached root\n dir = parent;\n }\n } catch {\n // Fall through to next method\n }\n break;\n }\n }\n } catch {\n // Fall through to next method\n }\n\n // 4. Final fallback: Try to extract from Error stack trace with node_modules pattern\n // This method is fragile and fails in pnpm workspaces, but kept for backward compatibility\n const error = new Error();\n const stack = error.stack || '';\n const stackLines = stack.split('\\n');\n\n // Look for line with 'node_modules/@scope/package' pattern\n for (const line of stackLines) {\n const match = line.match(/node_modules\\/(@[^/]+\\/[^/]+)/);\n if (match) {\n return match[1];\n }\n }\n\n // Package name is now injected at build time into the manifest and stored in ObjectRegistry\n // If we reach here, the class is likely not from an external package\n return null;\n } catch {\n return null;\n }\n}\n\ninterface ManifestExportConditions {\n default?: string;\n import?: string;\n require?: string;\n}\n\ninterface ExternalPackageJson {\n exports?: Record<string, string | ManifestExportConditions>;\n}\n\nfunction findWorkspaceRoot(startDir: string): string | null {\n let currentDir = startDir;\n\n while (true) {\n if (existsSync(join(currentDir, 'pnpm-workspace.yaml'))) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n return null;\n }\n\n currentDir = parentDir;\n }\n}\n\nfunction resolveInstalledPackageJsonPath(packageName: string): string | null {\n let currentDir = process.cwd();\n\n while (true) {\n const packageJsonPath = join(\n currentDir,\n 'node_modules',\n packageName,\n 'package.json',\n );\n\n if (existsSync(packageJsonPath)) {\n return packageJsonPath;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n return null;\n }\n\n currentDir = parentDir;\n }\n}\n\nfunction resolveWorkspacePackageJsonPath(packageName: string): string | null {\n const workspaceRoot = findWorkspaceRoot(process.cwd());\n if (!workspaceRoot) {\n return null;\n }\n\n const workspacePackagesDir = join(workspaceRoot, 'packages');\n if (!existsSync(workspacePackagesDir)) {\n return null;\n }\n\n for (const packageDirName of readdirSync(workspacePackagesDir)) {\n const packageJsonPath = join(\n workspacePackagesDir,\n packageDirName,\n 'package.json',\n );\n if (!existsSync(packageJsonPath)) {\n continue;\n }\n\n try {\n const packageJson = parse<{ name?: string }>(\n readFileSync(packageJsonPath, 'utf-8'),\n );\n if (packageJson.name === packageName) {\n return packageJsonPath;\n }\n } catch {\n // Ignore unreadable workspace package metadata and continue scanning.\n }\n }\n\n return null;\n}\n\nfunction resolveWorkspaceSourceManifestPath(packageDir: string): string | null {\n const candidates = [\n join(packageDir, 'src', 'manifest', 'manifest.json'),\n join(packageDir, '.smrt', 'manifest.json'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\ninterface ManifestLoadOptions {\n warn?: boolean;\n}\n\nfunction resolveManifestExportPath(\n packageName: string,\n options: ManifestLoadOptions = {},\n): string | null {\n const shouldWarn = options.warn ?? true;\n const packageJsonPath =\n resolveInstalledPackageJsonPath(packageName) ||\n resolveWorkspacePackageJsonPath(packageName);\n\n if (!packageJsonPath) {\n return null;\n }\n\n const packageDir = dirname(packageJsonPath);\n const packageJson = parse<ExternalPackageJson>(\n readFileSync(packageJsonPath, 'utf-8'),\n );\n const manifestExports = ['./manifest.json', './manifest'];\n\n for (const exportKey of manifestExports) {\n const manifestExport = packageJson.exports?.[exportKey];\n if (!manifestExport) {\n continue;\n }\n\n const manifestRelativePath =\n typeof manifestExport === 'string'\n ? manifestExport\n : manifestExport.import ||\n manifestExport.default ||\n manifestExport.require;\n\n if (!manifestRelativePath) {\n if (shouldWarn) {\n logger.warn(\n `Package ${packageName} has invalid manifest export configuration for ${exportKey}`,\n );\n }\n return null;\n }\n\n if (!manifestRelativePath.endsWith('.json')) {\n if (shouldWarn) {\n logger.warn(\n `Package ${packageName} must export a JSON manifest for ${exportKey}, received ${manifestRelativePath}`,\n );\n }\n return null;\n }\n\n const manifestPath = join(packageDir, manifestRelativePath);\n if (existsSync(manifestPath)) {\n return manifestPath;\n }\n\n const workspaceSourceManifest =\n resolveWorkspaceSourceManifestPath(packageDir);\n if (workspaceSourceManifest) {\n return workspaceSourceManifest;\n }\n\n if (shouldWarn) {\n logger.warn(\n `Package ${packageName} declares manifest export ${manifestRelativePath}, but no manifest file was found.`,\n );\n }\n return null;\n }\n\n return null;\n}\n\nfunction collectDeclaredSmrtDependencies(\n manifests: Array<Manifest | null | undefined>,\n): string[] {\n const dependencies = new Set<string>();\n\n for (const manifest of manifests) {\n for (const pkg of manifest?.smrtDependencies || []) {\n dependencies.add(pkg);\n }\n }\n\n return Array.from(dependencies);\n}\n\n/**\n * Load manifest from external package\n *\n * Uses createRequire from process.cwd() to resolve packages from the calling\n * application's context, not from smrt-core's context. This allows finding\n * packages that are dependencies of the app but not of smrt-core.\n *\n * External packages export manifests via package.json:\n * \"exports\": { \"./manifest\": \"./dist/manifest.json\" }\n *\n * @param packageName - Package name (e.g., '@happyvertical/smrt-places')\n * @returns Manifest object or null if not found\n */\n/**\n * Load external package manifest synchronously\n * This is the synchronous version of loadExternalManifest for use during class registration\n */\nexport function loadExternalManifestSync(\n packageName: string,\n options: ManifestLoadOptions = {},\n): Manifest | null {\n // Check cache first\n if (getManifestCacheMap().has(packageName)) {\n debugLog(`[manifest-loader] Using cached manifest for ${packageName}`);\n return getManifestCacheMap().get(packageName)!;\n }\n\n debugLog(\n `[manifest-loader] Attempting to load external manifest for ${packageName}`,\n );\n\n const manifestPath = resolveManifestExportPath(packageName, options);\n\n if (!manifestPath) {\n debugLog(\n `[manifest-loader] Package ${packageName} does not expose a JSON manifest export`,\n );\n return null;\n }\n\n try {\n const manifest = parse<Manifest>(readFileSync(manifestPath, 'utf-8'));\n\n if (!manifest.objects || typeof manifest.objects !== 'object') {\n if (options.warn ?? true) {\n logger.warn(`Invalid manifest structure for package ${packageName}`);\n }\n return null;\n }\n\n const cachedManifest = manifest.packageName\n ? manifest\n : { ...manifest, packageName };\n\n getManifestCacheMap().set(packageName, cachedManifest);\n debugLog(\n `[manifest-loader] ✅ Loaded external manifest for ${packageName} (${Object.keys(cachedManifest.objects).length} objects)`,\n );\n\n return cachedManifest;\n } catch (error) {\n if (options.warn ?? true) {\n logger.warn(\n `Failed to load manifest for package ${packageName}: ${error instanceof Error ? error.message : error}`,\n );\n }\n return null;\n }\n}\n\nexport async function loadExternalManifest(\n packageName: string,\n options: ManifestLoadOptions = {},\n): Promise<Manifest | null> {\n // Delegate to synchronous version since all operations are sync anyway\n return loadExternalManifestSync(packageName, options);\n}\n\n/**\n * Load a manifest directly from a known file path and cache it by package name.\n *\n * This is used by workspace/dev flows where sibling packages may not be\n * installed into node_modules yet, but their generated manifests are still\n * available on disk.\n */\nexport function loadManifestFromPathSync(\n manifestPath: string,\n): Manifest | null {\n try {\n const manifestJson = readFileSync(manifestPath, 'utf-8');\n const manifest: Manifest = parse(manifestJson);\n\n if (!manifest.objects || typeof manifest.objects !== 'object') {\n logger.warn(`Invalid manifest structure at ${manifestPath}`);\n return null;\n }\n\n const cacheKey = manifest.packageName || manifestPath;\n getManifestCacheMap().set(cacheKey, manifest);\n debugLog(\n `[manifest-loader] ✅ Loaded manifest from path ${manifestPath} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n return manifest;\n } catch (error) {\n logger.warn(\n `Failed to load manifest from path ${manifestPath}: ${error instanceof Error ? error.message : error}`,\n );\n return null;\n }\n}\n\n/**\n * Discover manifest entry synchronously (checks only loaded manifests)\n *\n * Search order:\n * 1. localTestManifest (for domain package test classes)\n * 2. testManifest (for core test classes)\n * 3. staticManifest (for core framework classes)\n * 4. Cached external manifests\n *\n * @param className - Class name (for lookup)\n * @returns ManifestEntry or undefined if not found\n */\nexport function discoverManifestSync(\n className: string,\n): ManifestEntry | undefined {\n debugLog(`[manifest-loader] discoverManifestSync called for: ${className}`);\n\n // Ensure test-env caches are seeded before the composite queries them.\n // Historically, steps 1-2 of discoverManifestSync did this inline. The\n // composite's TestManifestSource and LocalTestManifestSource read directly\n // from cache state — without this seeding the first sync lookup in a\n // clean test process would miss core test classes on their first access\n // (regression noted in #1138 review).\n if (isTestEnvironment()) {\n if (!getLocalTestManifestCache()) {\n loadLocalTestManifestSync();\n }\n if (!getTestManifestCache()) {\n getTestManifest();\n }\n }\n\n // Carry qualified-name / package context into the composite lookup so\n // multi-package same-simple-name scenarios (issue #951) resolve to the\n // right manifest even via the sync path.\n const query = isQualifiedName(className)\n ? (() => {\n const parsed = parseQualifiedName(className);\n return {\n className: parsed.className,\n packageName: parsed.packageName,\n qualifiedName: className,\n };\n })()\n : { className };\n\n // Steps 1-4 (local-test → test → static → embedded cache) now live in\n // CompositeManifestSource at the exact same priority order.\n const compositeHit = getDefaultCompositeSource().lookup(query);\n if (compositeHit) {\n debugLog(\n `[manifest-loader] ✅ Found ${className} via ${compositeHit.source} source`,\n );\n const entry = compositeHit.def;\n if (!entry.packageName && compositeHit.packageName) {\n return { ...entry, packageName: compositeHit.packageName };\n }\n return entry;\n }\n\n // 5. Try loading from explicitly declared external SMRT package dependencies.\n debugLog(\n `[manifest-loader] ${className} not found in cached manifests, trying external packages...`,\n );\n\n const pendingPackages = collectDeclaredSmrtDependencies([\n getLocalTestManifestCache(),\n isTestEnvironment() ? getTestManifest() : null,\n getStaticManifest(),\n ...getManifestCacheMap().values(),\n ]);\n\n if (pendingPackages.length === 0) {\n debugLog(\n '[manifest-loader] No SMRT dependencies discovered. Run manifest generation if external packages are expected.',\n );\n }\n\n const visitedPackages = new Set<string>();\n\n while (pendingPackages.length > 0) {\n const pkg = pendingPackages.shift();\n if (!pkg || visitedPackages.has(pkg)) {\n continue;\n }\n\n visitedPackages.add(pkg);\n const manifest = loadExternalManifestSync(pkg);\n if (!manifest) {\n continue;\n }\n\n for (const dependency of manifest.smrtDependencies || []) {\n if (!visitedPackages.has(dependency)) {\n pendingPackages.push(dependency);\n }\n }\n\n // Use lookupInManifest for qualified name support (Issue #713)\n const entry = lookupInManifest(manifest, className);\n if (entry) {\n debugLog(\n `[manifest-loader] ✅ Found ${className} in external package ${pkg}`,\n );\n // Enrich entry with packageName from manifest if not already present\n if (!entry.packageName && manifest.packageName) {\n return { ...entry, packageName: manifest.packageName };\n }\n return entry;\n }\n }\n\n debugLog(`[manifest-loader] ❌ ${className} not found in any manifest`);\n return undefined;\n}\n\n// Note: manifestCollisions is now accessed via globalThis helper function\n// getManifestCollisionsMap()\n\n/**\n * Look up a manifest entry in a manifest's objects map.\n * Supports both qualified names and simple class names.\n *\n * Lookup order:\n * 1. Direct qualified name lookup (e.g., \"@happyvertical/smrt-core:Product\")\n * 2. Constructed qualified name (packageName + className)\n * 3. Search by className property (case-insensitive)\n *\n * @param manifest - The manifest to search in\n * @param nameOrQualified - Either a qualified name or simple class name\n * @returns ManifestEntry or undefined if not found\n */\nexport function lookupInManifest(\n manifest: SmartObjectManifest,\n nameOrQualified: string,\n): ManifestEntry | undefined {\n // 1. First try direct lookup (handles both qualified names and exact matches)\n if (manifest.objects[nameOrQualified]) {\n return manifest.objects[nameOrQualified];\n }\n\n // 2. Get the className index for O(1) lookups (instead of O(n) iteration)\n // This is the key optimization for issue #729\n const classNameIndex = getClassNameIndex(manifest);\n\n // 3. If input is a qualified name, extract className and use index\n if (isQualifiedName(nameOrQualified)) {\n const { className } = parseQualifiedName(nameOrQualified);\n return classNameIndex.get(className.toLowerCase());\n }\n\n // 4. For simple class names, try constructing qualified name if manifest has packageName\n if (manifest.packageName) {\n const qualifiedKey = createQualifiedName(\n manifest.packageName,\n nameOrQualified,\n );\n if (manifest.objects[qualifiedKey]) {\n return manifest.objects[qualifiedKey];\n }\n }\n\n // 5. Use index for O(1) className lookup (instead of O(n) iteration)\n return classNameIndex.get(nameOrQualified.toLowerCase());\n}\n\n/**\n * Find a manifest entry by qualified name across all loaded manifests.\n *\n * @param qualifiedName - The fully qualified class name (e.g., \"@happyvertical/smrt-core:Product\")\n * @returns ManifestEntry or undefined if not found\n */\nexport function findManifestEntryByQualifiedName(\n qualifiedName: string,\n): ManifestEntry | undefined {\n if (!isQualifiedName(qualifiedName)) {\n return undefined;\n }\n\n const { packageName } = parseQualifiedName(qualifiedName);\n\n // Check if we have the package's manifest cached\n const manifest = getManifestCacheMap().get(packageName);\n if (manifest) {\n // Try qualified name first, then fallback to simple names\n return lookupInManifest(manifest, qualifiedName);\n }\n\n // Check static manifest\n const staticManifestData = getStaticManifest();\n if (staticManifestData.packageName === packageName) {\n return lookupInManifest(staticManifestData, qualifiedName);\n }\n\n // Check test manifest (if in test environment)\n if (isTestEnvironment()) {\n const testManifest = getTestManifest();\n if (testManifest?.packageName === packageName) {\n return lookupInManifest(testManifest, qualifiedName);\n }\n\n // Check local test manifest\n const localTest = getLocalTestManifestCache();\n if (localTest?.packageName === packageName) {\n return lookupInManifest(localTest, qualifiedName);\n }\n }\n\n return undefined;\n}\n\n/**\n * Discover manifest entry asynchronously (includes external package loading)\n *\n * Search order:\n * 1. External package manifest (for constructor's package) - PRIORITIZED\n * 2. testManifest (for test classes)\n * 3. staticManifest (for core framework classes)\n * 4. Cached external manifests\n *\n * This function now detects and reports class name collisions across packages.\n *\n * @param ctor - Class constructor\n * @param className - Class name (for lookup)\n * @returns ManifestEntry or undefined if not found\n * @throws {Error} If class name collision detected across different packages\n */\nexport async function discoverManifestEntry(\n ctor: SmrtObjectConstructor,\n className: string,\n): Promise<ManifestEntry | undefined> {\n // ✅ FAST PATH: O(1) constructor-based lookup for already-registered classes\n // Skip manifest scanning if we already know this constructor's qualified name via WeakMap\n // This provides instant resolution and prevents collisions (each constructor is unique in memory)\n if (!(ctor as { _isManifestStub?: boolean })._isManifestStub) {\n const registered = ObjectRegistry.getClassByConstructor(ctor);\n if (\n registered?.qualifiedName &&\n isQualifiedName(registered.qualifiedName)\n ) {\n // Parse package name from qualified name (format: \"@package/name:ClassName\")\n const { packageName } = parseQualifiedName(registered.qualifiedName);\n\n const cachedManifest = getManifestCacheMap().get(packageName);\n if (cachedManifest) {\n const cachedEntry = lookupInManifest(\n cachedManifest,\n registered.qualifiedName,\n );\n if (cachedEntry) {\n return !cachedEntry.packageName && cachedManifest.packageName\n ? { ...cachedEntry, packageName: cachedManifest.packageName }\n : cachedEntry;\n }\n }\n\n // Load the manifest for this specific package before trusting any\n // existing runtime field metadata. Imported external classes can be\n // registered with only a partial field set until their manifest is\n // hydrated, which is exactly what happens with STI parents like Event.\n const manifest = await loadExternalManifest(packageName, {\n warn: registered.fields.size === 0,\n });\n if (manifest) {\n // Look up the entry using the qualified name (exact match)\n const entry = lookupInManifest(manifest, registered.qualifiedName);\n if (entry) {\n // Enrich entry with package name if missing\n return !entry.packageName && manifest.packageName\n ? { ...entry, packageName: manifest.packageName }\n : entry;\n }\n }\n\n // Source-registered classes with explicit field metadata do not need a\n // second manifest probe from fallback discovery when the package did not\n // resolve to a manifest. This keeps workspace/dev runtimes from spamming\n // missing-dist-manifest warnings for packages that are already fully\n // usable from source.\n if (registered.fields.size > 0) {\n return undefined;\n }\n }\n }\n\n // FALLBACK: Original manifest scanning logic for:\n // - First-time registration (WeakMap not populated yet)\n // - Manifest stubs (not in WeakMap)\n // - Undecorated classes (never registered)\n const name = className.toLowerCase();\n const constructorPackage = getPackageName(ctor);\n\n // Track all manifest sources that define this class\n const foundEntries: Array<{\n entry: ManifestEntry;\n packageName: string;\n filePath?: string;\n manifestSource: string;\n }> = [];\n\n // Build qualified name for lookup if we have package context\n const qualifiedName = constructorPackage\n ? createQualifiedName(constructorPackage, className)\n : undefined;\n\n // 2. Check localTestManifest first (domain package test classes) - ONLY in test environment\n // Do this BEFORE loading external manifest to avoid duplicate loading\n let localEntry: SmartObjectDefinition | undefined;\n if (isTestEnvironment()) {\n if (getLocalTestManifestCache() === undefined) {\n loadLocalTestManifestSync();\n }\n const localManifest = getLocalTestManifestCache();\n if (localManifest) {\n // Use lookupInManifest for consistent qualified name handling\n localEntry = lookupInManifest(localManifest, qualifiedName || className);\n if (localEntry) {\n foundEntries.push({\n entry: localEntry,\n packageName: localManifest.packageName || 'local-test',\n filePath: localEntry.filePath,\n manifestSource: 'local test manifest',\n });\n }\n }\n }\n\n // 1. PRIORITY: Try loading from the constructor's package first\n // BUT skip if it's the same package as the local test manifest to avoid collisions\n if (constructorPackage) {\n const skipExternal =\n getLocalTestManifestCache()?.packageName &&\n constructorPackage === getLocalTestManifestCache()?.packageName;\n\n if (!skipExternal) {\n const manifest = await loadExternalManifest(constructorPackage);\n if (manifest) {\n // Use lookupInManifest for consistent qualified name handling\n const entry = lookupInManifest(manifest, qualifiedName || className);\n if (entry) {\n const enrichedEntry =\n !entry.packageName && manifest.packageName\n ? { ...entry, packageName: manifest.packageName }\n : entry;\n\n foundEntries.push({\n entry: enrichedEntry,\n packageName: manifest.packageName || constructorPackage,\n filePath: entry.filePath,\n manifestSource: `${manifest.packageName || constructorPackage}/manifest.json`,\n });\n }\n }\n }\n }\n\n // 3. Check testManifest (core test classes) - ONLY in test environment\n // Skip if we already loaded a local test manifest (avoids duplicate entries from same package)\n if (isTestEnvironment() && (!getLocalTestManifestCache() || !localEntry)) {\n const manifest = getTestManifest();\n if (manifest) {\n // Use lookupInManifest for consistent qualified name handling\n const testEntry = lookupInManifest(manifest, qualifiedName || className);\n if (testEntry) {\n foundEntries.push({\n entry: testEntry,\n packageName: manifest.packageName || '@happyvertical/smrt-core',\n filePath: testEntry.filePath,\n manifestSource: '@happyvertical/smrt-core test manifest',\n });\n }\n }\n }\n\n // 4. Check staticManifest (core framework classes)\n const staticManifestData = getStaticManifest();\n // Use lookupInManifest for consistent qualified name handling\n const staticEntry = lookupInManifest(\n staticManifestData,\n qualifiedName || className,\n );\n if (staticEntry) {\n foundEntries.push({\n entry: staticEntry,\n packageName: staticManifestData.packageName || '@happyvertical/smrt-core',\n filePath: staticEntry.filePath,\n manifestSource: '@happyvertical/smrt-core static manifest',\n });\n }\n\n // 5. Check other cached external manifests\n for (const [cachedPkgName, manifest] of getManifestCacheMap().entries()) {\n // Skip if this is the constructor's package (already checked above)\n if (cachedPkgName === constructorPackage) {\n continue;\n }\n\n // Use lookupInManifest for consistent qualified name handling\n const entry = lookupInManifest(manifest, qualifiedName || className);\n if (entry) {\n foundEntries.push({\n entry:\n !entry.packageName && manifest.packageName\n ? { ...entry, packageName: manifest.packageName }\n : entry,\n packageName: manifest.packageName || cachedPkgName,\n filePath: entry.filePath,\n manifestSource: `${manifest.packageName || cachedPkgName}/manifest.json`,\n });\n }\n }\n\n // Deduplicate entries that reference the same source file.\n // Consumer manifests (e.g. smrt-users, dashboard) re-export classes from\n // upstream packages (e.g. smrt-profiles). These appear in multiple manifests\n // but point to the same filePath — they are NOT real collisions.\n if (foundEntries.length > 1) {\n const uniqueByFile = new Map<string, (typeof foundEntries)[0]>();\n for (const entry of foundEntries) {\n // Normalize file paths so the same source file with different absolute\n // prefixes (local dev vs CI build) is recognized as identical.\n // Extract the relative path from the last \"packages/\" segment onward.\n let key = entry.filePath || `${entry.packageName}:${className}`;\n if (entry.filePath) {\n const pkgIdx = entry.filePath.lastIndexOf('packages/');\n if (pkgIdx !== -1) {\n key = entry.filePath.slice(pkgIdx);\n }\n }\n if (!uniqueByFile.has(key)) {\n uniqueByFile.set(key, entry);\n }\n }\n\n if (uniqueByFile.size === 1) {\n // All entries point to the same source file — not a real collision.\n // Use the first (highest priority) entry.\n foundEntries.splice(1);\n } else if (uniqueByFile.size > 1) {\n // True collision: different source files define the same class name\n const collisionInfo = foundEntries.map(\n (f) =>\n ` - ${f.packageName} (${f.filePath || 'unknown file'}) from ${f.manifestSource}`,\n );\n\n // Store collision info for reporting\n getManifestCollisionsMap().set(\n className,\n foundEntries.map((f) => ({\n packageName: f.packageName,\n filePath: f.filePath,\n manifestSource: f.manifestSource,\n })),\n );\n\n // Throw error on collision\n throw new Error(\n `SMRT Class Name Collision Detected: \"${className}\"\\n\\n` +\n `This class is defined in multiple packages:\\n${collisionInfo.join('\\n')}\\n\\n` +\n `The collision will cause the wrong field definitions to be used,\\n` +\n `leading to properties not being initialized correctly.\\n\\n` +\n `To fix:\\n` +\n ` 1. Use unique class names across packages (e.g., ${className}_${constructorPackage?.split('/').pop() || 'Unique'})\\n` +\n ` 2. Or use @smrt({ name: 'unique_name' }) to override the registration name\\n` +\n ` 3. Remove test classes with conflicting names from production manifests\\n\\n` +\n `If this is a test class collision, ensure test manifests are not included in production builds.`,\n );\n }\n }\n\n // Return the found entry (priority given to constructor's package)\n if (foundEntries.length === 1) {\n return foundEntries[0].entry;\n }\n\n return undefined;\n}\n\n/**\n * Get all detected manifest collisions\n *\n * @returns Map of class names to array of collision info\n */\nexport function getManifestCollisions(): Map<\n string,\n Array<{ packageName: string; filePath?: string; manifestSource: string }>\n> {\n return new Map(getManifestCollisionsMap());\n}\n\n/**\n * Clear manifest cache\n *\n * Useful for testing or when packages are updated at runtime.\n */\nexport function clearManifestCache(): void {\n // Reset all cached manifest state so tests/dev tooling can force a full\n // rediscovery pass on the next lookup.\n setStaticManifestCache(undefined);\n setStaticManifestLoadAttempted(false);\n setTestManifestCache(undefined);\n setTestManifestLoadAttempted(false);\n setLocalTestManifestCache(undefined);\n getManifestCacheMap().clear();\n getManifestCollisionsMap().clear();\n getSTISiblingCache().clear();\n}\n\n/**\n * Get all loaded manifests\n *\n * Returns a copy of the manifest cache for inspection.\n *\n * @returns Array of [packageName, manifest] entries\n */\nexport function getLoadedManifests(): Array<[string, Manifest]> {\n return Array.from(getManifestCacheMap().entries());\n}\n\n/**\n * Discover all STI sibling classes that share the same collection (table)\n *\n * This is critical for STI schema merging: when one subtype is accessed,\n * we need to discover ALL subtypes sharing the same table so that the\n * database adapter receives a complete schema with all columns.\n *\n * Scans all available manifests:\n * 1. Local test manifest (for test classes)\n * 2. Test manifest (for core test classes)\n * 3. Static manifest (for core framework classes)\n * 4. Cached external manifests\n * 5. SMRT dependencies from local test manifest\n *\n * @param collection - The collection/table name to find siblings for\n * @returns Array of manifest entries that share the same collection\n */\nexport function discoverSTISiblingsSync(\n collection: string,\n): Array<{ className: string; entry: ManifestEntry; packageName?: string }> {\n // Check cache first to avoid repeated scans (fixes #644)\n const cache = getSTISiblingCache();\n const cached = cache.get(collection);\n if (cached !== undefined) {\n return cached;\n }\n\n const siblings: Array<{\n className: string;\n entry: ManifestEntry;\n packageName?: string;\n }> = [];\n\n // Track already-found class names to avoid duplicates (case-insensitive)\n // Use lowercase keys to prevent both 'praeco' and 'Praeco' from being added\n const foundClasses = new Set<string>();\n\n debugLog(\n `[manifest-loader] discoverSTISiblingsSync called for collection: ${collection}`,\n );\n\n // Helper to add entries from a manifest\n const addFromManifest = (\n manifest: Manifest | null | undefined,\n source: string,\n ) => {\n if (!manifest?.objects) return;\n\n for (const [key, entry] of Object.entries(manifest.objects) as [\n string,\n ManifestEntry,\n ][]) {\n // Check if this entry uses the same collection (table)\n if (entry.collection === collection) {\n const className = entry.className || key;\n // Use case-insensitive check to prevent registering both 'praeco' and 'Praeco'\n const lowerClassName = className.toLowerCase();\n if (!foundClasses.has(lowerClassName)) {\n foundClasses.add(lowerClassName);\n siblings.push({\n className,\n entry,\n packageName: entry.packageName || manifest.packageName,\n });\n debugLog(\n `[manifest-loader] Found STI sibling: ${className} (collection: ${collection}) from ${source}`,\n );\n }\n }\n }\n };\n\n // 1. Check local test manifest (domain package test classes)\n if (isTestEnvironment()) {\n if (!getLocalTestManifestCache()) {\n loadLocalTestManifestSync();\n }\n addFromManifest(getLocalTestManifestCache(), 'localTestManifest');\n }\n\n // 2. Check test manifest (core test classes)\n const testManifestData = isTestEnvironment() ? getTestManifest() : null;\n if (testManifestData) {\n addFromManifest(testManifestData, 'testManifest');\n }\n\n // 3. Check static manifest (core framework classes)\n const staticManifestData = getStaticManifest();\n addFromManifest(staticManifestData, 'staticManifest');\n\n // 4. Check cached external manifests\n for (const [pkgName, manifest] of getManifestCacheMap().entries()) {\n addFromManifest(manifest, `manifestCache:${pkgName}`);\n }\n\n // 5. Try loading from SMRT dependencies from ALL manifests (not just localTestManifest)\n // This ensures production environments also discover STI siblings\n const pendingDependencies = collectDeclaredSmrtDependencies([\n getLocalTestManifestCache(),\n isTestEnvironment() ? testManifestData : null,\n staticManifestData,\n ...getManifestCacheMap().values(),\n ]);\n const visitedDependencies = new Set<string>();\n\n debugLog(\n `[manifest-loader] Scanning ${pendingDependencies.length} SMRT dependencies for STI siblings: ${pendingDependencies.join(', ')}`,\n );\n\n while (pendingDependencies.length > 0) {\n const pkg = pendingDependencies.shift();\n if (!pkg || visitedDependencies.has(pkg)) {\n continue;\n }\n\n visitedDependencies.add(pkg);\n\n const manifest = loadExternalManifestSync(pkg);\n if (manifest) {\n addFromManifest(manifest, `smrtDependency:${pkg}`);\n\n for (const dependency of manifest.smrtDependencies || []) {\n if (!visitedDependencies.has(dependency)) {\n pendingDependencies.push(dependency);\n }\n }\n }\n }\n\n debugLog(\n `[manifest-loader] discoverSTISiblingsSync found ${siblings.length} siblings for collection: ${collection}`,\n );\n\n // Cache the results for future calls (fixes #644)\n cache.set(collection, siblings);\n\n return siblings;\n}\n"],"names":["getStaticManifestCacheFromStore","getTestManifestCacheFromStore","getLocalTestManifestCacheFromStore","getManifestCacheFromStore","require","isTestEnvFromStore","error","stack","stackLines"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manifest-loader.js","sources":["../../src/manifest/manifest-loader.ts"],"sourcesContent":["/**\n * Manifest Loader - Automatic discovery of external package manifests\n *\n * This module provides automatic loading of SMRT manifests from external packages,\n * solving issue #131 where external package schemas weren't being detected.\n *\n * Architecture:\n * - Build-time: AST scanner generates manifests in dist/manifest.json\n * - Run-time: This module discovers and loads those manifests automatically\n * - Caching: Loaded manifests are cached to avoid repeated imports\n *\n * Flow:\n * 1. Check testManifest (for test classes)\n * 2. Check staticManifest (for core framework classes)\n * 3. Resolve external package manifests from explicit JSON exports\n * 4. Return manifest entry or undefined\n *\n * External manifest loading intentionally follows a pure-ESM JSON contract.\n * Packages are expected to publish a JSON manifest via \"./manifest\" and/or\n * \"./manifest.json\" exports. Runtime discovery does not guess sibling workspace\n * paths or load JavaScript manifest modules.\n */\n\nimport { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { createLogger } from '@happyvertical/logger';\nimport type { SmrtObjectConstructor } from '../registry/types.js';\nimport { ObjectRegistry } from '../registry.js';\nimport type {\n FieldDefinition,\n MethodDefinition,\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types.js';\nimport { parse } from '../utils/json.js';\nimport {\n createQualifiedName,\n isQualifiedName,\n parseQualifiedName,\n} from '../utils/qualified-names.js';\nimport { ManifestManager } from './manager.js';\nimport { getDefaultCompositeSource } from './sources/composite.js';\nimport {\n getLocalTestManifestCache as getLocalTestManifestCacheFromStore,\n getManifestCache as getManifestCacheFromStore,\n getStaticManifestCache as getStaticManifestCacheFromStore,\n getTestManifestCache as getTestManifestCacheFromStore,\n isTestEnvironment as isTestEnvFromStore,\n shouldLoadCoreTestManifest,\n} from './store.js';\n\n/**\n * Extend globalThis to include manifest loader state.\n * Using globalThis ensures all module instances share the same manifest caches,\n * which is critical in monorepos where the same package can be loaded\n * from different paths (e.g., pnpm store vs workspace symlink).\n *\n * @see https://github.com/happyvertical/smrt/issues/543\n */\ndeclare global {\n // eslint-disable-next-line no-var\n var __smrtManifestStatic: SmartObjectManifest | null | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestStaticLoadAttempted: boolean | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestTest: SmartObjectManifest | null | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestTestLoadAttempted: boolean | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestCache: Map<string, SmartObjectManifest> | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestLocalTest: SmartObjectManifest | null | undefined;\n // eslint-disable-next-line no-var\n var __smrtManifestCollisions:\n | Map<\n string,\n Array<{\n packageName: string;\n filePath?: string;\n manifestSource: string;\n }>\n >\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtSTISiblingCache:\n | Map<\n string,\n Array<{ className: string; entry: ManifestEntry; packageName?: string }>\n >\n | undefined;\n}\n\n// Use globalThis for cross-module state sharing\n// This ensures loadConfig() in one module instance affects all packages\n\n// ── Cache access (delegates to manifest/store.ts — the single source of\n// truth added in Release B #1133 for globalThis manifest state).\n// manifest-loader.ts keeps its own setters + load-attempted flags below\n// because those are internal to this module's async loader state machine;\n// the read-only getters just forward to store.ts to eliminate drift.\n\nconst getStaticManifestCache = getStaticManifestCacheFromStore;\nconst getTestManifestCache = getTestManifestCacheFromStore;\nconst getLocalTestManifestCache = getLocalTestManifestCacheFromStore;\nconst getManifestCacheMap = getManifestCacheFromStore;\n\nfunction setStaticManifestCache(\n manifest: SmartObjectManifest | null | undefined,\n): void {\n globalThis.__smrtManifestStatic = manifest;\n}\n\nfunction getStaticManifestLoadAttempted(): boolean {\n return globalThis.__smrtManifestStaticLoadAttempted ?? false;\n}\n\nfunction setStaticManifestLoadAttempted(value: boolean): void {\n globalThis.__smrtManifestStaticLoadAttempted = value;\n}\n\nfunction setTestManifestCache(\n manifest: SmartObjectManifest | null | undefined,\n): void {\n globalThis.__smrtManifestTest = manifest;\n}\n\nfunction getTestManifestLoadAttempted(): boolean {\n return globalThis.__smrtManifestTestLoadAttempted ?? false;\n}\n\nfunction setTestManifestLoadAttempted(value: boolean): void {\n globalThis.__smrtManifestTestLoadAttempted = value;\n}\n\nfunction setLocalTestManifestCache(\n manifest: SmartObjectManifest | null | undefined,\n): void {\n globalThis.__smrtManifestLocalTest = manifest;\n}\n\n/**\n * Get the manifest collisions Map from globalThis\n */\nfunction getManifestCollisionsMap(): Map<\n string,\n Array<{ packageName: string; filePath?: string; manifestSource: string }>\n> {\n if (!globalThis.__smrtManifestCollisions) {\n globalThis.__smrtManifestCollisions = new Map();\n }\n return globalThis.__smrtManifestCollisions;\n}\n\n/**\n * Get the STI sibling cache Map from globalThis\n * Caches discoverSTISiblingsSync results per collection to avoid repeated scans\n */\nfunction getSTISiblingCache(): Map<\n string,\n Array<{ className: string; entry: ManifestEntry; packageName?: string }>\n> {\n if (!globalThis.__smrtSTISiblingCache) {\n globalThis.__smrtSTISiblingCache = new Map();\n }\n return globalThis.__smrtSTISiblingCache;\n}\n\n// Create require function once for reuse\nconst require = createRequire(import.meta.url);\n\n/**\n * Cached debug flag evaluated once at module load time.\n * Environment variables don't change at runtime, so this is safe.\n * @see https://github.com/happyvertical/smrt/issues/729\n */\nconst DEBUG_ENABLED =\n process.env.DEBUG_MANIFEST === 'true' ||\n process.env.DEBUG_MANIFEST === '1' ||\n process.env.DEBUG?.includes('manifest') ||\n false;\n\n// The debug traces below are gated by DEBUG_MANIFEST / DEBUG_TEST_ENV, so the\n// logger level must allow debug when either is set (a fixed 'info' would filter\n// them out and silently break those debug switches).\nconst logger = createLogger({\n level: DEBUG_ENABLED || process.env.DEBUG_TEST_ENV ? 'debug' : 'info',\n});\n\n/**\n * Log a debug message only if DEBUG_MANIFEST is enabled.\n * Uses cached boolean check instead of repeated env var access.\n */\nfunction debugLog(message: string): void {\n if (DEBUG_ENABLED) {\n logger.debug(message);\n }\n}\n\n/**\n * Cache for className-to-entry index per manifest.\n * This enables O(1) lookup by className instead of O(n) iteration.\n * @see https://github.com/happyvertical/smrt/issues/729\n */\nconst classNameIndexCache = new WeakMap<\n SmartObjectManifest,\n Map<string, SmartObjectDefinition>\n>();\n\n/**\n * Get or build the className index for a manifest.\n * Index maps lowercase className to entry for O(1) lookup.\n */\nfunction getClassNameIndex(\n manifest: SmartObjectManifest,\n): Map<string, SmartObjectDefinition> {\n let index = classNameIndexCache.get(manifest);\n if (!index) {\n index = new Map<string, SmartObjectDefinition>();\n for (const [key, entry] of Object.entries(manifest.objects)) {\n const name = (entry.className || key).toLowerCase();\n if (!index.has(name)) {\n index.set(name, entry);\n } else {\n const existing = index.get(name)!;\n const existingName = (existing.className || '').toLowerCase();\n const newExtends = (entry.extends || '').toLowerCase();\n const existingExtends = (existing.extends || '').toLowerCase();\n\n // Issue #950: STI child-wins — if new entry extends existing, replace\n if (\n newExtends &&\n (newExtends === existingName || newExtends === name)\n ) {\n index.set(name, entry);\n debugLog(\n `Manifest className '${name}': child '${key}' replaces parent`,\n );\n } else if (\n existingExtends &&\n (existingExtends === (entry.className || key).toLowerCase() ||\n existingExtends === name)\n ) {\n // Existing is already the child, keep it\n debugLog(\n `Manifest className '${name}': keeping child, ignoring parent '${key}'`,\n );\n } else {\n debugLog(\n `Manifest className collision for '${name}': keeping first, ignoring key '${key}'`,\n );\n }\n }\n }\n classNameIndexCache.set(manifest, index);\n }\n return index;\n}\n\n/**\n * Test-environment detection with optional DEBUG_TEST_ENV logging.\n *\n * Delegates to the single source of truth in `store.ts` so the\n * ManifestSource implementations (which also gate on test-env) cannot\n * drift from the legacy sync loader. The logging wrapper stays here\n * because the trace is specific to this module's loader state machine.\n */\nfunction isTestEnvironment(): boolean {\n const result = isTestEnvFromStore();\n\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug('[manifest-loader] isTestEnvironment check', {\n NODE_ENV: process.env.NODE_ENV,\n VITEST: process.env.VITEST,\n JEST_WORKER_ID: process.env.JEST_WORKER_ID,\n result,\n });\n }\n\n return result;\n}\n\nfunction getStaticManifest(): SmartObjectManifest {\n if (!getStaticManifestLoadAttempted()) {\n setStaticManifestLoadAttempted(true);\n try {\n // Try to import the generated static manifest\n const imported = require('./static-manifest.js');\n setStaticManifestCache(imported.staticManifest || imported.default);\n } catch {\n // Fallback to empty manifest if file doesn't exist yet (during build)\n setStaticManifestCache({\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n packageName: '@happyvertical/smrt-core',\n });\n }\n }\n return getStaticManifestCache()!;\n}\n\n/**\n * Lazy-load smrt-core's internal test manifest only for smrt-core's own tests.\n * Consumer packages should never see these fixtures, or they can collide with\n * real external classes during downstream test runs.\n */\nfunction getTestManifest(): SmartObjectManifest | null {\n if (!getTestManifestLoadAttempted()) {\n setTestManifestLoadAttempted(true);\n\n // CRITICAL: Scope the core test manifest to smrt-core's own test suite.\n if (!shouldLoadCoreTestManifest()) {\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug(\n '[manifest-loader] ⚠️ Skipping core test manifest load (not smrt-core test environment)',\n );\n }\n setTestManifestCache(null);\n return null;\n }\n\n try {\n // Dynamically import test manifest to avoid loading in production\n const imported = require('./test-manifest-stub.js');\n const manifest = imported.testManifest || imported.default;\n setTestManifestCache(manifest);\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug(\n `[manifest-loader] ✅ Loaded test manifest (${Object.keys(manifest?.objects || {}).length} objects)`,\n );\n }\n } catch (error) {\n if (process.env.DEBUG_TEST_ENV) {\n logger.debug(\n '[manifest-loader] ⚠️ Test manifest not found (this is normal in production)',\n );\n }\n setTestManifestCache(null);\n }\n }\n return getTestManifestCache();\n}\n\n// Re-export types for convenience\nexport type Manifest = SmartObjectManifest;\nexport type ManifestEntry = SmartObjectDefinition;\nexport type { FieldDefinition, MethodDefinition };\n\n// Note: manifestCache and localTestManifest are now accessed via globalThis helper functions\n// getManifestCacheMap() and getLocalTestManifestCache()/setLocalTestManifestCache()\n\n/**\n * Load local test manifest from current package (synchronous)\n *\n * During test runs, packages can have manifests in two locations:\n * 1. src/manifest/test-manifest.json - Domain packages during development\n * 2. dist/manifest.json - Built packages (consuming apps like praeco)\n *\n * This function attempts to load the manifest from either location.\n *\n * @returns Loaded manifest or null if not found or undefined if not yet attempted\n */\nexport function loadLocalTestManifestSync(): Manifest | null | undefined {\n // Only return cached manifest if it was successfully loaded\n // Don't cache null (failed loads) - allow retries\n const cached = getLocalTestManifestCache();\n if (cached !== undefined && cached !== null) {\n return cached;\n }\n\n // Use ManifestManager for unified local loading\n // This checks: .smrt/manifest.json -> dist/manifest.json\n const manager = new ManifestManager(process.cwd());\n const manifest = manager.loadLocal();\n\n // Fallback location: src/manifest/test-manifest.json\n // This is still used by smrt-core and other packages that generate test manifests here\n const testManifestPath = join(\n process.cwd(),\n 'src/manifest/test-manifest.json',\n );\n\n // If ManifestManager found a manifest, check if it has objects\n // If it has 0 objects but the fallback exists with objects, use the fallback instead\n // This handles the case where dist/manifest.json is the static-manifest.json (0 objects)\n // but src/manifest/test-manifest.json has the real test classes\n if (manifest) {\n const objectCount = Object.keys(manifest.objects).length;\n\n // If manifest has objects, use it\n if (objectCount > 0) {\n setLocalTestManifestCache(manifest);\n debugLog(\n `[manifest-loader] ✅ Loaded local manifest via ManifestManager (${objectCount} objects)`,\n );\n return manifest;\n }\n\n // Manifest has 0 objects - check if fallback has more\n if (existsSync(testManifestPath)) {\n try {\n const testManifest: Manifest = parse(\n readFileSync(testManifestPath, 'utf-8'),\n );\n const testObjectCount = Object.keys(testManifest.objects).length;\n\n if (testObjectCount > 0) {\n setLocalTestManifestCache(testManifest);\n debugLog(\n `[manifest-loader] ✅ Loaded test manifest from ${testManifestPath} (${testObjectCount} objects) - preferred over empty ManifestManager result`,\n );\n return testManifest;\n }\n } catch {\n // Fallback also failed, use the empty manifest\n }\n }\n\n // No better option, cache and use the empty manifest\n setLocalTestManifestCache(manifest);\n debugLog(\n `[manifest-loader] ✅ Loaded local manifest via ManifestManager (${objectCount} objects)`,\n );\n return manifest;\n }\n\n // ManifestManager returned null - check fallback\n if (existsSync(testManifestPath)) {\n try {\n const testManifest: Manifest = parse(\n readFileSync(testManifestPath, 'utf-8'),\n );\n setLocalTestManifestCache(testManifest);\n const objectCount = Object.keys(testManifest.objects).length;\n debugLog(\n `[manifest-loader] ✅ Loaded test manifest from ${testManifestPath} (${objectCount} objects)`,\n );\n return testManifest;\n } catch (error) {\n debugLog(\n `[manifest-loader] ✗ Failed to load test manifest from ${testManifestPath}: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n }\n\n // No manifest found - DON'T cache null, allow retries\n // This is important because the manifest may be generated later\n debugLog(\n '[manifest-loader] ⚠️ No local manifest found (will retry on next call)',\n );\n return null;\n}\n\n/**\n * Extract package name from class constructor\n *\n * Uses the ObjectRegistry (preferred) or fallback methods to determine\n * which package the class belongs to.\n *\n * Search order:\n * 1. ObjectRegistry (packageName injected at build time from manifest) - SKIPPED during initial registration\n * 2. __package__ metadata (build tooling can inject this)\n * 3. require.resolve() (resolves package.json from constructor file location)\n * 4. Error stack trace parsing (fallback, fragile in pnpm workspaces)\n *\n * @param ctor - Class constructor\n * @param skipRegistry - If true, skip checking ObjectRegistry (used during initial registration to avoid circular dependency)\n * @returns Package name (e.g., '@happyvertical/smrt-places') or null\n */\nexport function getPackageName(\n ctor: SmrtObjectConstructor,\n skipRegistry: boolean = false,\n): string | null {\n try {\n // 1. Try ObjectRegistry first (most reliable - from build-time manifest)\n // This solves issue #143 where pnpm workspace symlinks break stack trace parsing\n // CRITICAL: Skip during initial registration to avoid circular dependency (issue #159)\n if (!skipRegistry) {\n const className = ctor.name;\n if (className) {\n const registered = ObjectRegistry.getClass(className);\n if (registered?.packageName) {\n return registered.packageName;\n }\n }\n }\n\n // 2. Check if class has __package__ metadata (could be added by build tooling)\n const packageMeta = (ctor as { __package__?: string }).__package__;\n if (packageMeta) {\n return packageMeta;\n }\n\n // 3. Try require.resolve() to find package.json from constructor location\n // This is more reliable than stack trace parsing for published packages\n try {\n const error = new Error();\n const stack = error.stack || '';\n const stackLines = stack.split('\\n');\n\n // Find the first line with a file path that's NOT from smrt-core\n // Skip manifest-loader, registry, and other smrt-core files\n for (const line of stackLines) {\n const fileMatch = line.match(/\\(([^)]+\\.(?:js|ts))/);\n if (fileMatch) {\n const filePath = fileMatch[1];\n // Skip smrt-core internal files\n if (\n filePath.includes('manifest-loader') ||\n filePath.includes('registry') ||\n filePath.includes('/smrt-core/dist/')\n ) {\n continue; // Skip smrt-core files, look for external package\n }\n\n // Try to resolve package.json from this file\n try {\n // Handle file:// URLs\n const cleanPath = filePath.replace(/^file:\\/\\//, '');\n let dir = dirname(cleanPath);\n // Walk up until we find a package.json\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(dir, 'package.json');\n try {\n if (existsSync(pkgPath)) {\n const pkg = parse<{ name?: string }>(\n readFileSync(pkgPath, 'utf-8'),\n );\n if (pkg.name?.startsWith('@')) {\n return pkg.name;\n }\n }\n } catch {\n // Keep walking up\n }\n const parent = dirname(dir);\n if (parent === dir) break; // Reached root\n dir = parent;\n }\n } catch {\n // Fall through to next method\n }\n break;\n }\n }\n } catch {\n // Fall through to next method\n }\n\n // 4. Final fallback: Try to extract from Error stack trace with node_modules pattern\n // This method is fragile and fails in pnpm workspaces, but kept for backward compatibility\n const error = new Error();\n const stack = error.stack || '';\n const stackLines = stack.split('\\n');\n\n // Look for line with 'node_modules/@scope/package' pattern\n for (const line of stackLines) {\n const match = line.match(/node_modules\\/(@[^/]+\\/[^/]+)/);\n if (match) {\n return match[1];\n }\n }\n\n // Package name is now injected at build time into the manifest and stored in ObjectRegistry\n // If we reach here, the class is likely not from an external package\n return null;\n } catch {\n return null;\n }\n}\n\ninterface ManifestExportConditions {\n default?: string;\n import?: string;\n require?: string;\n}\n\ninterface ExternalPackageJson {\n exports?: Record<string, string | ManifestExportConditions>;\n}\n\nfunction findWorkspaceRoot(startDir: string): string | null {\n let currentDir = startDir;\n\n while (true) {\n if (existsSync(join(currentDir, 'pnpm-workspace.yaml'))) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n return null;\n }\n\n currentDir = parentDir;\n }\n}\n\nfunction resolveInstalledPackageJsonPath(packageName: string): string | null {\n let currentDir = process.cwd();\n\n while (true) {\n const packageJsonPath = join(\n currentDir,\n 'node_modules',\n packageName,\n 'package.json',\n );\n\n if (existsSync(packageJsonPath)) {\n return packageJsonPath;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n return null;\n }\n\n currentDir = parentDir;\n }\n}\n\nfunction resolveWorkspacePackageJsonPath(packageName: string): string | null {\n const workspaceRoot = findWorkspaceRoot(process.cwd());\n if (!workspaceRoot) {\n return null;\n }\n\n const workspacePackagesDir = join(workspaceRoot, 'packages');\n if (!existsSync(workspacePackagesDir)) {\n return null;\n }\n\n for (const packageDirName of readdirSync(workspacePackagesDir)) {\n const packageJsonPath = join(\n workspacePackagesDir,\n packageDirName,\n 'package.json',\n );\n if (!existsSync(packageJsonPath)) {\n continue;\n }\n\n try {\n const packageJson = parse<{ name?: string }>(\n readFileSync(packageJsonPath, 'utf-8'),\n );\n if (packageJson.name === packageName) {\n return packageJsonPath;\n }\n } catch {\n // Ignore unreadable workspace package metadata and continue scanning.\n }\n }\n\n return null;\n}\n\nfunction resolveWorkspaceSourceManifestPath(packageDir: string): string | null {\n const candidates = [\n join(packageDir, 'src', 'manifest', 'manifest.json'),\n join(packageDir, '.smrt', 'manifest.json'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\ninterface ManifestLoadOptions {\n warn?: boolean;\n}\n\nfunction resolveManifestExportPath(\n packageName: string,\n options: ManifestLoadOptions = {},\n): string | null {\n const shouldWarn = options.warn ?? true;\n const packageJsonPath =\n resolveInstalledPackageJsonPath(packageName) ||\n resolveWorkspacePackageJsonPath(packageName);\n\n if (!packageJsonPath) {\n return null;\n }\n\n const packageDir = dirname(packageJsonPath);\n const packageJson = parse<ExternalPackageJson>(\n readFileSync(packageJsonPath, 'utf-8'),\n );\n const manifestExports = ['./manifest.json', './manifest'];\n\n for (const exportKey of manifestExports) {\n const manifestExport = packageJson.exports?.[exportKey];\n if (!manifestExport) {\n continue;\n }\n\n const manifestRelativePath =\n typeof manifestExport === 'string'\n ? manifestExport\n : manifestExport.import ||\n manifestExport.default ||\n manifestExport.require;\n\n if (!manifestRelativePath) {\n if (shouldWarn) {\n logger.warn(\n `Package ${packageName} has invalid manifest export configuration for ${exportKey}`,\n );\n }\n return null;\n }\n\n if (!manifestRelativePath.endsWith('.json')) {\n if (shouldWarn) {\n logger.warn(\n `Package ${packageName} must export a JSON manifest for ${exportKey}, received ${manifestRelativePath}`,\n );\n }\n return null;\n }\n\n const manifestPath = join(packageDir, manifestRelativePath);\n if (existsSync(manifestPath)) {\n return manifestPath;\n }\n\n const workspaceSourceManifest =\n resolveWorkspaceSourceManifestPath(packageDir);\n if (workspaceSourceManifest) {\n return workspaceSourceManifest;\n }\n\n if (shouldWarn) {\n logger.warn(\n `Package ${packageName} declares manifest export ${manifestRelativePath}, but no manifest file was found.`,\n );\n }\n return null;\n }\n\n return null;\n}\n\nfunction collectDeclaredSmrtDependencies(\n manifests: Array<Manifest | null | undefined>,\n): string[] {\n const dependencies = new Set<string>();\n\n for (const manifest of manifests) {\n for (const pkg of manifest?.smrtDependencies || []) {\n dependencies.add(pkg);\n }\n }\n\n return Array.from(dependencies);\n}\n\n/**\n * Load manifest from external package\n *\n * Uses createRequire from process.cwd() to resolve packages from the calling\n * application's context, not from smrt-core's context. This allows finding\n * packages that are dependencies of the app but not of smrt-core.\n *\n * External packages export manifests via package.json:\n * \"exports\": { \"./manifest\": \"./dist/manifest.json\" }\n *\n * @param packageName - Package name (e.g., '@happyvertical/smrt-places')\n * @returns Manifest object or null if not found\n */\n/**\n * Load external package manifest synchronously\n * This is the synchronous version of loadExternalManifest for use during class registration\n */\nexport function loadExternalManifestSync(\n packageName: string,\n options: ManifestLoadOptions = {},\n): Manifest | null {\n // Check cache first\n if (getManifestCacheMap().has(packageName)) {\n debugLog(`[manifest-loader] Using cached manifest for ${packageName}`);\n return getManifestCacheMap().get(packageName)!;\n }\n\n debugLog(\n `[manifest-loader] Attempting to load external manifest for ${packageName}`,\n );\n\n const manifestPath = resolveManifestExportPath(packageName, options);\n\n if (!manifestPath) {\n debugLog(\n `[manifest-loader] Package ${packageName} does not expose a JSON manifest export`,\n );\n return null;\n }\n\n try {\n const manifest = parse<Manifest>(readFileSync(manifestPath, 'utf-8'));\n\n if (!manifest.objects || typeof manifest.objects !== 'object') {\n if (options.warn ?? true) {\n logger.warn(`Invalid manifest structure for package ${packageName}`);\n }\n return null;\n }\n\n const cachedManifest = manifest.packageName\n ? manifest\n : { ...manifest, packageName };\n\n getManifestCacheMap().set(packageName, cachedManifest);\n debugLog(\n `[manifest-loader] ✅ Loaded external manifest for ${packageName} (${Object.keys(cachedManifest.objects).length} objects)`,\n );\n\n return cachedManifest;\n } catch (error) {\n if (options.warn ?? true) {\n logger.warn(\n `Failed to load manifest for package ${packageName}: ${error instanceof Error ? error.message : error}`,\n );\n }\n return null;\n }\n}\n\nexport async function loadExternalManifest(\n packageName: string,\n options: ManifestLoadOptions = {},\n): Promise<Manifest | null> {\n // Delegate to synchronous version since all operations are sync anyway\n return loadExternalManifestSync(packageName, options);\n}\n\n/**\n * Load a manifest directly from a known file path and cache it by package name.\n *\n * This is used by workspace/dev flows where sibling packages may not be\n * installed into node_modules yet, but their generated manifests are still\n * available on disk.\n */\nexport function loadManifestFromPathSync(\n manifestPath: string,\n): Manifest | null {\n try {\n const manifestJson = readFileSync(manifestPath, 'utf-8');\n const manifest: Manifest = parse(manifestJson);\n\n if (!manifest.objects || typeof manifest.objects !== 'object') {\n logger.warn(`Invalid manifest structure at ${manifestPath}`);\n return null;\n }\n\n const cacheKey = manifest.packageName || manifestPath;\n getManifestCacheMap().set(cacheKey, manifest);\n debugLog(\n `[manifest-loader] ✅ Loaded manifest from path ${manifestPath} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n return manifest;\n } catch (error) {\n logger.warn(\n `Failed to load manifest from path ${manifestPath}: ${error instanceof Error ? error.message : error}`,\n );\n return null;\n }\n}\n\n/**\n * Discover manifest entry synchronously (checks only loaded manifests)\n *\n * Search order:\n * 1. localTestManifest (for domain package test classes)\n * 2. testManifest (for core test classes)\n * 3. staticManifest (for core framework classes)\n * 4. Cached external manifests\n *\n * @param className - Class name (for lookup)\n * @returns ManifestEntry or undefined if not found\n */\nexport function discoverManifestSync(\n className: string,\n): ManifestEntry | undefined {\n debugLog(`[manifest-loader] discoverManifestSync called for: ${className}`);\n\n // Ensure test-env caches are seeded before the composite queries them.\n // Historically, steps 1-2 of discoverManifestSync did this inline. The\n // composite's TestManifestSource and LocalTestManifestSource read directly\n // from cache state — without this seeding the first sync lookup in a\n // clean test process would miss core test classes on their first access\n // (regression noted in #1138 review).\n if (isTestEnvironment()) {\n if (!getLocalTestManifestCache()) {\n loadLocalTestManifestSync();\n }\n if (!getTestManifestCache()) {\n getTestManifest();\n }\n }\n\n // Carry qualified-name / package context into the composite lookup so\n // multi-package same-simple-name scenarios (issue #951) resolve to the\n // right manifest even via the sync path.\n const query = isQualifiedName(className)\n ? (() => {\n const parsed = parseQualifiedName(className);\n return {\n className: parsed.className,\n packageName: parsed.packageName,\n qualifiedName: className,\n };\n })()\n : { className };\n\n // Steps 1-4 (local-test → test → static → embedded cache) now live in\n // CompositeManifestSource at the exact same priority order.\n const compositeHit = getDefaultCompositeSource().lookup(query);\n if (compositeHit) {\n debugLog(\n `[manifest-loader] ✅ Found ${className} via ${compositeHit.source} source`,\n );\n const entry = compositeHit.def;\n if (!entry.packageName && compositeHit.packageName) {\n return { ...entry, packageName: compositeHit.packageName };\n }\n return entry;\n }\n\n // 5. Try loading from explicitly declared external SMRT package dependencies.\n debugLog(\n `[manifest-loader] ${className} not found in cached manifests, trying external packages...`,\n );\n\n const pendingPackages = collectDeclaredSmrtDependencies([\n getLocalTestManifestCache(),\n isTestEnvironment() ? getTestManifest() : null,\n getStaticManifest(),\n ...getManifestCacheMap().values(),\n ]);\n\n if (pendingPackages.length === 0) {\n debugLog(\n '[manifest-loader] No SMRT dependencies discovered. Run manifest generation if external packages are expected.',\n );\n }\n\n const visitedPackages = new Set<string>();\n\n while (pendingPackages.length > 0) {\n const pkg = pendingPackages.shift();\n if (!pkg || visitedPackages.has(pkg)) {\n continue;\n }\n\n visitedPackages.add(pkg);\n const manifest = loadExternalManifestSync(pkg);\n if (!manifest) {\n continue;\n }\n\n for (const dependency of manifest.smrtDependencies || []) {\n if (!visitedPackages.has(dependency)) {\n pendingPackages.push(dependency);\n }\n }\n\n // Use lookupInManifest for qualified name support (Issue #713)\n const entry = lookupInManifest(manifest, className);\n if (entry) {\n debugLog(\n `[manifest-loader] ✅ Found ${className} in external package ${pkg}`,\n );\n // Enrich entry with packageName from manifest if not already present\n if (!entry.packageName && manifest.packageName) {\n return { ...entry, packageName: manifest.packageName };\n }\n return entry;\n }\n }\n\n debugLog(`[manifest-loader] ❌ ${className} not found in any manifest`);\n return undefined;\n}\n\n// Note: manifestCollisions is now accessed via globalThis helper function\n// getManifestCollisionsMap()\n\n/**\n * Look up a manifest entry in a manifest's objects map.\n * Supports both qualified names and simple class names.\n *\n * Lookup order:\n * 1. Direct qualified name lookup (e.g., \"@happyvertical/smrt-core:Product\")\n * 2. Constructed qualified name (packageName + className)\n * 3. Search by className property (case-insensitive)\n *\n * @param manifest - The manifest to search in\n * @param nameOrQualified - Either a qualified name or simple class name\n * @returns ManifestEntry or undefined if not found\n */\nexport function lookupInManifest(\n manifest: SmartObjectManifest,\n nameOrQualified: string,\n): ManifestEntry | undefined {\n // 1. First try direct lookup (handles both qualified names and exact matches)\n if (manifest.objects[nameOrQualified]) {\n return manifest.objects[nameOrQualified];\n }\n\n // 2. Get the className index for O(1) lookups (instead of O(n) iteration)\n // This is the key optimization for issue #729\n const classNameIndex = getClassNameIndex(manifest);\n\n // 3. If input is a qualified name, extract className and use index\n if (isQualifiedName(nameOrQualified)) {\n const { className } = parseQualifiedName(nameOrQualified);\n return classNameIndex.get(className.toLowerCase());\n }\n\n // 4. For simple class names, try constructing qualified name if manifest has packageName\n if (manifest.packageName) {\n const qualifiedKey = createQualifiedName(\n manifest.packageName,\n nameOrQualified,\n );\n if (manifest.objects[qualifiedKey]) {\n return manifest.objects[qualifiedKey];\n }\n }\n\n // 5. Use index for O(1) className lookup (instead of O(n) iteration)\n return classNameIndex.get(nameOrQualified.toLowerCase());\n}\n\n/**\n * Find a manifest entry by qualified name across all loaded manifests.\n *\n * @param qualifiedName - The fully qualified class name (e.g., \"@happyvertical/smrt-core:Product\")\n * @returns ManifestEntry or undefined if not found\n */\nexport function findManifestEntryByQualifiedName(\n qualifiedName: string,\n): ManifestEntry | undefined {\n if (!isQualifiedName(qualifiedName)) {\n return undefined;\n }\n\n const { packageName } = parseQualifiedName(qualifiedName);\n\n // Check if we have the package's manifest cached\n const manifest = getManifestCacheMap().get(packageName);\n if (manifest) {\n // Try qualified name first, then fallback to simple names\n return lookupInManifest(manifest, qualifiedName);\n }\n\n // Check static manifest\n const staticManifestData = getStaticManifest();\n if (staticManifestData.packageName === packageName) {\n return lookupInManifest(staticManifestData, qualifiedName);\n }\n\n // Check test manifest (if in test environment)\n if (isTestEnvironment()) {\n const testManifest = getTestManifest();\n if (testManifest?.packageName === packageName) {\n return lookupInManifest(testManifest, qualifiedName);\n }\n\n // Check local test manifest\n const localTest = getLocalTestManifestCache();\n if (localTest?.packageName === packageName) {\n return lookupInManifest(localTest, qualifiedName);\n }\n }\n\n return undefined;\n}\n\n/**\n * Discover manifest entry asynchronously (includes external package loading)\n *\n * Search order:\n * 1. External package manifest (for constructor's package) - PRIORITIZED\n * 2. testManifest (for test classes)\n * 3. staticManifest (for core framework classes)\n * 4. Cached external manifests\n *\n * This function now detects and reports class name collisions across packages.\n *\n * @param ctor - Class constructor\n * @param className - Class name (for lookup)\n * @returns ManifestEntry or undefined if not found\n * @throws {Error} If class name collision detected across different packages\n */\nexport async function discoverManifestEntry(\n ctor: SmrtObjectConstructor,\n className: string,\n): Promise<ManifestEntry | undefined> {\n // ✅ FAST PATH: O(1) constructor-based lookup for already-registered classes\n // Skip manifest scanning if we already know this constructor's qualified name via WeakMap\n // This provides instant resolution and prevents collisions (each constructor is unique in memory)\n if (!(ctor as { _isManifestStub?: boolean })._isManifestStub) {\n const registered = ObjectRegistry.getClassByConstructor(ctor);\n if (\n registered?.qualifiedName &&\n isQualifiedName(registered.qualifiedName)\n ) {\n // Parse package name from qualified name (format: \"@package/name:ClassName\")\n const { packageName } = parseQualifiedName(registered.qualifiedName);\n\n const cachedManifest = getManifestCacheMap().get(packageName);\n if (cachedManifest) {\n const cachedEntry = lookupInManifest(\n cachedManifest,\n registered.qualifiedName,\n );\n if (cachedEntry) {\n return !cachedEntry.packageName && cachedManifest.packageName\n ? { ...cachedEntry, packageName: cachedManifest.packageName }\n : cachedEntry;\n }\n }\n\n // Load the manifest for this specific package before trusting any\n // existing runtime field metadata. Imported external classes can be\n // registered with only a partial field set until their manifest is\n // hydrated, which is exactly what happens with STI parents like Event.\n const manifest = await loadExternalManifest(packageName, {\n warn: registered.fields.size === 0,\n });\n if (manifest) {\n // Look up the entry using the qualified name (exact match)\n const entry = lookupInManifest(manifest, registered.qualifiedName);\n if (entry) {\n // Enrich entry with package name if missing\n return !entry.packageName && manifest.packageName\n ? { ...entry, packageName: manifest.packageName }\n : entry;\n }\n }\n\n // Source-registered classes with explicit field metadata do not need a\n // second manifest probe from fallback discovery when the package did not\n // resolve to a manifest. This keeps workspace/dev runtimes from spamming\n // missing-dist-manifest warnings for packages that are already fully\n // usable from source.\n if (registered.fields.size > 0) {\n return undefined;\n }\n }\n }\n\n // FALLBACK: Original manifest scanning logic for:\n // - First-time registration (WeakMap not populated yet)\n // - Manifest stubs (not in WeakMap)\n // - Undecorated classes (never registered)\n const name = className.toLowerCase();\n const constructorPackage = getPackageName(ctor);\n\n // Track all manifest sources that define this class\n const foundEntries: Array<{\n entry: ManifestEntry;\n packageName: string;\n filePath?: string;\n manifestSource: string;\n }> = [];\n\n // Build qualified name for lookup if we have package context\n const qualifiedName = constructorPackage\n ? createQualifiedName(constructorPackage, className)\n : undefined;\n\n // 2. Check localTestManifest first (domain package test classes) - ONLY in test environment\n // Do this BEFORE loading external manifest to avoid duplicate loading\n let localEntry: SmartObjectDefinition | undefined;\n if (isTestEnvironment()) {\n if (getLocalTestManifestCache() === undefined) {\n loadLocalTestManifestSync();\n }\n const localManifest = getLocalTestManifestCache();\n if (localManifest) {\n // Use lookupInManifest for consistent qualified name handling\n localEntry = lookupInManifest(localManifest, qualifiedName || className);\n if (localEntry) {\n foundEntries.push({\n entry: localEntry,\n packageName: localManifest.packageName || 'local-test',\n filePath: localEntry.filePath,\n manifestSource: 'local test manifest',\n });\n }\n }\n }\n\n // 1. PRIORITY: Try loading from the constructor's package first\n // BUT skip if it's the same package as the local test manifest to avoid collisions\n if (constructorPackage) {\n const skipExternal =\n getLocalTestManifestCache()?.packageName &&\n constructorPackage === getLocalTestManifestCache()?.packageName;\n\n if (!skipExternal) {\n const manifest = await loadExternalManifest(constructorPackage);\n if (manifest) {\n // Use lookupInManifest for consistent qualified name handling\n const entry = lookupInManifest(manifest, qualifiedName || className);\n if (entry) {\n const enrichedEntry =\n !entry.packageName && manifest.packageName\n ? { ...entry, packageName: manifest.packageName }\n : entry;\n\n foundEntries.push({\n entry: enrichedEntry,\n packageName: manifest.packageName || constructorPackage,\n filePath: entry.filePath,\n manifestSource: `${manifest.packageName || constructorPackage}/manifest.json`,\n });\n }\n }\n }\n }\n\n // 3. Check testManifest (core test classes) - ONLY in test environment\n // Skip if we already loaded a local test manifest (avoids duplicate entries from same package)\n if (isTestEnvironment() && (!getLocalTestManifestCache() || !localEntry)) {\n const manifest = getTestManifest();\n if (manifest) {\n // Use lookupInManifest for consistent qualified name handling\n const testEntry = lookupInManifest(manifest, qualifiedName || className);\n if (testEntry) {\n foundEntries.push({\n entry: testEntry,\n packageName: manifest.packageName || '@happyvertical/smrt-core',\n filePath: testEntry.filePath,\n manifestSource: '@happyvertical/smrt-core test manifest',\n });\n }\n }\n }\n\n // 4. Check staticManifest (core framework classes)\n const staticManifestData = getStaticManifest();\n // Use lookupInManifest for consistent qualified name handling\n const staticEntry = lookupInManifest(\n staticManifestData,\n qualifiedName || className,\n );\n if (staticEntry) {\n foundEntries.push({\n entry: staticEntry,\n packageName: staticManifestData.packageName || '@happyvertical/smrt-core',\n filePath: staticEntry.filePath,\n manifestSource: '@happyvertical/smrt-core static manifest',\n });\n }\n\n // 5. Check other cached external manifests\n for (const [cachedPkgName, manifest] of getManifestCacheMap().entries()) {\n // Skip if this is the constructor's package (already checked above)\n if (cachedPkgName === constructorPackage) {\n continue;\n }\n\n // Use lookupInManifest for consistent qualified name handling\n const entry = lookupInManifest(manifest, qualifiedName || className);\n if (entry) {\n foundEntries.push({\n entry:\n !entry.packageName && manifest.packageName\n ? { ...entry, packageName: manifest.packageName }\n : entry,\n packageName: manifest.packageName || cachedPkgName,\n filePath: entry.filePath,\n manifestSource: `${manifest.packageName || cachedPkgName}/manifest.json`,\n });\n }\n }\n\n // Deduplicate entries that reference the same source file.\n // Consumer manifests (e.g. smrt-users, dashboard) re-export classes from\n // upstream packages (e.g. smrt-profiles). These appear in multiple manifests\n // but point to the same filePath — they are NOT real collisions.\n if (foundEntries.length > 1) {\n const uniqueByFile = new Map<string, (typeof foundEntries)[0]>();\n for (const entry of foundEntries) {\n // Normalize file paths so the same source file with different absolute\n // prefixes (local dev vs CI build) is recognized as identical.\n // Extract the relative path from the last \"packages/\" segment onward.\n let key = entry.filePath || `${entry.packageName}:${className}`;\n if (entry.filePath) {\n const pkgIdx = entry.filePath.lastIndexOf('packages/');\n if (pkgIdx !== -1) {\n key = entry.filePath.slice(pkgIdx);\n }\n }\n if (!uniqueByFile.has(key)) {\n uniqueByFile.set(key, entry);\n }\n }\n\n if (uniqueByFile.size === 1) {\n // All entries point to the same source file — not a real collision.\n // Use the first (highest priority) entry.\n foundEntries.splice(1);\n } else if (uniqueByFile.size > 1) {\n // True collision: different source files define the same class name\n const collisionInfo = foundEntries.map(\n (f) =>\n ` - ${f.packageName} (${f.filePath || 'unknown file'}) from ${f.manifestSource}`,\n );\n\n // Store collision info for reporting\n getManifestCollisionsMap().set(\n className,\n foundEntries.map((f) => ({\n packageName: f.packageName,\n filePath: f.filePath,\n manifestSource: f.manifestSource,\n })),\n );\n\n // Throw error on collision\n throw new Error(\n `SMRT Class Name Collision Detected: \"${className}\"\\n\\n` +\n `This class is defined in multiple packages:\\n${collisionInfo.join('\\n')}\\n\\n` +\n `The collision will cause the wrong field definitions to be used,\\n` +\n `leading to properties not being initialized correctly.\\n\\n` +\n `To fix:\\n` +\n ` 1. Use unique class names across packages (e.g., ${className}_${constructorPackage?.split('/').pop() || 'Unique'})\\n` +\n ` 2. Or use @smrt({ name: 'unique_name' }) to override the registration name\\n` +\n ` 3. Remove test classes with conflicting names from production manifests\\n\\n` +\n `If this is a test class collision, ensure test manifests are not included in production builds.`,\n );\n }\n }\n\n // Return the found entry (priority given to constructor's package)\n if (foundEntries.length === 1) {\n return foundEntries[0].entry;\n }\n\n return undefined;\n}\n\n/**\n * Get all detected manifest collisions\n *\n * @returns Map of class names to array of collision info\n */\nexport function getManifestCollisions(): Map<\n string,\n Array<{ packageName: string; filePath?: string; manifestSource: string }>\n> {\n return new Map(getManifestCollisionsMap());\n}\n\n/**\n * Clear manifest cache\n *\n * Useful for testing or when packages are updated at runtime.\n */\nexport function clearManifestCache(): void {\n // Reset all cached manifest state so tests/dev tooling can force a full\n // rediscovery pass on the next lookup.\n setStaticManifestCache(undefined);\n setStaticManifestLoadAttempted(false);\n setTestManifestCache(undefined);\n setTestManifestLoadAttempted(false);\n setLocalTestManifestCache(undefined);\n getManifestCacheMap().clear();\n getManifestCollisionsMap().clear();\n getSTISiblingCache().clear();\n}\n\n/**\n * Get all loaded manifests\n *\n * Returns a copy of the manifest cache for inspection.\n *\n * @returns Array of [packageName, manifest] entries\n */\nexport function getLoadedManifests(): Array<[string, Manifest]> {\n return Array.from(getManifestCacheMap().entries());\n}\n\n/**\n * Discover all STI sibling classes that share the same collection (table)\n *\n * This is critical for STI schema merging: when one subtype is accessed,\n * we need to discover ALL subtypes sharing the same table so that the\n * database adapter receives a complete schema with all columns.\n *\n * Scans all available manifests:\n * 1. Local test manifest (for test classes)\n * 2. Test manifest (for core test classes)\n * 3. Static manifest (for core framework classes)\n * 4. Cached external manifests\n * 5. SMRT dependencies from local test manifest\n *\n * @param collection - The collection/table name to find siblings for\n * @returns Array of manifest entries that share the same collection\n *\n * Known limitation (#1579, won't-fix): the per-collection result is cached on\n * `globalThis.__smrtSTISiblingCache` after the first call and is not invalidated\n * when a manifest is registered *afterwards* and isn't reachable via\n * `smrtDependencies` (the Release-A self-register path). A sibling registered\n * after first discovery for a given collection can therefore be missed until the\n * cache is cleared. Accepted as low-risk: STI manifests are registered at\n * startup before query traffic, and the few self-register flows that could hit\n * it can reset the cache. Fixing it properly means a registration→cache\n * invalidation hook, which is disproportionate to the exposure.\n */\nexport function discoverSTISiblingsSync(\n collection: string,\n): Array<{ className: string; entry: ManifestEntry; packageName?: string }> {\n // Check cache first to avoid repeated scans (fixes #644)\n const cache = getSTISiblingCache();\n const cached = cache.get(collection);\n if (cached !== undefined) {\n return cached;\n }\n\n const siblings: Array<{\n className: string;\n entry: ManifestEntry;\n packageName?: string;\n }> = [];\n\n // Track already-found class names to avoid duplicates (case-insensitive)\n // Use lowercase keys to prevent both 'praeco' and 'Praeco' from being added\n const foundClasses = new Set<string>();\n\n debugLog(\n `[manifest-loader] discoverSTISiblingsSync called for collection: ${collection}`,\n );\n\n // Helper to add entries from a manifest\n const addFromManifest = (\n manifest: Manifest | null | undefined,\n source: string,\n ) => {\n if (!manifest?.objects) return;\n\n for (const [key, entry] of Object.entries(manifest.objects) as [\n string,\n ManifestEntry,\n ][]) {\n // Check if this entry uses the same collection (table)\n if (entry.collection === collection) {\n const className = entry.className || key;\n // Use case-insensitive check to prevent registering both 'praeco' and 'Praeco'\n const lowerClassName = className.toLowerCase();\n if (!foundClasses.has(lowerClassName)) {\n foundClasses.add(lowerClassName);\n siblings.push({\n className,\n entry,\n packageName: entry.packageName || manifest.packageName,\n });\n debugLog(\n `[manifest-loader] Found STI sibling: ${className} (collection: ${collection}) from ${source}`,\n );\n }\n }\n }\n };\n\n // 1. Check local test manifest (domain package test classes)\n if (isTestEnvironment()) {\n if (!getLocalTestManifestCache()) {\n loadLocalTestManifestSync();\n }\n addFromManifest(getLocalTestManifestCache(), 'localTestManifest');\n }\n\n // 2. Check test manifest (core test classes)\n const testManifestData = isTestEnvironment() ? getTestManifest() : null;\n if (testManifestData) {\n addFromManifest(testManifestData, 'testManifest');\n }\n\n // 3. Check static manifest (core framework classes)\n const staticManifestData = getStaticManifest();\n addFromManifest(staticManifestData, 'staticManifest');\n\n // 4. Check cached external manifests\n for (const [pkgName, manifest] of getManifestCacheMap().entries()) {\n addFromManifest(manifest, `manifestCache:${pkgName}`);\n }\n\n // 5. Try loading from SMRT dependencies from ALL manifests (not just localTestManifest)\n // This ensures production environments also discover STI siblings\n const pendingDependencies = collectDeclaredSmrtDependencies([\n getLocalTestManifestCache(),\n isTestEnvironment() ? testManifestData : null,\n staticManifestData,\n ...getManifestCacheMap().values(),\n ]);\n const visitedDependencies = new Set<string>();\n\n debugLog(\n `[manifest-loader] Scanning ${pendingDependencies.length} SMRT dependencies for STI siblings: ${pendingDependencies.join(', ')}`,\n );\n\n while (pendingDependencies.length > 0) {\n const pkg = pendingDependencies.shift();\n if (!pkg || visitedDependencies.has(pkg)) {\n continue;\n }\n\n visitedDependencies.add(pkg);\n\n const manifest = loadExternalManifestSync(pkg);\n if (manifest) {\n addFromManifest(manifest, `smrtDependency:${pkg}`);\n\n for (const dependency of manifest.smrtDependencies || []) {\n if (!visitedDependencies.has(dependency)) {\n pendingDependencies.push(dependency);\n }\n }\n }\n }\n\n debugLog(\n `[manifest-loader] discoverSTISiblingsSync found ${siblings.length} siblings for collection: ${collection}`,\n );\n\n // Cache the results for future calls (fixes #644)\n cache.set(collection, siblings);\n\n return siblings;\n}\n"],"names":["getStaticManifestCacheFromStore","getTestManifestCacheFromStore","getLocalTestManifestCacheFromStore","getManifestCacheFromStore","require","isTestEnvFromStore","error","stack","stackLines"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const staticManifest = {
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"timestamp":
|
|
3
|
+
"timestamp": 1782792357137,
|
|
4
4
|
"packageName": "@happyvertical/smrt-core",
|
|
5
|
-
"packageVersion": "0.37.
|
|
5
|
+
"packageVersion": "0.37.1",
|
|
6
6
|
"objects": {
|
|
7
7
|
"@happyvertical/smrt-core:SmrtClass": {
|
|
8
8
|
"name": "smrtclass",
|