@happyvertical/smrt-core 0.36.8 → 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.
Files changed (105) hide show
  1. package/dist/child-accessors.d.ts +1 -1
  2. package/dist/child-accessors.d.ts.map +1 -1
  3. package/dist/child-accessors.js +1 -1
  4. package/dist/child-accessors.js.map +1 -1
  5. package/dist/class.d.ts.map +1 -1
  6. package/dist/class.js +3 -1
  7. package/dist/class.js.map +1 -1
  8. package/dist/collection-cache.d.ts.map +1 -1
  9. package/dist/collection-cache.js +5 -3
  10. package/dist/collection-cache.js.map +1 -1
  11. package/dist/collection.d.ts +39 -16
  12. package/dist/collection.d.ts.map +1 -1
  13. package/dist/collection.js +40 -19
  14. package/dist/collection.js.map +1 -1
  15. package/dist/consumer-plugin/index.js.map +1 -1
  16. package/dist/decorators/compatibility.d.ts +1 -1
  17. package/dist/decorators/compatibility.d.ts.map +1 -1
  18. package/dist/decorators/compatibility.js.map +1 -1
  19. package/dist/decorators/index.d.ts +4 -4
  20. package/dist/decorators/index.d.ts.map +1 -1
  21. package/dist/decorators/index.js.map +1 -1
  22. package/dist/hierarchical.d.ts.map +1 -1
  23. package/dist/hierarchical.js.map +1 -1
  24. package/dist/junction.d.ts.map +1 -1
  25. package/dist/junction.js.map +1 -1
  26. package/dist/manifest/discover-smrt-packages.d.ts +10 -0
  27. package/dist/manifest/discover-smrt-packages.d.ts.map +1 -1
  28. package/dist/manifest/discover-smrt-packages.js.map +1 -1
  29. package/dist/manifest/generator.d.ts.map +1 -1
  30. package/dist/manifest/generator.js +34 -37
  31. package/dist/manifest/generator.js.map +1 -1
  32. package/dist/manifest/index.js +2 -2
  33. package/dist/manifest/index.js.map +1 -1
  34. package/dist/manifest/manifest-loader.d.ts +10 -0
  35. package/dist/manifest/manifest-loader.d.ts.map +1 -1
  36. package/dist/manifest/manifest-loader.js.map +1 -1
  37. package/dist/manifest/static-manifest.d.ts.map +1 -1
  38. package/dist/manifest/static-manifest.js +39 -20
  39. package/dist/manifest/static-manifest.js.map +1 -1
  40. package/dist/manifest/store.js +2 -2
  41. package/dist/manifest/store.js.map +1 -1
  42. package/dist/manifest/test-manifest-stub.d.ts.map +1 -1
  43. package/dist/manifest/test-manifest-stub.js +2301 -629
  44. package/dist/manifest/test-manifest-stub.js.map +1 -1
  45. package/dist/manifest.json +39 -20
  46. package/dist/migrations/differ.d.ts +104 -13
  47. package/dist/migrations/differ.d.ts.map +1 -1
  48. package/dist/migrations/differ.js +199 -26
  49. package/dist/migrations/differ.js.map +1 -1
  50. 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
  51. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/ast.js +1 -7
  52. package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/ast.js.map +1 -0
  53. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
  54. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js.map +1 -1
  55. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/index.js +17 -14
  56. package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/index.js.map +1 -0
  57. package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/unescape.js +10 -0
  58. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
  59. package/dist/object.d.ts +64 -17
  60. package/dist/object.d.ts.map +1 -1
  61. package/dist/object.js +76 -30
  62. package/dist/object.js.map +1 -1
  63. package/dist/registry/class-registration.d.ts +3 -3
  64. package/dist/registry/class-registration.d.ts.map +1 -1
  65. package/dist/registry/class-registration.js +39 -42
  66. package/dist/registry/class-registration.js.map +1 -1
  67. package/dist/registry/inheritance-resolver.d.ts +17 -3
  68. package/dist/registry/inheritance-resolver.d.ts.map +1 -1
  69. package/dist/registry/inheritance-resolver.js +1 -1
  70. package/dist/registry/inheritance-resolver.js.map +1 -1
  71. package/dist/registry/manifest-field-merge.d.ts +17 -3
  72. package/dist/registry/manifest-field-merge.d.ts.map +1 -1
  73. package/dist/registry/manifest-field-merge.js +8 -6
  74. package/dist/registry/manifest-field-merge.js.map +1 -1
  75. package/dist/registry/schema-builder.d.ts +1 -1
  76. package/dist/registry/schema-builder.d.ts.map +1 -1
  77. package/dist/registry/schema-builder.js.map +1 -1
  78. package/dist/registry/shared-state.d.ts +3 -3
  79. package/dist/registry/shared-state.d.ts.map +1 -1
  80. package/dist/registry/shared-state.js.map +1 -1
  81. package/dist/registry/types.d.ts +78 -19
  82. package/dist/registry/types.d.ts.map +1 -1
  83. package/dist/registry/validator.d.ts +2 -1
  84. package/dist/registry/validator.d.ts.map +1 -1
  85. package/dist/registry/validator.js +38 -39
  86. package/dist/registry/validator.js.map +1 -1
  87. package/dist/registry.d.ts +84 -57
  88. package/dist/registry.d.ts.map +1 -1
  89. package/dist/registry.js +31 -25
  90. package/dist/registry.js.map +1 -1
  91. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  92. package/dist/scanner/manifest-generator.js +22 -20
  93. package/dist/scanner/manifest-generator.js.map +1 -1
  94. package/dist/smrt-knowledge.json +8 -7
  95. package/dist/system-fields.d.ts +1 -1
  96. package/dist/system-fields.d.ts.map +1 -1
  97. package/dist/system-fields.js.map +1 -1
  98. package/dist/vite-plugin/index.js +1 -1
  99. package/package.json +7 -7
  100. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js.map +0 -1
  101. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js.map +0 -1
  102. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js +0 -10
  103. /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js +0 -0
  104. /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js +0 -0
  105. /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":"index.js","sources":["../../src/consumer-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for consuming SMRT packages\n * Solves virtual module resolution in downstream projects\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generateDeclarations } from '../prebuild/index.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\n\n/**\n * Loosely-typed view of an object definition as carried by an external\n * package's static manifest. The static manifests are read from JSON at the\n * package boundary, so only the fields this plugin consumes are typed; the\n * index signature preserves any additional fields (e.g. for spreads). This is\n * a structural superset of a manifest `SmartObjectDefinition` plus the\n * consumer-only `hasCollection` marker.\n */\ninterface ConsumerObjectDefinition {\n className?: string;\n packageName?: string;\n packageVersion?: string;\n qualifiedName?: string;\n importPath?: string;\n exportName?: string;\n collectionExportName?: string;\n hasCollection?: boolean;\n collection?: string;\n extends?: string;\n extendsQualified?: string;\n extendsTypeArg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Aggregated manifest assembled by the consumer plugin from one or more\n * external package manifests. Loosely typed because the inputs originate from\n * JSON read at the package boundary.\n */\ninterface ConsumerManifest {\n version: string;\n timestamp: number;\n packageName?: string;\n packageVersion?: string;\n objects: Record<string, ConsumerObjectDefinition>;\n}\n\n/**\n * Minimal structural shape of a parsed `package.json` consumed here (name,\n * version, and the export map used to derive import paths). The index\n * signature keeps the remaining fields accessible.\n */\ninterface ConsumerPackageJson {\n name?: string;\n version?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface SmrtConsumerOptions {\n /** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */\n packages?: string[];\n /** Generate TypeScript declarations */\n generateTypes?: boolean;\n /** Output directory for generated types */\n typesDir?: string;\n /** Project root path */\n projectRoot?: string;\n /** SvelteKit integration mode */\n svelteKit?: boolean;\n /** Use static types only (for federation builds) */\n staticTypes?: boolean;\n /** Disable file scanning */\n disableScanning?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@smrt/routes': 'smrt:routes',\n '@smrt/client': 'smrt:client',\n '@smrt/mcp': 'smrt:mcp',\n '@smrt/types': 'smrt:types',\n '@smrt/manifest': 'smrt:manifest',\n};\n\n/**\n * Consumer plugin for projects that use SMRT packages\n */\nexport function smrtConsumer(options: SmrtConsumerOptions = {}): Plugin {\n const {\n packages = [],\n generateTypes = true,\n typesDir = 'src/types/smrt-generated',\n projectRoot = process.cwd(),\n disableScanning = false,\n } = options;\n\n let smrtPackages: string[] = [];\n let typeManifest: ConsumerManifest | null = null;\n let typesGenerated = false;\n\n return {\n name: 'smrt-consumer',\n\n async buildStart() {\n console.log('[smrt:consumer] Initializing SMRT consumer plugin');\n\n // Discover SMRT packages if not explicitly specified\n if (packages.length === 0 && !disableScanning) {\n smrtPackages = await discoverSmrtPackages(projectRoot);\n } else {\n smrtPackages = packages;\n }\n\n if (smrtPackages.length > 0) {\n console.log(\n `[smrt:consumer] Found SMRT packages: ${smrtPackages.join(', ')}`,\n );\n\n // Aggregate type manifests from discovered packages\n typeManifest = await aggregateTypeManifests(smrtPackages, projectRoot);\n\n // Save aggregated manifest for CLI discovery\n await saveAggregatedManifest(typeManifest, projectRoot);\n\n // Generate registration file for CLI class loading\n await generateRegistrationFile(typeManifest, projectRoot);\n\n // Generate types if requested\n if (generateTypes && !typesGenerated) {\n await generateProjectTypes(typeManifest, typesDir, projectRoot);\n typesGenerated = true;\n }\n } else {\n console.log('[smrt:consumer] No SMRT packages found');\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n },\n\n resolveId(id, _importer) {\n // Resolve virtual modules to generated type declarations\n if (id in VIRTUAL_MODULES) {\n const typeFileName = getTypeFileName(id);\n const typePath = path.join(projectRoot, typesDir, typeFileName);\n\n // If types file exists, resolve to it\n if (fs.existsSync(typePath)) {\n return typePath;\n }\n\n // Otherwise use virtual module ID for runtime resolution\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n return null;\n },\n\n async load(id) {\n // Handle virtual modules if types aren't available\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!typeManifest) {\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n return generateFallbackRoutesModule();\n\n case 'smrt:client':\n return generateFallbackClientModule(typeManifest);\n\n case 'smrt:mcp':\n return generateFallbackMcpModule();\n\n case 'smrt:types':\n return generateFallbackTypesModule(typeManifest);\n\n case 'smrt:manifest':\n return generateFallbackManifestModule(typeManifest);\n\n default:\n return null;\n }\n },\n };\n}\n\n/**\n * Discover SMRT packages in node_modules\n */\nasync function discoverSmrtPackages(projectRoot: string): Promise<string[]> {\n const packages: string[] = [];\n const nodeModulesPath = path.join(projectRoot, 'node_modules');\n\n if (!fs.existsSync(nodeModulesPath)) {\n return packages;\n }\n\n try {\n // Check package.json for workspace dependencies\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n // Look for packages that likely contain SMRT objects\n for (const [name, version] of Object.entries(allDeps)) {\n if (\n typeof version === 'string' &&\n (name.includes('smrt') ||\n name.includes('@have/') ||\n (await hasSmrtManifest(nodeModulesPath, name)))\n ) {\n packages.push(name);\n }\n }\n }\n } catch (error) {\n console.warn('[smrt:consumer] Error discovering packages:', error);\n }\n\n return packages;\n}\n\n/**\n * Check if a package has SMRT manifest\n */\nasync function hasSmrtManifest(\n nodeModulesPath: string,\n packageName: string,\n): Promise<boolean> {\n const packagePath = path.join(nodeModulesPath, packageName);\n const manifestPath = path.join(\n packagePath,\n 'dist',\n 'manifest',\n 'static-manifest.js',\n );\n return fs.existsSync(manifestPath);\n}\n\n/**\n * Aggregate type manifests from multiple packages\n */\nasync function aggregateTypeManifests(\n packages: string[],\n projectRoot: string,\n): Promise<ConsumerManifest> {\n const aggregatedManifest: ConsumerManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n };\n\n for (const packageName of packages) {\n try {\n const packageDir = path.join(projectRoot, 'node_modules', packageName);\n\n // Load package.json for version and export information\n const packageJsonPath = path.join(packageDir, 'package.json');\n let packageJson: ConsumerPackageJson;\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(packageJsonContent) as ConsumerPackageJson;\n } catch {\n console.warn(\n `[smrt:consumer] Could not read package.json for ${packageName}`,\n );\n continue;\n }\n\n // Try multiple manifest locations\n const manifestCandidates = [\n path.join(packageDir, 'dist', 'manifest', 'static-manifest.js'),\n path.join(packageDir, 'dist', 'manifest.json'),\n path.join(packageDir, 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (fs.existsSync(manifestPath)) {\n // Import or read the manifest\n let manifest: Partial<ConsumerManifest> | undefined;\n if (manifestPath.endsWith('.js')) {\n const manifestModule = await import(manifestPath);\n manifest = manifestModule.staticManifest || manifestModule.default;\n } else {\n const manifestContent = fs.readFileSync(manifestPath, 'utf-8');\n manifest = JSON.parse(manifestContent) as Partial<ConsumerManifest>;\n }\n\n if (manifest?.objects) {\n console.log(\n `[smrt:consumer] Loaded manifest from ${packageName} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n // ENHANCED: Preserve package metadata for each object\n for (const [objectName, objectDef] of Object.entries(\n manifest.objects,\n )) {\n const def = objectDef;\n\n aggregatedManifest.objects[objectName] = {\n ...def,\n // Ensure package metadata is preserved/set\n packageName:\n def.packageName || manifest.packageName || packageName,\n packageVersion:\n def.packageVersion ||\n manifest.packageVersion ||\n packageJson.version,\n // Add fallback import paths if missing\n importPath: def.importPath || determineImportPath(packageJson),\n exportName: def.exportName || def.className || objectName,\n collectionExportName:\n def.collectionExportName ||\n `${def.className || objectName}Collection`,\n };\n }\n\n break; // Use first found manifest for this package\n }\n }\n }\n } catch (error) {\n console.warn(\n `[smrt:consumer] Error loading manifest from ${packageName}:`,\n error,\n );\n }\n }\n\n return aggregatedManifest;\n}\n\n/**\n * Determine import path from package.json\n */\nfunction determineImportPath(packageJson: ConsumerPackageJson): string {\n const packageName = packageJson.name;\n\n if (!packageName) {\n throw new Error('Package name not found in package.json');\n }\n\n // Strategy 1: Check for specific exports\n if (packageJson.exports) {\n // Check for objects export\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n\n // Check for main export\n const mainExport = packageJson.exports['.'];\n if (mainExport) {\n // Handle conditional exports\n if (typeof mainExport === 'object' && mainExport !== null) {\n const conditional = mainExport as Record<string, unknown>;\n if (conditional.import) {\n return packageName;\n }\n if (conditional.default) {\n return packageName;\n }\n }\n return packageName;\n }\n }\n\n // Strategy 2: Check main field\n if (packageJson.main) {\n return packageName;\n }\n\n // Strategy 3: Fallback to package name\n return packageName;\n}\n\n/**\n * Save aggregated manifest to .smrt/manifest.json for CLI discovery\n */\nasync function saveAggregatedManifest(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const manifestPath = path.join(smrtDir, 'manifest.json');\n\n try {\n // Create .smrt directory if it doesn't exist\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write manifest\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n console.log(\n `[smrt:consumer] Saved aggregated manifest to .smrt/manifest.json (${Object.keys(manifest.objects).length} objects)`,\n );\n } catch (error) {\n console.warn('[smrt:consumer] Failed to save aggregated manifest:', error);\n }\n}\n\n/**\n * Generate registration file for CLI class loading\n *\n * Creates .smrt/register.js with static imports and registrations\n * for all external SMRT objects discovered during build.\n */\nasync function generateRegistrationFile(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const registerPath = path.join(smrtDir, 'register.js');\n\n // Build import statements and registrations\n const imports: string[] = [];\n const registrations: string[] = [];\n let importedEntryCount = 0;\n let registeredObjectCount = 0;\n\n const manifestObjects = manifest.objects;\n const manifestObjectLookup = new Map<string, ConsumerObjectDefinition>();\n for (const [key, def] of Object.entries(manifestObjects)) {\n const candidate = def;\n const lookupKeys = [\n key,\n key.includes(':') ? key.split(':').pop() : undefined,\n candidate.qualifiedName,\n candidate.className,\n candidate.exportName,\n ];\n\n for (const lookupKey of lookupKeys) {\n if (lookupKey && !manifestObjectLookup.has(lookupKey)) {\n manifestObjectLookup.set(lookupKey, candidate);\n }\n }\n }\n\n const collectionClassMemo = new WeakMap<object, boolean>();\n\n const isCollectionClass = (\n def: ConsumerObjectDefinition | undefined,\n seen = new Set<string>(),\n ): boolean => {\n if (!def || typeof def !== 'object') {\n return false;\n }\n\n const cached = collectionClassMemo.get(def);\n if (cached !== undefined) {\n return cached;\n }\n\n if (\n def?.extends === 'SmrtCollection' ||\n def?.extendsTypeArg !== undefined\n ) {\n collectionClassMemo.set(def, true);\n return true;\n }\n\n const parentName = def?.extendsQualified || def?.extends;\n if (!parentName || seen.has(parentName)) {\n collectionClassMemo.set(def, false);\n return false;\n }\n seen.add(parentName);\n\n const parentDef = manifestObjectLookup.get(parentName);\n const isCollection = parentDef ? isCollectionClass(parentDef, seen) : false;\n collectionClassMemo.set(def, isCollection);\n\n return isCollection;\n };\n\n for (const [objectName, objectDef] of Object.entries(manifestObjects)) {\n const def = objectDef;\n\n // Skip local objects (they're imported from local entry point)\n if (!def.packageName || def.packageName === manifest.packageName) {\n continue;\n }\n\n const importPath = def.importPath || def.packageName;\n const exportName = def.exportName || def.className || objectName;\n const collectionExportName = def.collectionExportName;\n const hasCollection = def.hasCollection; // Check if collection class actually exists\n const tableName = def.collection || objectName.toLowerCase();\n\n // Generate import statement\n // Only import collection if it exists (hasCollection is truthy)\n if (hasCollection && collectionExportName) {\n imports.push(\n `import { ${exportName}, ${collectionExportName} } from '${importPath}';`,\n );\n } else {\n imports.push(`import { ${exportName} } from '${importPath}';`);\n }\n importedEntryCount++;\n\n if (isCollectionClass(def)) {\n continue;\n }\n\n // Generate registration calls\n // The import above already triggers the @smrt() decorator which registers the class\n // properly with its simple name and qualified name. We call register() again with\n // an empty config just to ensure the class is registered (in case it lacks a decorator).\n // Do NOT pass { name: qualifiedName } as that creates a separate registry entry.\n registrations.push(\n `ObjectRegistry.register(${exportName}, { name: ${JSON.stringify(exportName)}, packageName: ${JSON.stringify(def.packageName)} });`,\n );\n\n // Only register collection if it exists\n if (hasCollection && collectionExportName) {\n registrations.push(\n `ObjectRegistry.registerCollection('${tableName}', ${collectionExportName});`,\n );\n }\n\n registeredObjectCount++;\n }\n\n // Skip generation if no external entries\n if (importedEntryCount === 0) {\n console.log('[smrt:consumer] No external entries - skipping register.js');\n return;\n }\n\n const registeredObjectLabel =\n registeredObjectCount === 1 ? 'object' : 'objects';\n\n // Generate file content\n const content = `/**\n * Auto-generated by @happyvertical/smrt-core/consumer-plugin\n * DO NOT EDIT - This file is regenerated on every build\n *\n * Registers SMRT objects from external packages for CLI discovery.\n * Generated at: ${new Date().toISOString()}\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${imports.join('\\n')}\n\n// Register all objects (executed during module evaluation)\n${registrations.join('\\n')}\n\nexport function registerAll() {\n // Objects are already registered during module evaluation\n console.log('[smrt:register] Registered ${registeredObjectCount} external ${registeredObjectLabel}');\n}\n`;\n\n // Create .smrt directory if needed\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write registration file\n fs.writeFileSync(registerPath, content, 'utf-8');\n\n console.log(\n `[smrt:consumer] Generated .smrt/register.js with ${importedEntryCount} external entries (${registeredObjectCount} registered ${registeredObjectLabel})`,\n );\n}\n\n/**\n * Generate project-specific types\n */\nasync function generateProjectTypes(\n typeManifest: ConsumerManifest,\n typesDir: string,\n projectRoot: string,\n): Promise<void> {\n if (!typeManifest || Object.keys(typeManifest.objects).length === 0) {\n console.log(\n '[smrt:consumer] No SMRT objects found, skipping type generation',\n );\n return;\n }\n\n await generateDeclarations({\n // The aggregated manifest is a runtime SMRT manifest assembled from external\n // package manifests; it is intentionally typed loosely at the JSON boundary,\n // so narrow it to the declaration generator's strict manifest shape here.\n manifest: typeManifest as unknown as SmartObjectManifest,\n outDir: typesDir,\n projectRoot,\n includeVirtualModules: true,\n includeObjectTypes: true,\n });\n\n console.log(\n `[smrt:consumer] Generated types for ${Object.keys(typeManifest.objects).length} objects`,\n );\n}\n\n/**\n * Get type file name for virtual module\n */\nfunction getTypeFileName(virtualModule: string): string {\n const moduleMap: Record<string, string> = {\n '@smrt/routes': 'smrt-routes.d.ts',\n '@smrt/client': 'smrt-client.d.ts',\n '@smrt/mcp': 'smrt-mcp.d.ts',\n '@smrt/types': 'smrt-types.d.ts',\n '@smrt/manifest': 'smrt-manifest.d.ts',\n };\n return moduleMap[virtualModule] || 'smrt-unknown.d.ts';\n}\n\n/**\n * Fallback modules for when types aren't available\n */\nfunction generateFallbackRoutesModule(): string {\n return `\n// Fallback routes module\nexport function setupRoutes(app) {\n console.warn('[smrt:consumer] No routes available - SMRT packages may not be properly configured');\n}\nexport default setupRoutes;\n`;\n}\n\nfunction generateFallbackClientModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `\n// Fallback client module\nexport function createClient(basePath = '/api/v1') {\n console.warn('[smrt:consumer] No API client available - SMRT packages may not be properly configured');\n return {};\n}\nexport default createClient;\n`;\n }\n\n // Generate basic client from manifest\n const clientMethods = objects\n .map(([name, obj]) => {\n const { collection } = obj;\n return `\n ${name}: {\n list: () => fetch(basePath + '/${collection}').then(r => r.json()),\n get: (id) => fetch(basePath + '/${collection}/' + id).then(r => r.json()),\n create: (data) => fetch(basePath + '/${collection}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n update: (id, data) => fetch(basePath + '/${collection}/' + id, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n delete: (id) => fetch(basePath + '/${collection}/' + id, {\n method: 'DELETE'\n }).then(r => r.ok)\n }`;\n })\n .join(',');\n\n return `\n// Auto-generated API client from SMRT consumer\nexport function createClient(basePath = '/api/v1') {\n return {${clientMethods}\n };\n}\nexport default createClient;\n`;\n}\n\nfunction generateFallbackMcpModule(): string {\n return `\n// Fallback MCP module\nexport const tools = [];\nexport function createMCPServer() {\n console.warn('[smrt:consumer] No MCP tools available - SMRT packages may not be properly configured');\n return { name: 'smrt-consumer', version: '1.0.0', tools: [] };\n}\nexport default createMCPServer;\n`;\n}\n\nfunction generateFallbackTypesModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `// No types available`;\n }\n\n // Generate basic interfaces\n const interfaces = objects.map(([_name, obj]) => {\n return `export interface ${obj.className}Data {\n id?: string;\n created_at?: string;\n updated_at?: string;\n [key: string]: any;\n}`;\n });\n\n return interfaces.join('\\n\\n');\n}\n\nfunction generateFallbackManifestModule(manifest: ConsumerManifest): string {\n return `\n// Auto-generated manifest from SMRT consumer\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\nexport default manifest;\n`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/consumer-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for consuming SMRT packages\n * Solves virtual module resolution in downstream projects\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generateDeclarations } from '../prebuild/index.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\n\n/**\n * Loosely-typed view of an object definition as carried by an external\n * package's static manifest. The static manifests are read from JSON at the\n * package boundary, so only the fields this plugin consumes are typed; the\n * index signature preserves any additional fields (e.g. for spreads). This is\n * a structural superset of a manifest `SmartObjectDefinition` plus the\n * consumer-only `hasCollection` marker.\n */\ninterface ConsumerObjectDefinition {\n className?: string;\n packageName?: string;\n packageVersion?: string;\n qualifiedName?: string;\n importPath?: string;\n exportName?: string;\n collectionExportName?: string;\n hasCollection?: boolean;\n collection?: string;\n extends?: string;\n extendsQualified?: string;\n extendsTypeArg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Aggregated manifest assembled by the consumer plugin from one or more\n * external package manifests. Loosely typed because the inputs originate from\n * JSON read at the package boundary.\n */\ninterface ConsumerManifest {\n version: string;\n timestamp: number;\n packageName?: string;\n packageVersion?: string;\n objects: Record<string, ConsumerObjectDefinition>;\n}\n\n/**\n * Minimal structural shape of a parsed `package.json` consumed here (name,\n * version, and the export map used to derive import paths). The index\n * signature keeps the remaining fields accessible.\n */\ninterface ConsumerPackageJson {\n name?: string;\n version?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface SmrtConsumerOptions {\n /** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */\n packages?: string[];\n /** Generate TypeScript declarations */\n generateTypes?: boolean;\n /** Output directory for generated types */\n typesDir?: string;\n /** Project root path */\n projectRoot?: string;\n /** SvelteKit integration mode */\n svelteKit?: boolean;\n /** Use static types only (for federation builds) */\n staticTypes?: boolean;\n /** Disable file scanning */\n disableScanning?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@smrt/routes': 'smrt:routes',\n '@smrt/client': 'smrt:client',\n '@smrt/mcp': 'smrt:mcp',\n '@smrt/types': 'smrt:types',\n '@smrt/manifest': 'smrt:manifest',\n};\n\n/**\n * Consumer plugin for projects that use SMRT packages\n */\nexport function smrtConsumer(options: SmrtConsumerOptions = {}): Plugin {\n const {\n packages = [],\n generateTypes = true,\n typesDir = 'src/types/smrt-generated',\n projectRoot = process.cwd(),\n disableScanning = false,\n } = options;\n\n let smrtPackages: string[] = [];\n let typeManifest: ConsumerManifest | null = null;\n let typesGenerated = false;\n\n return {\n name: 'smrt-consumer',\n\n async buildStart() {\n console.log('[smrt:consumer] Initializing SMRT consumer plugin');\n\n // Discover SMRT packages if not explicitly specified\n if (packages.length === 0 && !disableScanning) {\n smrtPackages = await discoverSmrtPackages(projectRoot);\n } else {\n smrtPackages = packages;\n }\n\n if (smrtPackages.length > 0) {\n console.log(\n `[smrt:consumer] Found SMRT packages: ${smrtPackages.join(', ')}`,\n );\n\n // Aggregate type manifests from discovered packages\n typeManifest = await aggregateTypeManifests(smrtPackages, projectRoot);\n\n // Save aggregated manifest for CLI discovery\n await saveAggregatedManifest(typeManifest, projectRoot);\n\n // Generate registration file for CLI class loading\n await generateRegistrationFile(typeManifest, projectRoot);\n\n // Generate types if requested\n if (generateTypes && !typesGenerated) {\n await generateProjectTypes(typeManifest, typesDir, projectRoot);\n typesGenerated = true;\n }\n } else {\n console.log('[smrt:consumer] No SMRT packages found');\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n },\n\n resolveId(id, _importer) {\n // Resolve virtual modules to generated type declarations\n if (id in VIRTUAL_MODULES) {\n const typeFileName = getTypeFileName(id);\n const typePath = path.join(projectRoot, typesDir, typeFileName);\n\n // If types file exists, resolve to it\n if (fs.existsSync(typePath)) {\n return typePath;\n }\n\n // Otherwise use virtual module ID for runtime resolution\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n return null;\n },\n\n async load(id) {\n // Handle virtual modules if types aren't available\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!typeManifest) {\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n return generateFallbackRoutesModule();\n\n case 'smrt:client':\n return generateFallbackClientModule(typeManifest);\n\n case 'smrt:mcp':\n return generateFallbackMcpModule();\n\n case 'smrt:types':\n return generateFallbackTypesModule(typeManifest);\n\n case 'smrt:manifest':\n return generateFallbackManifestModule(typeManifest);\n\n default:\n return null;\n }\n },\n };\n}\n\n/**\n * Discover SMRT packages from a consumer app's dependencies.\n *\n * Intentional split (#1579): this **consumer-plugin** path is async and\n * resolves SMRT packages from the downstream app's `package.json` dependency\n * names (`@have/`/`smrt` heuristic + `hasSmrtManifest` probe) inside the Vite\n * consumer plugin. It is deliberately separate from the build-time\n * `discoverSmrtPackages()` in `src/manifest/discover-smrt-packages.ts` — a\n * synchronous, lockfile-cached `node_modules` manifest scan used for manifest\n * generation. Different inputs, contexts, and lifecycles, not duplicated logic.\n */\nasync function discoverSmrtPackages(projectRoot: string): Promise<string[]> {\n const packages: string[] = [];\n const nodeModulesPath = path.join(projectRoot, 'node_modules');\n\n if (!fs.existsSync(nodeModulesPath)) {\n return packages;\n }\n\n try {\n // Check package.json for workspace dependencies\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n // Look for packages that likely contain SMRT objects\n for (const [name, version] of Object.entries(allDeps)) {\n if (\n typeof version === 'string' &&\n (name.includes('smrt') ||\n name.includes('@have/') ||\n (await hasSmrtManifest(nodeModulesPath, name)))\n ) {\n packages.push(name);\n }\n }\n }\n } catch (error) {\n console.warn('[smrt:consumer] Error discovering packages:', error);\n }\n\n return packages;\n}\n\n/**\n * Check if a package has SMRT manifest\n */\nasync function hasSmrtManifest(\n nodeModulesPath: string,\n packageName: string,\n): Promise<boolean> {\n const packagePath = path.join(nodeModulesPath, packageName);\n const manifestPath = path.join(\n packagePath,\n 'dist',\n 'manifest',\n 'static-manifest.js',\n );\n return fs.existsSync(manifestPath);\n}\n\n/**\n * Aggregate type manifests from multiple packages\n */\nasync function aggregateTypeManifests(\n packages: string[],\n projectRoot: string,\n): Promise<ConsumerManifest> {\n const aggregatedManifest: ConsumerManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n };\n\n for (const packageName of packages) {\n try {\n const packageDir = path.join(projectRoot, 'node_modules', packageName);\n\n // Load package.json for version and export information\n const packageJsonPath = path.join(packageDir, 'package.json');\n let packageJson: ConsumerPackageJson;\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(packageJsonContent) as ConsumerPackageJson;\n } catch {\n console.warn(\n `[smrt:consumer] Could not read package.json for ${packageName}`,\n );\n continue;\n }\n\n // Try multiple manifest locations\n const manifestCandidates = [\n path.join(packageDir, 'dist', 'manifest', 'static-manifest.js'),\n path.join(packageDir, 'dist', 'manifest.json'),\n path.join(packageDir, 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (fs.existsSync(manifestPath)) {\n // Import or read the manifest\n let manifest: Partial<ConsumerManifest> | undefined;\n if (manifestPath.endsWith('.js')) {\n const manifestModule = await import(manifestPath);\n manifest = manifestModule.staticManifest || manifestModule.default;\n } else {\n const manifestContent = fs.readFileSync(manifestPath, 'utf-8');\n manifest = JSON.parse(manifestContent) as Partial<ConsumerManifest>;\n }\n\n if (manifest?.objects) {\n console.log(\n `[smrt:consumer] Loaded manifest from ${packageName} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n // ENHANCED: Preserve package metadata for each object\n for (const [objectName, objectDef] of Object.entries(\n manifest.objects,\n )) {\n const def = objectDef;\n\n aggregatedManifest.objects[objectName] = {\n ...def,\n // Ensure package metadata is preserved/set\n packageName:\n def.packageName || manifest.packageName || packageName,\n packageVersion:\n def.packageVersion ||\n manifest.packageVersion ||\n packageJson.version,\n // Add fallback import paths if missing\n importPath: def.importPath || determineImportPath(packageJson),\n exportName: def.exportName || def.className || objectName,\n collectionExportName:\n def.collectionExportName ||\n `${def.className || objectName}Collection`,\n };\n }\n\n break; // Use first found manifest for this package\n }\n }\n }\n } catch (error) {\n console.warn(\n `[smrt:consumer] Error loading manifest from ${packageName}:`,\n error,\n );\n }\n }\n\n return aggregatedManifest;\n}\n\n/**\n * Determine import path from package.json\n */\nfunction determineImportPath(packageJson: ConsumerPackageJson): string {\n const packageName = packageJson.name;\n\n if (!packageName) {\n throw new Error('Package name not found in package.json');\n }\n\n // Strategy 1: Check for specific exports\n if (packageJson.exports) {\n // Check for objects export\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n\n // Check for main export\n const mainExport = packageJson.exports['.'];\n if (mainExport) {\n // Handle conditional exports\n if (typeof mainExport === 'object' && mainExport !== null) {\n const conditional = mainExport as Record<string, unknown>;\n if (conditional.import) {\n return packageName;\n }\n if (conditional.default) {\n return packageName;\n }\n }\n return packageName;\n }\n }\n\n // Strategy 2: Check main field\n if (packageJson.main) {\n return packageName;\n }\n\n // Strategy 3: Fallback to package name\n return packageName;\n}\n\n/**\n * Save aggregated manifest to .smrt/manifest.json for CLI discovery\n */\nasync function saveAggregatedManifest(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const manifestPath = path.join(smrtDir, 'manifest.json');\n\n try {\n // Create .smrt directory if it doesn't exist\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write manifest\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n console.log(\n `[smrt:consumer] Saved aggregated manifest to .smrt/manifest.json (${Object.keys(manifest.objects).length} objects)`,\n );\n } catch (error) {\n console.warn('[smrt:consumer] Failed to save aggregated manifest:', error);\n }\n}\n\n/**\n * Generate registration file for CLI class loading\n *\n * Creates .smrt/register.js with static imports and registrations\n * for all external SMRT objects discovered during build.\n */\nasync function generateRegistrationFile(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const registerPath = path.join(smrtDir, 'register.js');\n\n // Build import statements and registrations\n const imports: string[] = [];\n const registrations: string[] = [];\n let importedEntryCount = 0;\n let registeredObjectCount = 0;\n\n const manifestObjects = manifest.objects;\n const manifestObjectLookup = new Map<string, ConsumerObjectDefinition>();\n for (const [key, def] of Object.entries(manifestObjects)) {\n const candidate = def;\n const lookupKeys = [\n key,\n key.includes(':') ? key.split(':').pop() : undefined,\n candidate.qualifiedName,\n candidate.className,\n candidate.exportName,\n ];\n\n for (const lookupKey of lookupKeys) {\n if (lookupKey && !manifestObjectLookup.has(lookupKey)) {\n manifestObjectLookup.set(lookupKey, candidate);\n }\n }\n }\n\n const collectionClassMemo = new WeakMap<object, boolean>();\n\n const isCollectionClass = (\n def: ConsumerObjectDefinition | undefined,\n seen = new Set<string>(),\n ): boolean => {\n if (!def || typeof def !== 'object') {\n return false;\n }\n\n const cached = collectionClassMemo.get(def);\n if (cached !== undefined) {\n return cached;\n }\n\n if (\n def?.extends === 'SmrtCollection' ||\n def?.extendsTypeArg !== undefined\n ) {\n collectionClassMemo.set(def, true);\n return true;\n }\n\n const parentName = def?.extendsQualified || def?.extends;\n if (!parentName || seen.has(parentName)) {\n collectionClassMemo.set(def, false);\n return false;\n }\n seen.add(parentName);\n\n const parentDef = manifestObjectLookup.get(parentName);\n const isCollection = parentDef ? isCollectionClass(parentDef, seen) : false;\n collectionClassMemo.set(def, isCollection);\n\n return isCollection;\n };\n\n for (const [objectName, objectDef] of Object.entries(manifestObjects)) {\n const def = objectDef;\n\n // Skip local objects (they're imported from local entry point)\n if (!def.packageName || def.packageName === manifest.packageName) {\n continue;\n }\n\n const importPath = def.importPath || def.packageName;\n const exportName = def.exportName || def.className || objectName;\n const collectionExportName = def.collectionExportName;\n const hasCollection = def.hasCollection; // Check if collection class actually exists\n const tableName = def.collection || objectName.toLowerCase();\n\n // Generate import statement\n // Only import collection if it exists (hasCollection is truthy)\n if (hasCollection && collectionExportName) {\n imports.push(\n `import { ${exportName}, ${collectionExportName} } from '${importPath}';`,\n );\n } else {\n imports.push(`import { ${exportName} } from '${importPath}';`);\n }\n importedEntryCount++;\n\n if (isCollectionClass(def)) {\n continue;\n }\n\n // Generate registration calls\n // The import above already triggers the @smrt() decorator which registers the class\n // properly with its simple name and qualified name. We call register() again with\n // an empty config just to ensure the class is registered (in case it lacks a decorator).\n // Do NOT pass { name: qualifiedName } as that creates a separate registry entry.\n registrations.push(\n `ObjectRegistry.register(${exportName}, { name: ${JSON.stringify(exportName)}, packageName: ${JSON.stringify(def.packageName)} });`,\n );\n\n // Only register collection if it exists\n if (hasCollection && collectionExportName) {\n registrations.push(\n `ObjectRegistry.registerCollection('${tableName}', ${collectionExportName});`,\n );\n }\n\n registeredObjectCount++;\n }\n\n // Skip generation if no external entries\n if (importedEntryCount === 0) {\n console.log('[smrt:consumer] No external entries - skipping register.js');\n return;\n }\n\n const registeredObjectLabel =\n registeredObjectCount === 1 ? 'object' : 'objects';\n\n // Generate file content\n const content = `/**\n * Auto-generated by @happyvertical/smrt-core/consumer-plugin\n * DO NOT EDIT - This file is regenerated on every build\n *\n * Registers SMRT objects from external packages for CLI discovery.\n * Generated at: ${new Date().toISOString()}\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${imports.join('\\n')}\n\n// Register all objects (executed during module evaluation)\n${registrations.join('\\n')}\n\nexport function registerAll() {\n // Objects are already registered during module evaluation\n console.log('[smrt:register] Registered ${registeredObjectCount} external ${registeredObjectLabel}');\n}\n`;\n\n // Create .smrt directory if needed\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write registration file\n fs.writeFileSync(registerPath, content, 'utf-8');\n\n console.log(\n `[smrt:consumer] Generated .smrt/register.js with ${importedEntryCount} external entries (${registeredObjectCount} registered ${registeredObjectLabel})`,\n );\n}\n\n/**\n * Generate project-specific types\n */\nasync function generateProjectTypes(\n typeManifest: ConsumerManifest,\n typesDir: string,\n projectRoot: string,\n): Promise<void> {\n if (!typeManifest || Object.keys(typeManifest.objects).length === 0) {\n console.log(\n '[smrt:consumer] No SMRT objects found, skipping type generation',\n );\n return;\n }\n\n await generateDeclarations({\n // The aggregated manifest is a runtime SMRT manifest assembled from external\n // package manifests; it is intentionally typed loosely at the JSON boundary,\n // so narrow it to the declaration generator's strict manifest shape here.\n manifest: typeManifest as unknown as SmartObjectManifest,\n outDir: typesDir,\n projectRoot,\n includeVirtualModules: true,\n includeObjectTypes: true,\n });\n\n console.log(\n `[smrt:consumer] Generated types for ${Object.keys(typeManifest.objects).length} objects`,\n );\n}\n\n/**\n * Get type file name for virtual module\n */\nfunction getTypeFileName(virtualModule: string): string {\n const moduleMap: Record<string, string> = {\n '@smrt/routes': 'smrt-routes.d.ts',\n '@smrt/client': 'smrt-client.d.ts',\n '@smrt/mcp': 'smrt-mcp.d.ts',\n '@smrt/types': 'smrt-types.d.ts',\n '@smrt/manifest': 'smrt-manifest.d.ts',\n };\n return moduleMap[virtualModule] || 'smrt-unknown.d.ts';\n}\n\n/**\n * Fallback modules for when types aren't available\n */\nfunction generateFallbackRoutesModule(): string {\n return `\n// Fallback routes module\nexport function setupRoutes(app) {\n console.warn('[smrt:consumer] No routes available - SMRT packages may not be properly configured');\n}\nexport default setupRoutes;\n`;\n}\n\nfunction generateFallbackClientModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `\n// Fallback client module\nexport function createClient(basePath = '/api/v1') {\n console.warn('[smrt:consumer] No API client available - SMRT packages may not be properly configured');\n return {};\n}\nexport default createClient;\n`;\n }\n\n // Generate basic client from manifest\n const clientMethods = objects\n .map(([name, obj]) => {\n const { collection } = obj;\n return `\n ${name}: {\n list: () => fetch(basePath + '/${collection}').then(r => r.json()),\n get: (id) => fetch(basePath + '/${collection}/' + id).then(r => r.json()),\n create: (data) => fetch(basePath + '/${collection}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n update: (id, data) => fetch(basePath + '/${collection}/' + id, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n delete: (id) => fetch(basePath + '/${collection}/' + id, {\n method: 'DELETE'\n }).then(r => r.ok)\n }`;\n })\n .join(',');\n\n return `\n// Auto-generated API client from SMRT consumer\nexport function createClient(basePath = '/api/v1') {\n return {${clientMethods}\n };\n}\nexport default createClient;\n`;\n}\n\nfunction generateFallbackMcpModule(): string {\n return `\n// Fallback MCP module\nexport const tools = [];\nexport function createMCPServer() {\n console.warn('[smrt:consumer] No MCP tools available - SMRT packages may not be properly configured');\n return { name: 'smrt-consumer', version: '1.0.0', tools: [] };\n}\nexport default createMCPServer;\n`;\n}\n\nfunction generateFallbackTypesModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `// No types available`;\n }\n\n // Generate basic interfaces\n const interfaces = objects.map(([_name, obj]) => {\n return `export interface ${obj.className}Data {\n id?: string;\n created_at?: string;\n updated_at?: string;\n [key: string]: any;\n}`;\n });\n\n return interfaces.join('\\n\\n');\n}\n\nfunction generateFallbackManifestModule(manifest: ConsumerManifest): string {\n return `\n// Auto-generated manifest from SMRT consumer\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\nexport default manifest;\n`;\n}\n"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ export type LegacyPropertyDecoratorTarget = {
4
4
  };
5
5
  };
6
6
  export type CompatiblePropertyDecoratorContext<This, Value> = string | symbol | ClassFieldDecoratorContext<This, Value>;
7
- export interface CompatiblePropertyDecorator<This = any, Value = any> {
7
+ export interface CompatiblePropertyDecorator<This = unknown, Value = unknown> {
8
8
  (target: object, propertyKey: string | symbol): void;
9
9
  (value: undefined, context: ClassFieldDecoratorContext<This, Value>): void;
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/decorators/compatibility.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,WAAW,CAAC,EAAE,QAAQ,GAAG;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kCAAkC,CAAC,IAAI,EAAE,KAAK,IACtD,MAAM,GACN,MAAM,GACN,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAE5C,MAAM,WAAW,2BAA2B,CAAC,IAAI,GAAG,GAAG,EAAE,KAAK,GAAG,GAAG;IAClE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrD,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CAC5E;AA2FD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAU7E;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,QAAQ,EAChB,gBAAgB,CAAC,EAAE,qBAAqB,GACvC,IAAI,CAsBN;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,KAAK,EAC1D,aAAa,EAAE,6BAA6B,GAAG,SAAS,EACxD,oBAAoB,EAAE,kCAAkC,CAAC,IAAI,EAAE,KAAK,CAAC,EACrE,sBAAsB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,GACvE,IAAI,CAiCN"}
1
+ {"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/decorators/compatibility.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,WAAW,CAAC,EAAE,QAAQ,GAAG;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kCAAkC,CAAC,IAAI,EAAE,KAAK,IACtD,MAAM,GACN,MAAM,GACN,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAE5C,MAAM,WAAW,2BAA2B,CAAC,IAAI,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO;IAC1E,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrD,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CAC5E;AA2FD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAU7E;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,QAAQ,EAChB,gBAAgB,CAAC,EAAE,qBAAqB,GACvC,IAAI,CAsBN;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,KAAK,EAC1D,aAAa,EAAE,6BAA6B,GAAG,SAAS,EACxD,oBAAoB,EAAE,kCAAkC,CAAC,IAAI,EAAE,KAAK,CAAC,EACrE,sBAAsB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,GACvE,IAAI,CAiCN"}
@@ -1 +1 @@
1
- {"version":3,"file":"compatibility.js","sources":["../../src/decorators/compatibility.ts"],"sourcesContent":["type DecoratorMetadataStore = Record<PropertyKey, unknown>;\n\nconst PENDING_FIELD_DECORATORS_KEY = Symbol.for(\n '@happyvertical/smrt-core/pending-field-decorators',\n);\nconst standardDecoratorRegistrations = new WeakMap<\n Function,\n WeakSet<(className: string) => void>\n>();\n\ntype PendingDecoratorRegistration = {\n register: (className: string) => void;\n};\n\nexport type LegacyPropertyDecoratorTarget = {\n constructor?: Function & {\n name?: string;\n };\n};\n\nexport type CompatiblePropertyDecoratorContext<This, Value> =\n | string\n | symbol\n | ClassFieldDecoratorContext<This, Value>;\n\nexport interface CompatiblePropertyDecorator<This = any, Value = any> {\n (target: object, propertyKey: string | symbol): void;\n (value: undefined, context: ClassFieldDecoratorContext<This, Value>): void;\n}\n\nfunction getDecoratorConstructor(target: unknown): Function | undefined {\n if (typeof target === 'function') {\n return target;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor;\n }\n\n return undefined;\n}\n\nfunction markStandardDecoratorRegistration(\n target: unknown,\n register: (className: string) => void,\n): boolean {\n const ctor = getDecoratorConstructor(target);\n if (!ctor) {\n return false;\n }\n\n const registeredCallbacks =\n standardDecoratorRegistrations.get(ctor) ?? new WeakSet();\n if (registeredCallbacks.has(register)) {\n return false;\n }\n\n registeredCallbacks.add(register);\n standardDecoratorRegistrations.set(ctor, registeredCallbacks);\n return true;\n}\n\nfunction getDecoratorMetadata(\n contextOrMetadata:\n | ClassFieldDecoratorContext<any, any>\n | ClassDecoratorContext\n | DecoratorMetadataStore\n | undefined,\n): DecoratorMetadataStore | undefined {\n if (!contextOrMetadata || typeof contextOrMetadata !== 'object') {\n return undefined;\n }\n\n if ('metadata' in contextOrMetadata) {\n const { metadata } = contextOrMetadata as {\n metadata?: DecoratorMetadataStore;\n };\n return metadata && typeof metadata === 'object' ? metadata : undefined;\n }\n\n return contextOrMetadata;\n}\n\nfunction getClassDecoratorMetadata(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): DecoratorMetadataStore | undefined {\n const metadataFromContext = getDecoratorMetadata(decoratorContext);\n if (metadataFromContext) {\n return metadataFromContext;\n }\n\n const metadataSymbol = (Symbol as typeof Symbol & { metadata?: symbol })\n .metadata;\n if (!metadataSymbol) {\n return undefined;\n }\n\n const metadata = (target as unknown as Record<PropertyKey, unknown>)[\n metadataSymbol\n ];\n return metadata && typeof metadata === 'object'\n ? (metadata as DecoratorMetadataStore)\n : undefined;\n}\n\nfunction queuePendingFieldDecorator(\n metadata: DecoratorMetadataStore,\n register: (className: string) => void,\n): void {\n const pendingDecorators =\n (metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined) ?? [];\n\n pendingDecorators.push({ register });\n metadata[PENDING_FIELD_DECORATORS_KEY] = pendingDecorators;\n}\n\nexport function resolveDecoratorClassName(target: unknown): string | undefined {\n if (typeof target === 'function') {\n return target.name;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor?.name;\n }\n\n return undefined;\n}\n\nexport function applyPendingDecoratorRegistrations(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): void {\n const metadata = getClassDecoratorMetadata(target, decoratorContext);\n if (!metadata) {\n return;\n }\n\n const pendingDecorators = metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined;\n if (!pendingDecorators || pendingDecorators.length === 0) {\n return;\n }\n\n for (const { register } of pendingDecorators) {\n if (!markStandardDecoratorRegistration(target, register)) {\n continue;\n }\n\n register(target.name);\n }\n\n Reflect.deleteProperty(metadata, PENDING_FIELD_DECORATORS_KEY);\n}\n\nexport function registerCompatibleFieldDecorator<This, Value>(\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<This, Value>,\n registerFieldDecorator: (className: string, propertyKey: string) => void,\n): void {\n if (\n typeof propertyKeyOrContext === 'string' ||\n typeof propertyKeyOrContext === 'symbol'\n ) {\n const className = resolveDecoratorClassName(targetOrValue);\n if (className) {\n registerFieldDecorator(className, String(propertyKeyOrContext));\n }\n return;\n }\n\n const context = propertyKeyOrContext;\n const propertyKey = String(context.name);\n const register = (className: string) =>\n registerFieldDecorator(className, propertyKey);\n const metadata = getDecoratorMetadata(context);\n\n if (metadata) {\n queuePendingFieldDecorator(metadata, register);\n return;\n }\n\n context.addInitializer?.(function registerSmrtDecorator() {\n if (!markStandardDecoratorRegistration(this, register)) {\n return;\n }\n\n const className = resolveDecoratorClassName(this);\n if (className) {\n register(className);\n }\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compatibility.js","sources":["../../src/decorators/compatibility.ts"],"sourcesContent":["type DecoratorMetadataStore = Record<PropertyKey, unknown>;\n\nconst PENDING_FIELD_DECORATORS_KEY = Symbol.for(\n '@happyvertical/smrt-core/pending-field-decorators',\n);\nconst standardDecoratorRegistrations = new WeakMap<\n Function,\n WeakSet<(className: string) => void>\n>();\n\ntype PendingDecoratorRegistration = {\n register: (className: string) => void;\n};\n\nexport type LegacyPropertyDecoratorTarget = {\n constructor?: Function & {\n name?: string;\n };\n};\n\nexport type CompatiblePropertyDecoratorContext<This, Value> =\n | string\n | symbol\n | ClassFieldDecoratorContext<This, Value>;\n\nexport interface CompatiblePropertyDecorator<This = unknown, Value = unknown> {\n (target: object, propertyKey: string | symbol): void;\n (value: undefined, context: ClassFieldDecoratorContext<This, Value>): void;\n}\n\nfunction getDecoratorConstructor(target: unknown): Function | undefined {\n if (typeof target === 'function') {\n return target;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor;\n }\n\n return undefined;\n}\n\nfunction markStandardDecoratorRegistration(\n target: unknown,\n register: (className: string) => void,\n): boolean {\n const ctor = getDecoratorConstructor(target);\n if (!ctor) {\n return false;\n }\n\n const registeredCallbacks =\n standardDecoratorRegistrations.get(ctor) ?? new WeakSet();\n if (registeredCallbacks.has(register)) {\n return false;\n }\n\n registeredCallbacks.add(register);\n standardDecoratorRegistrations.set(ctor, registeredCallbacks);\n return true;\n}\n\nfunction getDecoratorMetadata(\n contextOrMetadata:\n | ClassFieldDecoratorContext<unknown, unknown>\n | ClassDecoratorContext\n | DecoratorMetadataStore\n | undefined,\n): DecoratorMetadataStore | undefined {\n if (!contextOrMetadata || typeof contextOrMetadata !== 'object') {\n return undefined;\n }\n\n if ('metadata' in contextOrMetadata) {\n const { metadata } = contextOrMetadata as {\n metadata?: DecoratorMetadataStore;\n };\n return metadata && typeof metadata === 'object' ? metadata : undefined;\n }\n\n return contextOrMetadata;\n}\n\nfunction getClassDecoratorMetadata(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): DecoratorMetadataStore | undefined {\n const metadataFromContext = getDecoratorMetadata(decoratorContext);\n if (metadataFromContext) {\n return metadataFromContext;\n }\n\n const metadataSymbol = (Symbol as typeof Symbol & { metadata?: symbol })\n .metadata;\n if (!metadataSymbol) {\n return undefined;\n }\n\n const metadata = (target as unknown as Record<PropertyKey, unknown>)[\n metadataSymbol\n ];\n return metadata && typeof metadata === 'object'\n ? (metadata as DecoratorMetadataStore)\n : undefined;\n}\n\nfunction queuePendingFieldDecorator(\n metadata: DecoratorMetadataStore,\n register: (className: string) => void,\n): void {\n const pendingDecorators =\n (metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined) ?? [];\n\n pendingDecorators.push({ register });\n metadata[PENDING_FIELD_DECORATORS_KEY] = pendingDecorators;\n}\n\nexport function resolveDecoratorClassName(target: unknown): string | undefined {\n if (typeof target === 'function') {\n return target.name;\n }\n\n if (target && typeof target === 'object') {\n return (target as LegacyPropertyDecoratorTarget).constructor?.name;\n }\n\n return undefined;\n}\n\nexport function applyPendingDecoratorRegistrations(\n target: Function,\n decoratorContext?: ClassDecoratorContext,\n): void {\n const metadata = getClassDecoratorMetadata(target, decoratorContext);\n if (!metadata) {\n return;\n }\n\n const pendingDecorators = metadata[PENDING_FIELD_DECORATORS_KEY] as\n | PendingDecoratorRegistration[]\n | undefined;\n if (!pendingDecorators || pendingDecorators.length === 0) {\n return;\n }\n\n for (const { register } of pendingDecorators) {\n if (!markStandardDecoratorRegistration(target, register)) {\n continue;\n }\n\n register(target.name);\n }\n\n Reflect.deleteProperty(metadata, PENDING_FIELD_DECORATORS_KEY);\n}\n\nexport function registerCompatibleFieldDecorator<This, Value>(\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<This, Value>,\n registerFieldDecorator: (className: string, propertyKey: string) => void,\n): void {\n if (\n typeof propertyKeyOrContext === 'string' ||\n typeof propertyKeyOrContext === 'symbol'\n ) {\n const className = resolveDecoratorClassName(targetOrValue);\n if (className) {\n registerFieldDecorator(className, String(propertyKeyOrContext));\n }\n return;\n }\n\n const context = propertyKeyOrContext;\n const propertyKey = String(context.name);\n const register = (className: string) =>\n registerFieldDecorator(className, propertyKey);\n const metadata = getDecoratorMetadata(context);\n\n if (metadata) {\n queuePendingFieldDecorator(metadata, register);\n return;\n }\n\n context.addInitializer?.(function registerSmrtDecorator() {\n if (!markStandardDecoratorRegistration(this, register)) {\n return;\n }\n\n const className = resolveDecoratorClassName(this);\n if (className) {\n register(className);\n }\n });\n}\n"],"names":[],"mappings":"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"}
@@ -36,7 +36,7 @@ export interface FieldOptions {
36
36
  /** Whether the field is required */
37
37
  required?: boolean;
38
38
  /** Default value for the field */
39
- default?: any;
39
+ default?: unknown;
40
40
  /** Whether the field is unique */
41
41
  unique?: boolean;
42
42
  /**
@@ -214,7 +214,7 @@ export declare function field(options?: FieldOptions | NumericFieldOptions | Tex
214
214
  * @see {@link oneToMany} for the inverse (parent) side of the relationship
215
215
  * @see SmrtObject.loadRelated for lazy-loading the related object at runtime
216
216
  */
217
- export declare function foreignKey(relatedClass: string | Function | any, options?: Omit<RelationshipFieldOptions, 'related'>): CompatiblePropertyDecorator;
217
+ export declare function foreignKey(relatedClass: string | Function, options?: Omit<RelationshipFieldOptions, 'related'>): CompatiblePropertyDecorator;
218
218
  /**
219
219
  * Declares a cross-package foreign key reference.
220
220
  *
@@ -315,7 +315,7 @@ export declare function crossPackageRef(qualifiedName: string, options?: CrossPa
315
315
  * @see {@link foreignKey} for the many-to-one (child) side of the relationship
316
316
  * @see SmrtObject.loadRelatedMany for lazy-loading at runtime
317
317
  */
318
- export declare function oneToMany(relatedClass: string | Function | any, options?: Omit<RelationshipFieldOptions, 'related'>): CompatiblePropertyDecorator;
318
+ export declare function oneToMany(relatedClass: string | Function, options?: Omit<RelationshipFieldOptions, 'related'>): CompatiblePropertyDecorator;
319
319
  /**
320
320
  * Declares a many-to-many relationship between two `SmrtObject` classes via a join table.
321
321
  *
@@ -342,7 +342,7 @@ export declare function oneToMany(relatedClass: string | Function | any, options
342
342
  *
343
343
  * @see {@link oneToMany} for one-to-many relationships
344
344
  */
345
- export declare function manyToMany(relatedClass: string | Function | any, options?: Omit<RelationshipFieldOptions, 'related'>): CompatiblePropertyDecorator;
345
+ export declare function manyToMany(relatedClass: string | Function, options?: Omit<RelationshipFieldOptions, 'related'>): CompatiblePropertyDecorator;
346
346
  /**
347
347
  * Marks a field as a Single Table Inheritance (STI) meta field.
348
348
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/decorators/index.ts"],"sourcesContent":["/**\n * Field decorators for SMRT objects\n *\n * Modern decorator-based API for defining SMRT object properties.\n * Properties are typed as primitives with decorator metadata.\n */\n\nimport { ObjectRegistry } from '../registry.js';\nimport type { SQLDataType } from '../schema/types.js';\nimport {\n type CompatiblePropertyDecorator,\n type CompatiblePropertyDecoratorContext,\n type LegacyPropertyDecoratorTarget,\n registerCompatibleFieldDecorator,\n} from './compatibility.js';\n\n/**\n * Meta type wrapper for STI (Single Table Inheritance) meta fields\n *\n * Fields typed as Meta<T> are stored in the _meta_data JSONB column\n * rather than as direct table columns. Used for child-specific fields\n * in STI hierarchies.\n *\n * @example\n * ```typescript\n * @smrt({ tableStrategy: 'sti' })\n * class Event extends SmrtObject {\n * title: string = '';\n * }\n *\n * @smrt()\n * class Meeting extends Event {\n * // Stored in _meta_data JSONB column\n * roomNumber: Meta<string> = '';\n * attendees: Meta<string[]> = [];\n * }\n * ```\n */\nexport type Meta<T> = T;\n\n/**\n * Base field options\n */\nexport type PrimitiveFieldType =\n | 'text'\n | 'integer'\n | 'decimal'\n | 'boolean'\n | 'datetime'\n | 'json';\n\nexport type FieldType =\n | PrimitiveFieldType\n | 'meta'\n | 'foreignKey'\n | 'crossPackageRef'\n | 'oneToMany'\n | 'manyToMany';\n\nexport interface FieldOptions {\n /** Explicit field type for runtime-only registration paths */\n type?: FieldType;\n /** Explicit SQL storage type when runtime and persistence contracts differ */\n sqlType?: SQLDataType;\n /** Whether the field is required */\n required?: boolean;\n /** Default value for the field */\n default?: any;\n /** Whether the field is unique */\n unique?: boolean;\n /**\n * When `true`, the schema emits a database index targeting this field.\n *\n * For regular (column-backed) fields the index is a plain column index.\n * For `@meta()` fields stored inside `_meta_data` JSONB, the index targets\n * the JSON path — `json_extract(_meta_data, '$.fieldName')` on SQLite,\n * `(_meta_data->>'fieldName')` on Postgres — giving WHERE clauses on that\n * meta key the same performance as a real column.\n */\n indexed?: boolean;\n /** Whether the field is nullable */\n nullable?: boolean;\n /** Whether the field should be excluded from database */\n transient?: boolean;\n /**\n * Marks the field as sensitive (e.g. API secrets, credentials, tax IDs).\n *\n * Sensitive fields are still persisted to the database, but the framework:\n * - excludes them from `toPublicJSON()` (the serializer used by generated\n * REST/MCP/SvelteKit routes), so they never appear in API responses; and\n * - rejects them as `where`-clause filter keys, closing the\n * `?secret[like]=...` value-probing oracle.\n *\n * Use this for any column that holds a secret value that must never be\n * read back over a generated network surface.\n */\n sensitive?: boolean;\n /**\n * Marks the field as read-only over generated write surfaces.\n *\n * Read-only fields are stripped from the request body before\n * `create`/`update` in generated REST/MCP/SvelteKit routes, so callers\n * cannot mass-assign them. Server-side code can still set them directly.\n */\n readonly?: boolean;\n /** Field description */\n description?: string;\n /**\n * Controls whether the field is included in JSON exports.\n * - `true`: Always exported (unless site explicitly excludes it)\n * - `false`: Never exported (cannot be overridden by site config)\n * - `undefined`: Uses site's fieldExportDefault setting\n */\n exported?: boolean;\n}\n\n/**\n * Options for text fields\n */\nexport interface TextFieldOptions extends FieldOptions {\n /** Minimum length for text fields */\n minLength?: number;\n /** Maximum length for text fields */\n maxLength?: number;\n /** Regex pattern for validation */\n pattern?: RegExp | string;\n}\n\n/**\n * Options for numeric fields\n */\nexport interface NumericFieldOptions extends FieldOptions {\n /** Minimum value */\n min?: number;\n /** Maximum value */\n max?: number;\n}\n\n/**\n * Options for relationship fields\n */\nexport interface RelationshipFieldOptions extends FieldOptions {\n /** Related class name */\n related?: string;\n /** Foreign key field name */\n foreignKey?: string;\n /** Through table for many-to-many */\n through?: string;\n /** Relationship type */\n type?: 'foreignKey' | 'crossPackageRef' | 'oneToMany' | 'manyToMany';\n}\n\n/**\n * Options specific to cross-package references.\n */\nexport interface CrossPackageRefOptions\n extends Omit<RelationshipFieldOptions, 'related' | 'type'> {\n /**\n * Storage type for the referenced target id. Defaults to 'uuid'.\n *\n * Use 'text' only when the external target model declares\n * `@smrt({ idType: 'text' })`.\n */\n idType?: 'uuid' | 'text';\n\n /**\n * When `true`, the framework verifies the referenced object exists at save time.\n * Validation uses the target package's manifest (loaded on demand via\n * `ObjectRegistry.ensureManifestLoaded()`), so this requires the target manifest\n * to be discoverable at runtime.\n *\n * Empty/null values are always allowed (treated as \"no reference set\").\n *\n * Defaults to `false` — same behavior as a plain string field today.\n */\n validate?: boolean;\n}\n\n/**\n * Marks a class property with validation constraints and metadata options.\n *\n * Use `@field()` when you need options beyond what plain TypeScript initializers\n * express — required validation, numeric ranges, string length limits, uniqueness,\n * or transient (non-persisted) computed properties.\n *\n * For plain persisted fields with no constraints, no decorator is needed: just\n * declare the property with a TypeScript initializer and the framework will infer\n * the column type from the default value (`0` → INTEGER, `0.0` → DECIMAL, `''` → TEXT).\n *\n * @param options - Field configuration options\n * @param options.required - If `true`, `save()` throws `ValidationError` when empty/null\n * @param options.unique - Enforces a UNIQUE database constraint\n * @param options.nullable - If `true`, the column accepts NULL (default depends on type)\n * @param options.transient - If `true`, the property is not persisted to the database\n * @param options.default - Default value applied at the database level\n * @param options.description - Human-readable description used in generated API docs\n * @param options.exported - Controls JSON export visibility (see `FieldOptions`)\n * @returns A TypeScript property decorator\n *\n * @example\n * ```typescript\n * @smrt()\n * class Product extends SmrtObject {\n * @field({ required: true, maxLength: 100 })\n * name: string = '';\n *\n * @field({ min: 0 })\n * stock: number = 0;\n *\n * @field({ transient: true })\n * get displayPrice(): string { return `$${this.price.toFixed(2)}`; }\n * }\n * ```\n *\n * @see {@link meta} for STI child-specific fields stored in `_meta_data` JSON\n * @see {@link foreignKey} for typed relationship fields\n */\nexport function field(\n options: FieldOptions | NumericFieldOptions | TextFieldOptions = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<any, any>,\n ) => {\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, options);\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a many-to-one (foreign key) relationship to another `SmrtObject` class.\n *\n * The decorated property stores the UUID of the related object. At runtime, call\n * `instance.loadRelated('fieldName')` to lazy-load (and cache) the related object,\n * or pass `include: ['fieldName']` to `collection.list()` for batch eager loading.\n *\n * Cross-package rule: Use `@foreignKey()` only for same-package references.\n * For cross-package foreign keys, use a plain `string` property instead to avoid\n * circular dependencies between packages.\n *\n * @param relatedClass - The target class constructor (or class name string)\n * @param options - Optional field constraints (required, nullable, etc.)\n * @returns A TypeScript property decorator\n *\n * @example\n * ```typescript\n * @smrt()\n * class Order extends SmrtObject {\n * // Same-package FK — enables loadRelated() and eager loading\n * @foreignKey(Customer)\n * customerId: string = '';\n * }\n *\n * // Cross-package: use a plain string instead\n * @smrt()\n * class Post extends SmrtObject {\n * authorId: string = ''; // plain string — no circular dep\n * }\n * ```\n *\n * @see {@link oneToMany} for the inverse (parent) side of the relationship\n * @see SmrtObject.loadRelated for lazy-loading the related object at runtime\n */\nexport function foreignKey(\n relatedClass: string | Function | any,\n options: Omit<RelationshipFieldOptions, 'related'> = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<any, any>,\n ) => {\n const relatedClassName =\n typeof relatedClass === 'string' ? relatedClass : relatedClass.name;\n\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'foreignKey',\n related: relatedClassName,\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a cross-package foreign key reference.\n *\n * Use this for relationships that point to a `SmrtObject` in a *different* package\n * (e.g. `Customer.profileId` pointing at `@happyvertical/smrt-profiles:Profile`).\n * Unlike `@foreignKey()`, this decorator does **not** emit a DDL `FOREIGN KEY`\n * constraint — cross-package classes are not visible at schema-generation time and\n * adding a constraint would force a circular package dependency. The decorated\n * property remains a plain `TEXT` column at the database level.\n *\n * What you get over a plain string field:\n * - The relationship is registered with the `ObjectRegistry`, so `loadRelated()`\n * and `Collection.list({ include })` can resolve it once the target package's\n * manifest is loaded.\n * - Optional save-time validation (`validate: true`) confirms the referenced\n * object exists, catching typos and stale IDs before they hit the database.\n *\n * The `qualifiedName` is a fully-qualified class identifier in the form\n * `@package/scope:ClassName` — for example `@happyvertical/smrt-profiles:Profile`.\n *\n * @param qualifiedName - Qualified name of the target class\n * @param options - Optional field constraints and `validate` flag\n * @returns A TypeScript property decorator\n *\n * @example\n * ```typescript\n * @smrt()\n * class Customer extends SmrtObject {\n * @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n * profileId: string = '';\n *\n * // With save-time validation\n * @crossPackageRef('@happyvertical/smrt-profiles:Profile', { validate: true })\n * primaryContactId: string = '';\n * }\n * ```\n *\n * @see {@link foreignKey} for same-package relationships (emits FK constraint)\n * @see SmrtObject.loadRelated for runtime resolution\n */\nexport function crossPackageRef(\n qualifiedName: string,\n options: CrossPackageRefOptions = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<any, any>,\n ) => {\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'crossPackageRef',\n related: qualifiedName,\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a one-to-many relationship from this object to a collection of related objects.\n *\n * The decorated property is `transient` — it is not persisted as a database column.\n * At runtime, call `instance.loadRelatedMany('fieldName')` to load the related objects,\n * or pass `include: ['fieldName']` to `collection.list()` for batch eager loading (issues\n * a single batched query for all instances instead of N individual queries).\n *\n * The inverse side (`@foreignKey`) must exist on the `relatedClass` pointing back to this\n * class. The framework discovers it automatically via `ObjectRegistry.getInverseRelationships()`.\n *\n * **Generated accessor (R10):** registering the class installs a consistent\n * `get<FieldName>()` instance method (e.g. `items` → `order.getItems()`) that\n * delegates to `loadRelatedMany('items')`. Generation is additive — a\n * hand-rolled method of the same name is never overwritten.\n *\n * **Disambiguation:** when `relatedClass` declares more than one `@foreignKey`\n * back to this class, pass `{ foreignKey: '<inverseFieldName>' }` so both\n * `loadRelatedMany` and the generated accessor resolve the intended inverse\n * side. Without it the first matching foreign key is used.\n *\n * @param relatedClass - The class constructor of the child/related objects\n * @param options - Optional relationship options. `foreignKey` selects the\n * inverse foreign-key field on `relatedClass` when it has more than one.\n * @returns A TypeScript property decorator (sets `transient: true` automatically)\n *\n * @example\n * ```typescript\n * @smrt()\n * class Order extends SmrtObject {\n * @oneToMany(OrderItem)\n * items: OrderItem[] = [];\n * }\n *\n * @smrt()\n * class OrderItem extends SmrtObject {\n * @foreignKey(Order)\n * orderId: string = '';\n * }\n *\n * const order = await orders.get({ id });\n * const items = await order.getItems(); // generated; === loadRelatedMany('items')\n * ```\n *\n * @example\n * ```typescript\n * // Multiple inverse foreign keys → disambiguate explicitly.\n * @smrt()\n * class Profile extends SmrtObject {\n * @oneToMany(ProfileRelationship, { foreignKey: 'fromProfileId' })\n * relationshipsFrom: ProfileRelationship[] = [];\n * @oneToMany(ProfileRelationship, { foreignKey: 'toProfileId' })\n * relationshipsTo: ProfileRelationship[] = [];\n * }\n * ```\n *\n * @see {@link foreignKey} for the many-to-one (child) side of the relationship\n * @see SmrtObject.loadRelatedMany for lazy-loading at runtime\n */\nexport function oneToMany(\n relatedClass: string | Function | any,\n options: Omit<RelationshipFieldOptions, 'related'> = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<any, any>,\n ) => {\n const relatedClassName =\n typeof relatedClass === 'string' ? relatedClass : relatedClass.name;\n\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'oneToMany',\n related: relatedClassName,\n transient: true, // Relationship fields are not database columns\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a many-to-many relationship between two `SmrtObject` classes via a join table.\n *\n * The decorated property is `transient` — it is not persisted as a database column.\n * The `through` option specifies the junction table name. The join table model must\n * be decorated with `@smrt({ conflictColumns: ['...', '...'] })` to use the natural\n * key columns for upsert operations.\n *\n * Runtime loading: call `instance.loadRelatedMany('field')` to lazy-load, or\n * pass `include: ['field']` to `collection.list()` for batched eager loading.\n *\n * @param relatedClass - The class constructor of the related objects\n * @param options - Relationship options; `through` specifies the junction table name\n * @returns A TypeScript property decorator (sets `transient: true` automatically)\n *\n * @example\n * ```typescript\n * @smrt()\n * class Product extends SmrtObject {\n * @manyToMany(Tag, { through: 'product_tags' })\n * tags: Tag[] = [];\n * }\n * ```\n *\n * @see {@link oneToMany} for one-to-many relationships\n */\nexport function manyToMany(\n relatedClass: string | Function | any,\n options: Omit<RelationshipFieldOptions, 'related'> = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<any, any>,\n ) => {\n const relatedClassName =\n typeof relatedClass === 'string' ? relatedClass : relatedClass.name;\n\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'manyToMany',\n related: relatedClassName,\n transient: true, // Relationship fields are not database columns\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Marks a field as a Single Table Inheritance (STI) meta field.\n *\n * Meta fields are stored in the `_meta_data` JSONB column on the shared STI\n * table rather than as dedicated table columns. Use this decorator for fields\n * that are specific to an STI child class and should not pollute the shared\n * table schema with child-specific columns.\n *\n * The `@smrt({ tableStrategy: 'sti' })` decorator must be set on the base class.\n * All child-specific fields should use `@meta()` (or the `Meta<T>` type alias).\n *\n * @param options - Standard field options (required, nullable, description, etc.)\n * @returns A TypeScript property decorator (registers field with `type: 'meta'`)\n *\n * @example\n * ```typescript\n * @smrt({ tableStrategy: 'sti' })\n * class Event extends SmrtObject {\n * title: string = ''; // shared column on events table\n * }\n *\n * @smrt()\n * class Meeting extends Event {\n * @meta()\n * roomNumber: string = ''; // stored in _meta_data JSON, not a column\n *\n * @meta({ required: true })\n * durationMinutes: number = 60;\n * }\n * ```\n *\n * @see {@link Meta} for the equivalent type alias approach\n * @see {@link field} for regular (non-STI) field declarations\n */\nexport function meta(options: FieldOptions = {}) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<any, any>,\n ) => {\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'meta', // Mark this field as a meta field for STI\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n"],"names":[],"mappings":";;AAyNO,SAAS,MACd,UAAiE,IACjE;AACA,UAAQ,CACN,eACA,yBACG;AACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa,OAAO;AAAA,MACvE;AAAA,IAAA;AAAA,EAEJ;AACF;AAoCO,SAAS,WACd,cACA,UAAqD,IACrD;AACA,UAAQ,CACN,eACA,yBACG;AACH,UAAM,mBACJ,OAAO,iBAAiB,WAAW,eAAe,aAAa;AAEjE;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AA0CO,SAAS,gBACd,eACA,UAAkC,IAClC;AACA,UAAQ,CACN,eACA,yBACG;AACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AA6DO,SAAS,UACd,cACA,UAAqD,IACrD;AACA,UAAQ,CACN,eACA,yBACG;AACH,UAAM,mBACJ,OAAO,iBAAiB,WAAW,eAAe,aAAa;AAEjE;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA;AAAA,QAAA,CACZ;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AA4BO,SAAS,WACd,cACA,UAAqD,IACrD;AACA,UAAQ,CACN,eACA,yBACG;AACH,UAAM,mBACJ,OAAO,iBAAiB,WAAW,eAAe,aAAa;AAEjE;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA;AAAA,QAAA,CACZ;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AAoCO,SAAS,KAAK,UAAwB,IAAI;AAC/C,UAAQ,CACN,eACA,yBACG;AACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA;AAAA,QAAA,CACP;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/decorators/index.ts"],"sourcesContent":["/**\n * Field decorators for SMRT objects\n *\n * Modern decorator-based API for defining SMRT object properties.\n * Properties are typed as primitives with decorator metadata.\n */\n\nimport { ObjectRegistry } from '../registry.js';\nimport type { SQLDataType } from '../schema/types.js';\nimport {\n type CompatiblePropertyDecorator,\n type CompatiblePropertyDecoratorContext,\n type LegacyPropertyDecoratorTarget,\n registerCompatibleFieldDecorator,\n} from './compatibility.js';\n\n/**\n * Meta type wrapper for STI (Single Table Inheritance) meta fields\n *\n * Fields typed as Meta<T> are stored in the _meta_data JSONB column\n * rather than as direct table columns. Used for child-specific fields\n * in STI hierarchies.\n *\n * @example\n * ```typescript\n * @smrt({ tableStrategy: 'sti' })\n * class Event extends SmrtObject {\n * title: string = '';\n * }\n *\n * @smrt()\n * class Meeting extends Event {\n * // Stored in _meta_data JSONB column\n * roomNumber: Meta<string> = '';\n * attendees: Meta<string[]> = [];\n * }\n * ```\n */\nexport type Meta<T> = T;\n\n/**\n * Base field options\n */\nexport type PrimitiveFieldType =\n | 'text'\n | 'integer'\n | 'decimal'\n | 'boolean'\n | 'datetime'\n | 'json';\n\nexport type FieldType =\n | PrimitiveFieldType\n | 'meta'\n | 'foreignKey'\n | 'crossPackageRef'\n | 'oneToMany'\n | 'manyToMany';\n\nexport interface FieldOptions {\n /** Explicit field type for runtime-only registration paths */\n type?: FieldType;\n /** Explicit SQL storage type when runtime and persistence contracts differ */\n sqlType?: SQLDataType;\n /** Whether the field is required */\n required?: boolean;\n /** Default value for the field */\n default?: unknown;\n /** Whether the field is unique */\n unique?: boolean;\n /**\n * When `true`, the schema emits a database index targeting this field.\n *\n * For regular (column-backed) fields the index is a plain column index.\n * For `@meta()` fields stored inside `_meta_data` JSONB, the index targets\n * the JSON path — `json_extract(_meta_data, '$.fieldName')` on SQLite,\n * `(_meta_data->>'fieldName')` on Postgres — giving WHERE clauses on that\n * meta key the same performance as a real column.\n */\n indexed?: boolean;\n /** Whether the field is nullable */\n nullable?: boolean;\n /** Whether the field should be excluded from database */\n transient?: boolean;\n /**\n * Marks the field as sensitive (e.g. API secrets, credentials, tax IDs).\n *\n * Sensitive fields are still persisted to the database, but the framework:\n * - excludes them from `toPublicJSON()` (the serializer used by generated\n * REST/MCP/SvelteKit routes), so they never appear in API responses; and\n * - rejects them as `where`-clause filter keys, closing the\n * `?secret[like]=...` value-probing oracle.\n *\n * Use this for any column that holds a secret value that must never be\n * read back over a generated network surface.\n */\n sensitive?: boolean;\n /**\n * Marks the field as read-only over generated write surfaces.\n *\n * Read-only fields are stripped from the request body before\n * `create`/`update` in generated REST/MCP/SvelteKit routes, so callers\n * cannot mass-assign them. Server-side code can still set them directly.\n */\n readonly?: boolean;\n /** Field description */\n description?: string;\n /**\n * Controls whether the field is included in JSON exports.\n * - `true`: Always exported (unless site explicitly excludes it)\n * - `false`: Never exported (cannot be overridden by site config)\n * - `undefined`: Uses site's fieldExportDefault setting\n */\n exported?: boolean;\n}\n\n/**\n * Options for text fields\n */\nexport interface TextFieldOptions extends FieldOptions {\n /** Minimum length for text fields */\n minLength?: number;\n /** Maximum length for text fields */\n maxLength?: number;\n /** Regex pattern for validation */\n pattern?: RegExp | string;\n}\n\n/**\n * Options for numeric fields\n */\nexport interface NumericFieldOptions extends FieldOptions {\n /** Minimum value */\n min?: number;\n /** Maximum value */\n max?: number;\n}\n\n/**\n * Options for relationship fields\n */\nexport interface RelationshipFieldOptions extends FieldOptions {\n /** Related class name */\n related?: string;\n /** Foreign key field name */\n foreignKey?: string;\n /** Through table for many-to-many */\n through?: string;\n /** Relationship type */\n type?: 'foreignKey' | 'crossPackageRef' | 'oneToMany' | 'manyToMany';\n}\n\n/**\n * Options specific to cross-package references.\n */\nexport interface CrossPackageRefOptions\n extends Omit<RelationshipFieldOptions, 'related' | 'type'> {\n /**\n * Storage type for the referenced target id. Defaults to 'uuid'.\n *\n * Use 'text' only when the external target model declares\n * `@smrt({ idType: 'text' })`.\n */\n idType?: 'uuid' | 'text';\n\n /**\n * When `true`, the framework verifies the referenced object exists at save time.\n * Validation uses the target package's manifest (loaded on demand via\n * `ObjectRegistry.ensureManifestLoaded()`), so this requires the target manifest\n * to be discoverable at runtime.\n *\n * Empty/null values are always allowed (treated as \"no reference set\").\n *\n * Defaults to `false` — same behavior as a plain string field today.\n */\n validate?: boolean;\n}\n\n/**\n * Marks a class property with validation constraints and metadata options.\n *\n * Use `@field()` when you need options beyond what plain TypeScript initializers\n * express — required validation, numeric ranges, string length limits, uniqueness,\n * or transient (non-persisted) computed properties.\n *\n * For plain persisted fields with no constraints, no decorator is needed: just\n * declare the property with a TypeScript initializer and the framework will infer\n * the column type from the default value (`0` → INTEGER, `0.0` → DECIMAL, `''` → TEXT).\n *\n * @param options - Field configuration options\n * @param options.required - If `true`, `save()` throws `ValidationError` when empty/null\n * @param options.unique - Enforces a UNIQUE database constraint\n * @param options.nullable - If `true`, the column accepts NULL (default depends on type)\n * @param options.transient - If `true`, the property is not persisted to the database\n * @param options.default - Default value applied at the database level\n * @param options.description - Human-readable description used in generated API docs\n * @param options.exported - Controls JSON export visibility (see `FieldOptions`)\n * @returns A TypeScript property decorator\n *\n * @example\n * ```typescript\n * @smrt()\n * class Product extends SmrtObject {\n * @field({ required: true, maxLength: 100 })\n * name: string = '';\n *\n * @field({ min: 0 })\n * stock: number = 0;\n *\n * @field({ transient: true })\n * get displayPrice(): string { return `$${this.price.toFixed(2)}`; }\n * }\n * ```\n *\n * @see {@link meta} for STI child-specific fields stored in `_meta_data` JSON\n * @see {@link foreignKey} for typed relationship fields\n */\nexport function field(\n options: FieldOptions | NumericFieldOptions | TextFieldOptions = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<unknown, unknown>,\n ) => {\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, options);\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a many-to-one (foreign key) relationship to another `SmrtObject` class.\n *\n * The decorated property stores the UUID of the related object. At runtime, call\n * `instance.loadRelated('fieldName')` to lazy-load (and cache) the related object,\n * or pass `include: ['fieldName']` to `collection.list()` for batch eager loading.\n *\n * Cross-package rule: Use `@foreignKey()` only for same-package references.\n * For cross-package foreign keys, use a plain `string` property instead to avoid\n * circular dependencies between packages.\n *\n * @param relatedClass - The target class constructor (or class name string)\n * @param options - Optional field constraints (required, nullable, etc.)\n * @returns A TypeScript property decorator\n *\n * @example\n * ```typescript\n * @smrt()\n * class Order extends SmrtObject {\n * // Same-package FK — enables loadRelated() and eager loading\n * @foreignKey(Customer)\n * customerId: string = '';\n * }\n *\n * // Cross-package: use a plain string instead\n * @smrt()\n * class Post extends SmrtObject {\n * authorId: string = ''; // plain string — no circular dep\n * }\n * ```\n *\n * @see {@link oneToMany} for the inverse (parent) side of the relationship\n * @see SmrtObject.loadRelated for lazy-loading the related object at runtime\n */\nexport function foreignKey(\n relatedClass: string | Function,\n options: Omit<RelationshipFieldOptions, 'related'> = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<unknown, unknown>,\n ) => {\n const relatedClassName =\n typeof relatedClass === 'string' ? relatedClass : relatedClass.name;\n\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'foreignKey',\n related: relatedClassName,\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a cross-package foreign key reference.\n *\n * Use this for relationships that point to a `SmrtObject` in a *different* package\n * (e.g. `Customer.profileId` pointing at `@happyvertical/smrt-profiles:Profile`).\n * Unlike `@foreignKey()`, this decorator does **not** emit a DDL `FOREIGN KEY`\n * constraint — cross-package classes are not visible at schema-generation time and\n * adding a constraint would force a circular package dependency. The decorated\n * property remains a plain `TEXT` column at the database level.\n *\n * What you get over a plain string field:\n * - The relationship is registered with the `ObjectRegistry`, so `loadRelated()`\n * and `Collection.list({ include })` can resolve it once the target package's\n * manifest is loaded.\n * - Optional save-time validation (`validate: true`) confirms the referenced\n * object exists, catching typos and stale IDs before they hit the database.\n *\n * The `qualifiedName` is a fully-qualified class identifier in the form\n * `@package/scope:ClassName` — for example `@happyvertical/smrt-profiles:Profile`.\n *\n * @param qualifiedName - Qualified name of the target class\n * @param options - Optional field constraints and `validate` flag\n * @returns A TypeScript property decorator\n *\n * @example\n * ```typescript\n * @smrt()\n * class Customer extends SmrtObject {\n * @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n * profileId: string = '';\n *\n * // With save-time validation\n * @crossPackageRef('@happyvertical/smrt-profiles:Profile', { validate: true })\n * primaryContactId: string = '';\n * }\n * ```\n *\n * @see {@link foreignKey} for same-package relationships (emits FK constraint)\n * @see SmrtObject.loadRelated for runtime resolution\n */\nexport function crossPackageRef(\n qualifiedName: string,\n options: CrossPackageRefOptions = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<unknown, unknown>,\n ) => {\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'crossPackageRef',\n related: qualifiedName,\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a one-to-many relationship from this object to a collection of related objects.\n *\n * The decorated property is `transient` — it is not persisted as a database column.\n * At runtime, call `instance.loadRelatedMany('fieldName')` to load the related objects,\n * or pass `include: ['fieldName']` to `collection.list()` for batch eager loading (issues\n * a single batched query for all instances instead of N individual queries).\n *\n * The inverse side (`@foreignKey`) must exist on the `relatedClass` pointing back to this\n * class. The framework discovers it automatically via `ObjectRegistry.getInverseRelationships()`.\n *\n * **Generated accessor (R10):** registering the class installs a consistent\n * `get<FieldName>()` instance method (e.g. `items` → `order.getItems()`) that\n * delegates to `loadRelatedMany('items')`. Generation is additive — a\n * hand-rolled method of the same name is never overwritten.\n *\n * **Disambiguation:** when `relatedClass` declares more than one `@foreignKey`\n * back to this class, pass `{ foreignKey: '<inverseFieldName>' }` so both\n * `loadRelatedMany` and the generated accessor resolve the intended inverse\n * side. Without it the first matching foreign key is used.\n *\n * @param relatedClass - The class constructor of the child/related objects\n * @param options - Optional relationship options. `foreignKey` selects the\n * inverse foreign-key field on `relatedClass` when it has more than one.\n * @returns A TypeScript property decorator (sets `transient: true` automatically)\n *\n * @example\n * ```typescript\n * @smrt()\n * class Order extends SmrtObject {\n * @oneToMany(OrderItem)\n * items: OrderItem[] = [];\n * }\n *\n * @smrt()\n * class OrderItem extends SmrtObject {\n * @foreignKey(Order)\n * orderId: string = '';\n * }\n *\n * const order = await orders.get({ id });\n * const items = await order.getItems(); // generated; === loadRelatedMany('items')\n * ```\n *\n * @example\n * ```typescript\n * // Multiple inverse foreign keys → disambiguate explicitly.\n * @smrt()\n * class Profile extends SmrtObject {\n * @oneToMany(ProfileRelationship, { foreignKey: 'fromProfileId' })\n * relationshipsFrom: ProfileRelationship[] = [];\n * @oneToMany(ProfileRelationship, { foreignKey: 'toProfileId' })\n * relationshipsTo: ProfileRelationship[] = [];\n * }\n * ```\n *\n * @see {@link foreignKey} for the many-to-one (child) side of the relationship\n * @see SmrtObject.loadRelatedMany for lazy-loading at runtime\n */\nexport function oneToMany(\n relatedClass: string | Function,\n options: Omit<RelationshipFieldOptions, 'related'> = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<unknown, unknown>,\n ) => {\n const relatedClassName =\n typeof relatedClass === 'string' ? relatedClass : relatedClass.name;\n\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'oneToMany',\n related: relatedClassName,\n transient: true, // Relationship fields are not database columns\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Declares a many-to-many relationship between two `SmrtObject` classes via a join table.\n *\n * The decorated property is `transient` — it is not persisted as a database column.\n * The `through` option specifies the junction table name. The join table model must\n * be decorated with `@smrt({ conflictColumns: ['...', '...'] })` to use the natural\n * key columns for upsert operations.\n *\n * Runtime loading: call `instance.loadRelatedMany('field')` to lazy-load, or\n * pass `include: ['field']` to `collection.list()` for batched eager loading.\n *\n * @param relatedClass - The class constructor of the related objects\n * @param options - Relationship options; `through` specifies the junction table name\n * @returns A TypeScript property decorator (sets `transient: true` automatically)\n *\n * @example\n * ```typescript\n * @smrt()\n * class Product extends SmrtObject {\n * @manyToMany(Tag, { through: 'product_tags' })\n * tags: Tag[] = [];\n * }\n * ```\n *\n * @see {@link oneToMany} for one-to-many relationships\n */\nexport function manyToMany(\n relatedClass: string | Function,\n options: Omit<RelationshipFieldOptions, 'related'> = {},\n) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<unknown, unknown>,\n ) => {\n const relatedClassName =\n typeof relatedClass === 'string' ? relatedClass : relatedClass.name;\n\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'manyToMany',\n related: relatedClassName,\n transient: true, // Relationship fields are not database columns\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n\n/**\n * Marks a field as a Single Table Inheritance (STI) meta field.\n *\n * Meta fields are stored in the `_meta_data` JSONB column on the shared STI\n * table rather than as dedicated table columns. Use this decorator for fields\n * that are specific to an STI child class and should not pollute the shared\n * table schema with child-specific columns.\n *\n * The `@smrt({ tableStrategy: 'sti' })` decorator must be set on the base class.\n * All child-specific fields should use `@meta()` (or the `Meta<T>` type alias).\n *\n * @param options - Standard field options (required, nullable, description, etc.)\n * @returns A TypeScript property decorator (registers field with `type: 'meta'`)\n *\n * @example\n * ```typescript\n * @smrt({ tableStrategy: 'sti' })\n * class Event extends SmrtObject {\n * title: string = ''; // shared column on events table\n * }\n *\n * @smrt()\n * class Meeting extends Event {\n * @meta()\n * roomNumber: string = ''; // stored in _meta_data JSON, not a column\n *\n * @meta({ required: true })\n * durationMinutes: number = 60;\n * }\n * ```\n *\n * @see {@link Meta} for the equivalent type alias approach\n * @see {@link field} for regular (non-STI) field declarations\n */\nexport function meta(options: FieldOptions = {}) {\n return ((\n targetOrValue: LegacyPropertyDecoratorTarget | undefined,\n propertyKeyOrContext: CompatiblePropertyDecoratorContext<unknown, unknown>,\n ) => {\n registerCompatibleFieldDecorator(\n targetOrValue,\n propertyKeyOrContext,\n (className, propertyKey) => {\n ObjectRegistry.registerFieldDecorator(className, propertyKey, {\n ...options,\n type: 'meta', // Mark this field as a meta field for STI\n });\n },\n );\n }) as CompatiblePropertyDecorator;\n}\n"],"names":[],"mappings":";;AAyNO,SAAS,MACd,UAAiE,IACjE;AACA,UAAQ,CACN,eACA,yBACG;AACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa,OAAO;AAAA,MACvE;AAAA,IAAA;AAAA,EAEJ;AACF;AAoCO,SAAS,WACd,cACA,UAAqD,IACrD;AACA,UAAQ,CACN,eACA,yBACG;AACH,UAAM,mBACJ,OAAO,iBAAiB,WAAW,eAAe,aAAa;AAEjE;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AA0CO,SAAS,gBACd,eACA,UAAkC,IAClC;AACA,UAAQ,CACN,eACA,yBACG;AACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AA6DO,SAAS,UACd,cACA,UAAqD,IACrD;AACA,UAAQ,CACN,eACA,yBACG;AACH,UAAM,mBACJ,OAAO,iBAAiB,WAAW,eAAe,aAAa;AAEjE;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA;AAAA,QAAA,CACZ;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AA4BO,SAAS,WACd,cACA,UAAqD,IACrD;AACA,UAAQ,CACN,eACA,yBACG;AACH,UAAM,mBACJ,OAAO,iBAAiB,WAAW,eAAe,aAAa;AAEjE;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA;AAAA,QAAA,CACZ;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;AAoCO,SAAS,KAAK,UAAwB,IAAI;AAC/C,UAAQ,CACN,eACA,yBACG;AACH;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,WAAW,gBAAgB;AAC1B,uBAAe,uBAAuB,WAAW,aAAa;AAAA,UAC5D,GAAG;AAAA,UACH,MAAM;AAAA;AAAA,QAAA,CACP;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"hierarchical.d.ts","sourceRoot":"","sources":["../src/hierarchical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,gBAAgB;IACvD,SAAS,EAAE,CAAC,EAAE,CAAC;IACf,OAAO,EAAE,CAAC,CAAC;IACX,WAAW,EAAE,CAAC,EAAE,CAAC;CAClB;AAED,qBAAa,gBAAiB,SAAQ,UAAU;IAC9C;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAG,IAAI,CAAU;IAEpD,mEAAmE;IACnE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;cACa,oBAAoB,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAgCrE;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAOvC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IASpC;;;;;;;OAOG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAmBrC;;;;;;;;;;;;;;OAcG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAgCvC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAQlD;;;;;;;;;OASG;IACG,MAAM,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CA0B7D"}
1
+ {"version":3,"file":"hierarchical.d.ts","sourceRoot":"","sources":["../src/hierarchical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKtC;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,gBAAgB;IACvD,SAAS,EAAE,CAAC,EAAE,CAAC;IACf,OAAO,EAAE,CAAC,CAAC;IACX,WAAW,EAAE,CAAC,EAAE,CAAC;CAClB;AAED,qBAAa,gBAAiB,SAAQ,UAAU;IAC9C;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAG,IAAI,CAAU;IAEpD,mEAAmE;IACnE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;cACa,oBAAoB,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAgCrE;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAOvC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IASpC;;;;;;;OAOG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAmBrC;;;;;;;;;;;;;;OAcG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAgCvC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAQlD;;;;;;;;;OASG;IACG,MAAM,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CA0B7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"hierarchical.js","sources":["../src/hierarchical.ts"],"sourcesContent":["/**\n * SmrtHierarchical — base class for self-referencing tree hierarchies.\n *\n * Provides batched parent/children/ancestors/descendants/hierarchy traversal\n * and a cycle-safe `moveTo`. Replaces five copies of the same logic across\n * Place, Event, Tag, Account, and Zone.\n *\n * Examples in the monorepo:\n *\n * | Subclass | Domain |\n * |----------|------------------------------------------------|\n * | Place | hierarchical geographic places |\n * | Event | nestable event hierarchy (game → period → …) |\n * | Tag | tag taxonomies and category trees |\n * | Account | chart of accounts |\n * | Zone | placement zones inside a digital property |\n *\n * Convention: every subclass uses `parentId: string | null` referencing\n * another row in the same table (or STI base table) by UUID. Classes whose\n * self-reference has different semantics — e.g. `Fact.previousFactId` (an\n * evolution chain) or `Asset.sourceAssetId` (a derivation DAG) — should\n * NOT extend SmrtHierarchical. Use descriptive names and class-specific\n * methods instead.\n *\n * @example\n * ```typescript\n * @smrt({ tableStrategy: 'sti', api: true })\n * export class Place extends SmrtHierarchical {\n * name = '';\n * }\n *\n * const ancestors = await place.getAncestors();\n * const descendants = await place.getDescendants(); // BFS, one query per level\n * await place.moveTo(newParent); // cycle-checked\n * ```\n */\n\nimport type { SmrtCollection } from './collection';\nimport { SmrtObject } from './object';\nimport { ObjectRegistry } from './registry';\nimport { chunkArray, IN_LIST_CHUNK_SIZE } from './utils/chunk';\n\n/**\n * Aggregate hierarchy view: ancestors (root-first), self, and all descendants\n * (BFS order). Generic on the concrete subclass so `getHierarchy()` preserves\n * the caller's type — `place.getHierarchy()` yields `HierarchyView<Place>`.\n */\nexport interface HierarchyView<T extends SmrtHierarchical> {\n ancestors: T[];\n current: T;\n descendants: T[];\n}\n\nexport class SmrtHierarchical extends SmrtObject {\n /**\n * Internal marker so the scanner can recognize this framework abstract base\n * even when consumers haven't built its package. Mirrors\n * `SmrtJunction._isJunctionBase`. Don't rename without also updating the\n * scanner's `FRAMEWORK_BASE_CLASSES` set in\n * `packages/scanner/src/inheritance-resolver.ts`.\n */\n static readonly _isHierarchicalBase = true as const;\n\n /** Self-referencing parent. `null` means top-level (no parent). */\n parentId: string | null = null;\n\n /**\n * Resolve the collection used to load siblings/ancestors/descendants.\n *\n * Goes through `ObjectRegistry.getCollection` so subclasses don't have to\n * hard-code a dynamic import of their own collection module. Also acts as\n * the abstract-base guard — `new SmrtHierarchical()` followed by any\n * traversal method throws a clear error rather than producing garbage.\n *\n * For STI subclasses, queries are issued against the STI base collection\n * so the table/discriminator are correct.\n *\n * Lookup uses the constructor's qualified name when available — set by\n * the registry on every registered class as `_smrtQualifiedName` (R5-\n * canon prep). Then `ObjectRegistry.getSTIBase(...)` returns the\n * qualified name of the STI base directly (R5-canon main), so the\n * `getCollection` lookup never collapses to a simple-name ambiguity\n * even when two packages ship a hierarchical class with the same\n * simple name. Falls back through `getClassByConstructor` → simple\n * `this.constructor.name` when the static / WeakMap aren't populated\n * (rare; `getCollection` then surfaces the existing \"not found in\n * ObjectRegistry\" error).\n *\n * The constructor prototype-chain walk that lived here from PR #1269\n * is gone — the registry now returns qualified names directly so the\n * walk became dead code.\n */\n protected async _hierarchyCollection(): Promise<SmrtCollection<this>> {\n if (this.constructor === SmrtHierarchical) {\n throw new Error(\n 'SmrtHierarchical is abstract — extend it from a concrete @smrt() class before calling hierarchy methods.',\n );\n }\n\n // Identity priority:\n // 1. The constructor's `_smrtQualifiedName` static (set at\n // registration, survives HMR / federated-module duplication).\n // 2. The registry's WeakMap (`getClassByConstructor`) — same value\n // as the static when both are populated, but the WeakMap is\n // where simple-name fallback lives.\n // 3. The simple constructor name as a last-ditch fallback.\n const ctor = this.constructor as typeof SmrtHierarchical & {\n _smrtQualifiedName?: string;\n };\n const tagged = ctor._smrtQualifiedName;\n const registered = tagged\n ? undefined\n : ObjectRegistry.getClassByConstructor(ctor as any);\n const className =\n tagged ?? registered?.qualifiedName ?? registered?.name ?? ctor.name;\n\n const stiBase = ObjectRegistry.getSTIBase(className);\n const collectionClass = stiBase ?? className;\n return await ObjectRegistry.getCollection<this>(\n collectionClass,\n this.options,\n );\n }\n\n /**\n * The parent row, or `null` when this row is top-level.\n *\n * Single query. Returns the hydrated row (STI dispatch applies, so an\n * Article-extends-Document subclass comes back as `Article`).\n */\n async getParent(): Promise<this | null> {\n if (!this.parentId) return null;\n const collection = await this._hierarchyCollection();\n const parent = await collection.get({ id: this.parentId });\n return parent as this | null;\n }\n\n /**\n * Immediate children. Single query: `WHERE parent_id = this.id`.\n */\n async getChildren(): Promise<this[]> {\n if (!this.id) return [];\n const collection = await this._hierarchyCollection();\n const children = await collection.list({\n where: { parentId: this.id },\n });\n return children as this[];\n }\n\n /**\n * All ancestors, root-first (immediate parent last). Does not include self.\n *\n * Intrinsically O(depth) queries — each step needs the previous level's\n * `parentId` before it can fetch the next. Includes cycle protection: if\n * a row's ancestor chain loops back on itself (data corruption), the walk\n * stops cleanly instead of looping forever.\n */\n async getAncestors(): Promise<this[]> {\n const ancestors: this[] = [];\n const visited = new Set<string>();\n if (this.id) visited.add(this.id);\n let current: this = this;\n\n while (current.parentId) {\n if (visited.has(current.parentId)) break;\n visited.add(current.parentId);\n\n const parent = (await current.getParent()) as this | null;\n if (!parent) break;\n ancestors.unshift(parent);\n current = parent;\n }\n\n return ancestors;\n }\n\n /**\n * All descendants in BFS order. One query per level of depth using `IN`\n * on the previous level's IDs — eliminates the recursive-per-child N+1\n * pattern the duplicated implementations used.\n *\n * Each level's frontier is chunked at `IN_LIST_CHUNK_SIZE` before being\n * expanded into a `parent_id IN (?, ?, …)` clause: the generic\n * `collection.list()` does NOT chunk array-valued WHERE clauses, so a level\n * wider than the backend's `SQLITE_MAX_VARIABLE_NUMBER` (999 on legacy\n * SQLite, 32766 on modern builds) would otherwise throw before traversal\n * completes. Mirrors the chunking the relationship/junction loaders in\n * `collection.ts` already do.\n *\n * Cycle-safe via a visited Set keyed on row id.\n */\n async getDescendants(): Promise<this[]> {\n if (!this.id) return [];\n const collection = await this._hierarchyCollection();\n const descendants: this[] = [];\n const visited = new Set<string>([this.id]);\n let frontier: string[] = [this.id];\n\n while (frontier.length > 0) {\n const next: string[] = [];\n\n // Chunk the frontier so each query stays under the bind-variable cap.\n // Children are merged into the same BFS level in chunk order, so the\n // overall ordering remains breadth-first.\n for (const idChunk of chunkArray(frontier, IN_LIST_CHUNK_SIZE)) {\n const children = (await collection.list({\n where: { parentId: idChunk },\n })) as this[];\n\n for (const child of children) {\n if (!child.id || visited.has(child.id)) continue;\n visited.add(child.id);\n descendants.push(child);\n next.push(child.id);\n }\n }\n\n frontier = next;\n }\n\n return descendants;\n }\n\n /**\n * Full hierarchy view: ancestors, self, descendants. Issued concurrently.\n */\n async getHierarchy(): Promise<HierarchyView<this>> {\n const [ancestors, descendants] = await Promise.all([\n this.getAncestors(),\n this.getDescendants(),\n ]);\n return { ancestors, current: this, descendants };\n }\n\n /**\n * Reparent this row. Pass `null` to make it a root, an id string, or the\n * target row itself. Refuses to:\n *\n * - move a row to itself (self-loop)\n * - move a row under one of its own descendants (would create a cycle)\n *\n * Persists via `save()`. Caller is responsible for any out-of-band\n * denormalization (e.g. depth caches on subclasses like Tag.level).\n */\n async moveTo(newParent: this | string | null): Promise<void> {\n const newParentId =\n newParent === null\n ? null\n : typeof newParent === 'string'\n ? newParent\n : (newParent.id ?? null);\n\n if (newParentId !== null && newParentId === this.id) {\n throw new Error(\n `Cannot move ${this.constructor.name} ${this.id} to itself.`,\n );\n }\n\n if (newParentId !== null) {\n const descendants = await this.getDescendants();\n if (descendants.some((d) => d.id === newParentId)) {\n throw new Error(\n `Cannot move ${this.constructor.name} ${this.id} under one of its own descendants (${newParentId}) — would create a cycle.`,\n );\n }\n }\n\n this.parentId = newParentId;\n await this.save();\n }\n}\n"],"names":[],"mappings":";;;AAqDO,MAAM,yBAAyB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ/C,OAAgB,sBAAsB;AAAA;AAAA,EAGtC,WAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4B1B,MAAgB,uBAAsD;AACpE,QAAI,KAAK,gBAAgB,kBAAkB;AACzC,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AASA,UAAM,OAAO,KAAK;AAGlB,UAAM,SAAS,KAAK;AACpB,UAAM,aAAa,SACf,SACA,eAAe,sBAAsB,IAAW;AACpD,UAAM,YACJ,UAAU,YAAY,iBAAiB,YAAY,QAAQ,KAAK;AAElE,UAAM,UAAU,eAAe,WAAW,SAAS;AACnD,UAAM,kBAAkB,WAAW;AACnC,WAAO,MAAM,eAAe;AAAA,MAC1B;AAAA,MACA,KAAK;AAAA,IAAA;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YAAkC;AACtC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,UAAM,aAAa,MAAM,KAAK,qBAAA;AAC9B,UAAM,SAAS,MAAM,WAAW,IAAI,EAAE,IAAI,KAAK,UAAU;AACzD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAA+B;AACnC,QAAI,CAAC,KAAK,GAAI,QAAO,CAAA;AACrB,UAAM,aAAa,MAAM,KAAK,qBAAA;AAC9B,UAAM,WAAW,MAAM,WAAW,KAAK;AAAA,MACrC,OAAO,EAAE,UAAU,KAAK,GAAA;AAAA,IAAG,CAC5B;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,eAAgC;AACpC,UAAM,YAAoB,CAAA;AAC1B,UAAM,8BAAc,IAAA;AACpB,QAAI,KAAK,GAAI,SAAQ,IAAI,KAAK,EAAE;AAChC,QAAI,UAAgB;AAEpB,WAAO,QAAQ,UAAU;AACvB,UAAI,QAAQ,IAAI,QAAQ,QAAQ,EAAG;AACnC,cAAQ,IAAI,QAAQ,QAAQ;AAE5B,YAAM,SAAU,MAAM,QAAQ,UAAA;AAC9B,UAAI,CAAC,OAAQ;AACb,gBAAU,QAAQ,MAAM;AACxB,gBAAU;AAAA,IACZ;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,iBAAkC;AACtC,QAAI,CAAC,KAAK,GAAI,QAAO,CAAA;AACrB,UAAM,aAAa,MAAM,KAAK,qBAAA;AAC9B,UAAM,cAAsB,CAAA;AAC5B,UAAM,UAAU,oBAAI,IAAY,CAAC,KAAK,EAAE,CAAC;AACzC,QAAI,WAAqB,CAAC,KAAK,EAAE;AAEjC,WAAO,SAAS,SAAS,GAAG;AAC1B,YAAM,OAAiB,CAAA;AAKvB,iBAAW,WAAW,WAAW,UAAU,kBAAkB,GAAG;AAC9D,cAAM,WAAY,MAAM,WAAW,KAAK;AAAA,UACtC,OAAO,EAAE,UAAU,QAAA;AAAA,QAAQ,CAC5B;AAED,mBAAW,SAAS,UAAU;AAC5B,cAAI,CAAC,MAAM,MAAM,QAAQ,IAAI,MAAM,EAAE,EAAG;AACxC,kBAAQ,IAAI,MAAM,EAAE;AACpB,sBAAY,KAAK,KAAK;AACtB,eAAK,KAAK,MAAM,EAAE;AAAA,QACpB;AAAA,MACF;AAEA,iBAAW;AAAA,IACb;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAA6C;AACjD,UAAM,CAAC,WAAW,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MACjD,KAAK,aAAA;AAAA,MACL,KAAK,eAAA;AAAA,IAAe,CACrB;AACD,WAAO,EAAE,WAAW,SAAS,MAAM,YAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,OAAO,WAAgD;AAC3D,UAAM,cACJ,cAAc,OACV,OACA,OAAO,cAAc,WACnB,YACC,UAAU,MAAM;AAEzB,QAAI,gBAAgB,QAAQ,gBAAgB,KAAK,IAAI;AACnD,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,YAAY,IAAI,IAAI,KAAK,EAAE;AAAA,MAAA;AAAA,IAEnD;AAEA,QAAI,gBAAgB,MAAM;AACxB,YAAM,cAAc,MAAM,KAAK,eAAA;AAC/B,UAAI,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,WAAW,GAAG;AACjD,cAAM,IAAI;AAAA,UACR,eAAe,KAAK,YAAY,IAAI,IAAI,KAAK,EAAE,sCAAsC,WAAW;AAAA,QAAA;AAAA,MAEpG;AAAA,IACF;AAEA,SAAK,WAAW;AAChB,UAAM,KAAK,KAAA;AAAA,EACb;AACF;"}
1
+ {"version":3,"file":"hierarchical.js","sources":["../src/hierarchical.ts"],"sourcesContent":["/**\n * SmrtHierarchical — base class for self-referencing tree hierarchies.\n *\n * Provides batched parent/children/ancestors/descendants/hierarchy traversal\n * and a cycle-safe `moveTo`. Replaces five copies of the same logic across\n * Place, Event, Tag, Account, and Zone.\n *\n * Examples in the monorepo:\n *\n * | Subclass | Domain |\n * |----------|------------------------------------------------|\n * | Place | hierarchical geographic places |\n * | Event | nestable event hierarchy (game → period → …) |\n * | Tag | tag taxonomies and category trees |\n * | Account | chart of accounts |\n * | Zone | placement zones inside a digital property |\n *\n * Convention: every subclass uses `parentId: string | null` referencing\n * another row in the same table (or STI base table) by UUID. Classes whose\n * self-reference has different semantics — e.g. `Fact.previousFactId` (an\n * evolution chain) or `Asset.sourceAssetId` (a derivation DAG) — should\n * NOT extend SmrtHierarchical. Use descriptive names and class-specific\n * methods instead.\n *\n * @example\n * ```typescript\n * @smrt({ tableStrategy: 'sti', api: true })\n * export class Place extends SmrtHierarchical {\n * name = '';\n * }\n *\n * const ancestors = await place.getAncestors();\n * const descendants = await place.getDescendants(); // BFS, one query per level\n * await place.moveTo(newParent); // cycle-checked\n * ```\n */\n\nimport type { SmrtCollection } from './collection';\nimport { SmrtObject } from './object';\nimport { ObjectRegistry } from './registry';\nimport type { SmrtObjectConstructor } from './registry/types';\nimport { chunkArray, IN_LIST_CHUNK_SIZE } from './utils/chunk';\n\n/**\n * Aggregate hierarchy view: ancestors (root-first), self, and all descendants\n * (BFS order). Generic on the concrete subclass so `getHierarchy()` preserves\n * the caller's type — `place.getHierarchy()` yields `HierarchyView<Place>`.\n */\nexport interface HierarchyView<T extends SmrtHierarchical> {\n ancestors: T[];\n current: T;\n descendants: T[];\n}\n\nexport class SmrtHierarchical extends SmrtObject {\n /**\n * Internal marker so the scanner can recognize this framework abstract base\n * even when consumers haven't built its package. Mirrors\n * `SmrtJunction._isJunctionBase`. Don't rename without also updating the\n * scanner's `FRAMEWORK_BASE_CLASSES` set in\n * `packages/scanner/src/inheritance-resolver.ts`.\n */\n static readonly _isHierarchicalBase = true as const;\n\n /** Self-referencing parent. `null` means top-level (no parent). */\n parentId: string | null = null;\n\n /**\n * Resolve the collection used to load siblings/ancestors/descendants.\n *\n * Goes through `ObjectRegistry.getCollection` so subclasses don't have to\n * hard-code a dynamic import of their own collection module. Also acts as\n * the abstract-base guard — `new SmrtHierarchical()` followed by any\n * traversal method throws a clear error rather than producing garbage.\n *\n * For STI subclasses, queries are issued against the STI base collection\n * so the table/discriminator are correct.\n *\n * Lookup uses the constructor's qualified name when available — set by\n * the registry on every registered class as `_smrtQualifiedName` (R5-\n * canon prep). Then `ObjectRegistry.getSTIBase(...)` returns the\n * qualified name of the STI base directly (R5-canon main), so the\n * `getCollection` lookup never collapses to a simple-name ambiguity\n * even when two packages ship a hierarchical class with the same\n * simple name. Falls back through `getClassByConstructor` → simple\n * `this.constructor.name` when the static / WeakMap aren't populated\n * (rare; `getCollection` then surfaces the existing \"not found in\n * ObjectRegistry\" error).\n *\n * The constructor prototype-chain walk that lived here from PR #1269\n * is gone — the registry now returns qualified names directly so the\n * walk became dead code.\n */\n protected async _hierarchyCollection(): Promise<SmrtCollection<this>> {\n if (this.constructor === SmrtHierarchical) {\n throw new Error(\n 'SmrtHierarchical is abstract — extend it from a concrete @smrt() class before calling hierarchy methods.',\n );\n }\n\n // Identity priority:\n // 1. The constructor's `_smrtQualifiedName` static (set at\n // registration, survives HMR / federated-module duplication).\n // 2. The registry's WeakMap (`getClassByConstructor`) — same value\n // as the static when both are populated, but the WeakMap is\n // where simple-name fallback lives.\n // 3. The simple constructor name as a last-ditch fallback.\n const ctor = this.constructor as typeof SmrtHierarchical & {\n _smrtQualifiedName?: string;\n };\n const tagged = ctor._smrtQualifiedName;\n const registered = tagged\n ? undefined\n : ObjectRegistry.getClassByConstructor(ctor as SmrtObjectConstructor);\n const className =\n tagged ?? registered?.qualifiedName ?? registered?.name ?? ctor.name;\n\n const stiBase = ObjectRegistry.getSTIBase(className);\n const collectionClass = stiBase ?? className;\n return await ObjectRegistry.getCollection<this>(\n collectionClass,\n this.options,\n );\n }\n\n /**\n * The parent row, or `null` when this row is top-level.\n *\n * Single query. Returns the hydrated row (STI dispatch applies, so an\n * Article-extends-Document subclass comes back as `Article`).\n */\n async getParent(): Promise<this | null> {\n if (!this.parentId) return null;\n const collection = await this._hierarchyCollection();\n const parent = await collection.get({ id: this.parentId });\n return parent as this | null;\n }\n\n /**\n * Immediate children. Single query: `WHERE parent_id = this.id`.\n */\n async getChildren(): Promise<this[]> {\n if (!this.id) return [];\n const collection = await this._hierarchyCollection();\n const children = await collection.list({\n where: { parentId: this.id },\n });\n return children as this[];\n }\n\n /**\n * All ancestors, root-first (immediate parent last). Does not include self.\n *\n * Intrinsically O(depth) queries — each step needs the previous level's\n * `parentId` before it can fetch the next. Includes cycle protection: if\n * a row's ancestor chain loops back on itself (data corruption), the walk\n * stops cleanly instead of looping forever.\n */\n async getAncestors(): Promise<this[]> {\n const ancestors: this[] = [];\n const visited = new Set<string>();\n if (this.id) visited.add(this.id);\n let current: this = this;\n\n while (current.parentId) {\n if (visited.has(current.parentId)) break;\n visited.add(current.parentId);\n\n const parent = (await current.getParent()) as this | null;\n if (!parent) break;\n ancestors.unshift(parent);\n current = parent;\n }\n\n return ancestors;\n }\n\n /**\n * All descendants in BFS order. One query per level of depth using `IN`\n * on the previous level's IDs — eliminates the recursive-per-child N+1\n * pattern the duplicated implementations used.\n *\n * Each level's frontier is chunked at `IN_LIST_CHUNK_SIZE` before being\n * expanded into a `parent_id IN (?, ?, …)` clause: the generic\n * `collection.list()` does NOT chunk array-valued WHERE clauses, so a level\n * wider than the backend's `SQLITE_MAX_VARIABLE_NUMBER` (999 on legacy\n * SQLite, 32766 on modern builds) would otherwise throw before traversal\n * completes. Mirrors the chunking the relationship/junction loaders in\n * `collection.ts` already do.\n *\n * Cycle-safe via a visited Set keyed on row id.\n */\n async getDescendants(): Promise<this[]> {\n if (!this.id) return [];\n const collection = await this._hierarchyCollection();\n const descendants: this[] = [];\n const visited = new Set<string>([this.id]);\n let frontier: string[] = [this.id];\n\n while (frontier.length > 0) {\n const next: string[] = [];\n\n // Chunk the frontier so each query stays under the bind-variable cap.\n // Children are merged into the same BFS level in chunk order, so the\n // overall ordering remains breadth-first.\n for (const idChunk of chunkArray(frontier, IN_LIST_CHUNK_SIZE)) {\n const children = (await collection.list({\n where: { parentId: idChunk },\n })) as this[];\n\n for (const child of children) {\n if (!child.id || visited.has(child.id)) continue;\n visited.add(child.id);\n descendants.push(child);\n next.push(child.id);\n }\n }\n\n frontier = next;\n }\n\n return descendants;\n }\n\n /**\n * Full hierarchy view: ancestors, self, descendants. Issued concurrently.\n */\n async getHierarchy(): Promise<HierarchyView<this>> {\n const [ancestors, descendants] = await Promise.all([\n this.getAncestors(),\n this.getDescendants(),\n ]);\n return { ancestors, current: this, descendants };\n }\n\n /**\n * Reparent this row. Pass `null` to make it a root, an id string, or the\n * target row itself. Refuses to:\n *\n * - move a row to itself (self-loop)\n * - move a row under one of its own descendants (would create a cycle)\n *\n * Persists via `save()`. Caller is responsible for any out-of-band\n * denormalization (e.g. depth caches on subclasses like Tag.level).\n */\n async moveTo(newParent: this | string | null): Promise<void> {\n const newParentId =\n newParent === null\n ? null\n : typeof newParent === 'string'\n ? newParent\n : (newParent.id ?? null);\n\n if (newParentId !== null && newParentId === this.id) {\n throw new Error(\n `Cannot move ${this.constructor.name} ${this.id} to itself.`,\n );\n }\n\n if (newParentId !== null) {\n const descendants = await this.getDescendants();\n if (descendants.some((d) => d.id === newParentId)) {\n throw new Error(\n `Cannot move ${this.constructor.name} ${this.id} under one of its own descendants (${newParentId}) — would create a cycle.`,\n );\n }\n }\n\n this.parentId = newParentId;\n await this.save();\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"junction.d.ts","sourceRoot":"","sources":["../src/junction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAM5D,8BAAsB,YAAY,CAChC,KAAK,SAAS,UAAU,CACxB,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAG,IAAI,CAAU;IAEhD,iFAAiF;IACjF,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAErC,gFAAgF;IAChF,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAEtC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAe;IAEjD;;;;;;;;;OASG;IACH,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAe;IAErD;;;OAGG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;IAYnB;;;OAGG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;IASnB;;;;;;;;;;;;;;;;OAgBG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,KAAK,CAAC;IAWjB;;;;OAIG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,IAAI,CAAC;IAahB;;;;;;;;;;OAUG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,IAAI,CAAC;CAwBjB"}
1
+ {"version":3,"file":"junction.d.ts","sourceRoot":"","sources":["../src/junction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,cAAc,EAAwB,MAAM,cAAc,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAM5D,8BAAsB,YAAY,CAChC,KAAK,SAAS,UAAU,CACxB,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAG,IAAI,CAAU;IAEhD,iFAAiF;IACjF,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAErC,gFAAgF;IAChF,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAEtC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAe;IAEjD;;;;;;;;;OASG;IACH,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAe;IAErD;;;OAGG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;IAYnB;;;OAGG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;IASnB;;;;;;;;;;;;;;;;OAgBG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,KAAK,CAAC;IAWjB;;;;OAIG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,IAAI,CAAC;IAahB;;;;;;;;;;OAUG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,IAAI,CAAC;CAwBjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"junction.js","sources":["../src/junction.ts"],"sourcesContent":["/**\n * SmrtJunction — base class for two-sided junction (many-to-many) collections.\n *\n * A junction collection manages rows that link a \"left\" entity to a \"right\" entity,\n * typically with discriminator fields (relationship/role) and an optional sortOrder.\n * Examples in the monorepo:\n *\n * | Subclass | Left field | Right field | Discriminator |\n * |--------------------------------|---------------|-------------|-----------------|\n * | ContentAssetCollection | contentId | assetId | relationship |\n * | PerformerOwnedAssetCollection | performerId | assetId | role |\n * | PlaceAssetCollection | placeId | assetId | relationship |\n * | EventParticipantCollection | eventId | profileId | role |\n * | FactContentCollection | factId | contentId | relationship |\n *\n * Each subclass declares `leftField` / `rightField` (camelCase) and optionally\n * overrides `sortField` (defaults to `'sortOrder'`; set `null` to disable ORDER BY).\n *\n * Polymorphic subclasses (where \"left\" or \"right\" is a composite key like\n * `metaType + metaId`) may override `byLeft` / `byRight` / `attach` / `detach`\n * with diverging signatures — see `AssetAssociationCollection` for a reference.\n *\n * @typeParam TItem - The junction row class (extends `SmrtObject`)\n */\n\nimport { SmrtCollection } from './collection';\nimport type { SmrtObject } from './object';\n\n/**\n * Options passed to `attach` / `setLinks` — written into the created junction row.\n *\n * Common keys: `relationship`, `role`, `sortOrder`, `tenantId`.\n * Subclass-specific keys (e.g. `placement`, `groupId` on EventParticipant) pass through.\n * Keys must match actual camelCase column names on the junction model; unknown\n * keys are rejected by `SmrtCollection.create`'s WHERE/field validation.\n */\nexport type JunctionAttachOptions = Record<string, unknown>;\n\n/**\n * Options passed to `byLeft` / `byRight` / `detach` — additional WHERE filters\n * narrowing the operation. Keys must match camelCase column names.\n */\nexport type JunctionFilterOptions = Record<string, unknown>;\n\nfunction camelToSnake(name: string): string {\n return name.replace(/[A-Z]/g, (m) => `_${m.toLowerCase()}`);\n}\n\nexport abstract class SmrtJunction<\n TItem extends SmrtObject,\n> extends SmrtCollection<TItem> {\n /**\n * Internal marker used by `SmrtCollection.create` to detect that this\n * subclass is a junction and apply a registration-presence guard. Static\n * property is inherited by all subclasses via the constructor chain.\n * Don't rename or remove without also updating the guard.\n */\n static readonly _isJunctionBase = true as const;\n\n /** Field name (camelCase) holding the \"left\" foreign key, e.g. `'contentId'`. */\n protected abstract leftField: string;\n\n /** Field name (camelCase) holding the \"right\" foreign key, e.g. `'assetId'`. */\n protected abstract rightField: string;\n\n /**\n * Field name (camelCase) used to ORDER BY when calling `byLeft` / `byRight`.\n * Defaults to `'sortOrder'`. Set to `null` to omit ORDER BY entirely.\n *\n * Independent from `positionField` — `sortField` is a *query* concern\n * (how rows are ordered when read), while `positionField` is a *write*\n * concern (what column `setLinks` auto-assigns to). Tables that order\n * by a non-position field (e.g. `'createdAt'`) should set `sortField`\n * accordingly and leave `positionField` set to `null` or its dedicated\n * position column name.\n */\n protected sortField: string | null = 'sortOrder';\n\n /**\n * Field name (camelCase) that `setLinks` auto-assigns the array index\n * to when the caller doesn't supply a value. Defaults to `'sortOrder'`.\n * Set to `null` for tables without a dedicated position column (e.g.\n * pure-key junctions, or tables ordered by timestamps).\n *\n * Writing the array index into a non-position field — like `createdAt`\n * or `placement` — would corrupt data. Subclasses without a numeric\n * position column MUST set this to `null`.\n */\n protected positionField: string | null = 'sortOrder';\n\n /**\n * Return junction rows where the left FK matches `leftId`, narrowed by\n * optional additional WHERE filters. Ordered ASC by `sortField` if set.\n */\n async byLeft(\n leftId: string,\n opts: JunctionFilterOptions = {},\n ): Promise<TItem[]> {\n return (await this.list({\n // Spread opts FIRST so the fixed key always wins — prevents a\n // caller-supplied `{ [leftField]: otherId }` from retargeting the\n // query when opts is forwarded from untrusted input.\n where: { ...opts, [this.leftField]: leftId },\n ...(this.sortField\n ? { orderBy: `${camelToSnake(this.sortField)} ASC` }\n : {}),\n })) as TItem[];\n }\n\n /**\n * Return junction rows where the right FK matches `rightId`, narrowed by\n * optional additional WHERE filters. Ordered ASC by `sortField` if set.\n */\n async byRight(\n rightId: string,\n opts: JunctionFilterOptions = {},\n ): Promise<TItem[]> {\n return (await this.list({\n where: { ...opts, [this.rightField]: rightId },\n ...(this.sortField\n ? { orderBy: `${camelToSnake(this.sortField)} ASC` }\n : {}),\n })) as TItem[];\n }\n\n /**\n * Create a new junction row linking `leftId` ↔ `rightId`.\n *\n * Goes through `SmrtCollection.create` which performs an upsert keyed on\n * the model's `@smrt({ conflictColumns })`. Duplicates on the conflict key\n * resolve to an UPDATE that rewrites every column — including the row's\n * `id` and any timestamp columns — to the new instance's values. For most\n * junctions that's fine: callers identify rows by (left, right, discriminator),\n * not by junction-row-id, so id rewrites are invisible.\n *\n * If your junction table is externally addressable by id (e.g. its rows\n * are exposed under `/api/v1/<table>/[id]`), override this method with a\n * find-or-create check to preserve id stability across duplicate calls.\n * See `ContentReferences.attach` for an example.\n *\n * @param opts - Extra fields to write into the row (e.g. `{ relationship, sortOrder, tenantId }`)\n */\n async attach(\n leftId: string,\n rightId: string,\n opts: JunctionAttachOptions = {},\n ): Promise<TItem> {\n return (await this.create({\n // Spread opts FIRST so the fixed key fields always win — prevents\n // a caller-supplied `{ [leftField]: otherId }` from retargeting\n // the write when opts is forwarded from untrusted input.\n ...opts,\n [this.leftField]: leftId,\n [this.rightField]: rightId,\n } as any)) as TItem;\n }\n\n /**\n * Delete all junction rows matching `leftId` + `rightId` (+ optional filter `opts`).\n *\n * @param opts - Additional WHERE filters (e.g. `{ relationship: 'thumbnail' }`)\n */\n async detach(\n leftId: string,\n rightId: string,\n opts: JunctionFilterOptions = {},\n ): Promise<void> {\n const links = (await this.list({\n where: {\n ...opts,\n [this.leftField]: leftId,\n [this.rightField]: rightId,\n },\n })) as TItem[];\n for (const link of links) {\n await (link as unknown as { delete(): Promise<void> }).delete();\n }\n }\n\n /**\n * Replace the full set of right-side rows for a `leftId`, scoped by `opts`.\n *\n * Behavior:\n * 1. Snapshots and deletes existing rows matching `{ leftField: leftId, ...opts }`.\n * 2. Creates a new row for each `rightId`, spreading `opts` into the row data.\n * 3. If `positionField` is set and `opts` doesn't specify it, assigns the array index.\n *\n * Not transactional — partial failure leaves the table in a mixed state.\n * For atomic replaces, wrap the call in your own DB transaction.\n */\n async setLinks(\n leftId: string,\n rightIds: string[],\n opts: JunctionAttachOptions = {},\n ): Promise<void> {\n // Strip the right-side key from snapshot opts — leaving it in would\n // narrow the delete to one specific right id, but `setLinks` is\n // contractually \"replace the full set of right rows for leftId\n // within the opts scope\". A rightField filter contradicts that.\n const snapshotOpts: JunctionAttachOptions = { ...opts };\n delete snapshotOpts[this.rightField];\n\n const existing = (await this.list({\n where: { ...snapshotOpts, [this.leftField]: leftId },\n })) as TItem[];\n for (const link of existing) {\n await (link as unknown as { delete(): Promise<void> }).delete();\n }\n\n const positionKey = this.positionField;\n for (let i = 0; i < rightIds.length; i++) {\n const rowOpts: JunctionAttachOptions = { ...opts };\n if (positionKey && rowOpts[positionKey] === undefined) {\n rowOpts[positionKey] = i;\n }\n await this.attach(leftId, rightIds[i], rowOpts);\n }\n }\n}\n"],"names":[],"mappings":";AA4CA,SAAS,aAAa,MAAsB;AAC1C,SAAO,KAAK,QAAQ,UAAU,CAAC,MAAM,IAAI,EAAE,YAAA,CAAa,EAAE;AAC5D;AAEO,MAAe,qBAEZ,eAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,OAAgB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBxB,YAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY3B,gBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzC,MAAM,OACJ,QACA,OAA8B,IACZ;AAClB,WAAQ,MAAM,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,MAItB,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,SAAS,GAAG,OAAA;AAAA,MACpC,GAAI,KAAK,YACL,EAAE,SAAS,GAAG,aAAa,KAAK,SAAS,CAAC,WAC1C,CAAA;AAAA,IAAC,CACN;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QACJ,SACA,OAA8B,IACZ;AAClB,WAAQ,MAAM,KAAK,KAAK;AAAA,MACtB,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,UAAU,GAAG,QAAA;AAAA,MACrC,GAAI,KAAK,YACL,EAAE,SAAS,GAAG,aAAa,KAAK,SAAS,CAAC,WAC1C,CAAA;AAAA,IAAC,CACN;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,OACJ,QACA,SACA,OAA8B,CAAA,GACd;AAChB,WAAQ,MAAM,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA,MAIxB,GAAG;AAAA,MACH,CAAC,KAAK,SAAS,GAAG;AAAA,MAClB,CAAC,KAAK,UAAU,GAAG;AAAA,IAAA,CACb;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OACJ,QACA,SACA,OAA8B,CAAA,GACf;AACf,UAAM,QAAS,MAAM,KAAK,KAAK;AAAA,MAC7B,OAAO;AAAA,QACL,GAAG;AAAA,QACH,CAAC,KAAK,SAAS,GAAG;AAAA,QAClB,CAAC,KAAK,UAAU,GAAG;AAAA,MAAA;AAAA,IACrB,CACD;AACD,eAAW,QAAQ,OAAO;AACxB,YAAO,KAAgD,OAAA;AAAA,IACzD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,SACJ,QACA,UACA,OAA8B,CAAA,GACf;AAKf,UAAM,eAAsC,EAAE,GAAG,KAAA;AACjD,WAAO,aAAa,KAAK,UAAU;AAEnC,UAAM,WAAY,MAAM,KAAK,KAAK;AAAA,MAChC,OAAO,EAAE,GAAG,cAAc,CAAC,KAAK,SAAS,GAAG,OAAA;AAAA,IAAO,CACpD;AACD,eAAW,QAAQ,UAAU;AAC3B,YAAO,KAAgD,OAAA;AAAA,IACzD;AAEA,UAAM,cAAc,KAAK;AACzB,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,YAAM,UAAiC,EAAE,GAAG,KAAA;AAC5C,UAAI,eAAe,QAAQ,WAAW,MAAM,QAAW;AACrD,gBAAQ,WAAW,IAAI;AAAA,MACzB;AACA,YAAM,KAAK,OAAO,QAAQ,SAAS,CAAC,GAAG,OAAO;AAAA,IAChD;AAAA,EACF;AACF;"}
1
+ {"version":3,"file":"junction.js","sources":["../src/junction.ts"],"sourcesContent":["/**\n * SmrtJunction — base class for two-sided junction (many-to-many) collections.\n *\n * A junction collection manages rows that link a \"left\" entity to a \"right\" entity,\n * typically with discriminator fields (relationship/role) and an optional sortOrder.\n * Examples in the monorepo:\n *\n * | Subclass | Left field | Right field | Discriminator |\n * |--------------------------------|---------------|-------------|-----------------|\n * | ContentAssetCollection | contentId | assetId | relationship |\n * | PerformerOwnedAssetCollection | performerId | assetId | role |\n * | PlaceAssetCollection | placeId | assetId | relationship |\n * | EventParticipantCollection | eventId | profileId | role |\n * | FactContentCollection | factId | contentId | relationship |\n *\n * Each subclass declares `leftField` / `rightField` (camelCase) and optionally\n * overrides `sortField` (defaults to `'sortOrder'`; set `null` to disable ORDER BY).\n *\n * Polymorphic subclasses (where \"left\" or \"right\" is a composite key like\n * `metaType + metaId`) may override `byLeft` / `byRight` / `attach` / `detach`\n * with diverging signatures — see `AssetAssociationCollection` for a reference.\n *\n * @typeParam TItem - The junction row class (extends `SmrtObject`)\n */\n\nimport { SmrtCollection, type SmrtCreateInput } from './collection';\nimport type { SmrtObject } from './object';\n\n/**\n * Options passed to `attach` / `setLinks` — written into the created junction row.\n *\n * Common keys: `relationship`, `role`, `sortOrder`, `tenantId`.\n * Subclass-specific keys (e.g. `placement`, `groupId` on EventParticipant) pass through.\n * Keys must match actual camelCase column names on the junction model; unknown\n * keys are rejected by `SmrtCollection.create`'s WHERE/field validation.\n */\nexport type JunctionAttachOptions = Record<string, unknown>;\n\n/**\n * Options passed to `byLeft` / `byRight` / `detach` — additional WHERE filters\n * narrowing the operation. Keys must match camelCase column names.\n */\nexport type JunctionFilterOptions = Record<string, unknown>;\n\nfunction camelToSnake(name: string): string {\n return name.replace(/[A-Z]/g, (m) => `_${m.toLowerCase()}`);\n}\n\nexport abstract class SmrtJunction<\n TItem extends SmrtObject,\n> extends SmrtCollection<TItem> {\n /**\n * Internal marker used by `SmrtCollection.create` to detect that this\n * subclass is a junction and apply a registration-presence guard. Static\n * property is inherited by all subclasses via the constructor chain.\n * Don't rename or remove without also updating the guard.\n */\n static readonly _isJunctionBase = true as const;\n\n /** Field name (camelCase) holding the \"left\" foreign key, e.g. `'contentId'`. */\n protected abstract leftField: string;\n\n /** Field name (camelCase) holding the \"right\" foreign key, e.g. `'assetId'`. */\n protected abstract rightField: string;\n\n /**\n * Field name (camelCase) used to ORDER BY when calling `byLeft` / `byRight`.\n * Defaults to `'sortOrder'`. Set to `null` to omit ORDER BY entirely.\n *\n * Independent from `positionField` — `sortField` is a *query* concern\n * (how rows are ordered when read), while `positionField` is a *write*\n * concern (what column `setLinks` auto-assigns to). Tables that order\n * by a non-position field (e.g. `'createdAt'`) should set `sortField`\n * accordingly and leave `positionField` set to `null` or its dedicated\n * position column name.\n */\n protected sortField: string | null = 'sortOrder';\n\n /**\n * Field name (camelCase) that `setLinks` auto-assigns the array index\n * to when the caller doesn't supply a value. Defaults to `'sortOrder'`.\n * Set to `null` for tables without a dedicated position column (e.g.\n * pure-key junctions, or tables ordered by timestamps).\n *\n * Writing the array index into a non-position field — like `createdAt`\n * or `placement` — would corrupt data. Subclasses without a numeric\n * position column MUST set this to `null`.\n */\n protected positionField: string | null = 'sortOrder';\n\n /**\n * Return junction rows where the left FK matches `leftId`, narrowed by\n * optional additional WHERE filters. Ordered ASC by `sortField` if set.\n */\n async byLeft(\n leftId: string,\n opts: JunctionFilterOptions = {},\n ): Promise<TItem[]> {\n return (await this.list({\n // Spread opts FIRST so the fixed key always wins — prevents a\n // caller-supplied `{ [leftField]: otherId }` from retargeting the\n // query when opts is forwarded from untrusted input.\n where: { ...opts, [this.leftField]: leftId },\n ...(this.sortField\n ? { orderBy: `${camelToSnake(this.sortField)} ASC` }\n : {}),\n })) as TItem[];\n }\n\n /**\n * Return junction rows where the right FK matches `rightId`, narrowed by\n * optional additional WHERE filters. Ordered ASC by `sortField` if set.\n */\n async byRight(\n rightId: string,\n opts: JunctionFilterOptions = {},\n ): Promise<TItem[]> {\n return (await this.list({\n where: { ...opts, [this.rightField]: rightId },\n ...(this.sortField\n ? { orderBy: `${camelToSnake(this.sortField)} ASC` }\n : {}),\n })) as TItem[];\n }\n\n /**\n * Create a new junction row linking `leftId` ↔ `rightId`.\n *\n * Goes through `SmrtCollection.create` which performs an upsert keyed on\n * the model's `@smrt({ conflictColumns })`. Duplicates on the conflict key\n * resolve to an UPDATE that rewrites every column — including the row's\n * `id` and any timestamp columns — to the new instance's values. For most\n * junctions that's fine: callers identify rows by (left, right, discriminator),\n * not by junction-row-id, so id rewrites are invisible.\n *\n * If your junction table is externally addressable by id (e.g. its rows\n * are exposed under `/api/v1/<table>/[id]`), override this method with a\n * find-or-create check to preserve id stability across duplicate calls.\n * See `ContentReferences.attach` for an example.\n *\n * @param opts - Extra fields to write into the row (e.g. `{ relationship, sortOrder, tenantId }`)\n */\n async attach(\n leftId: string,\n rightId: string,\n opts: JunctionAttachOptions = {},\n ): Promise<TItem> {\n return (await this.create({\n // Spread opts FIRST so the fixed key fields always win — prevents\n // a caller-supplied `{ [leftField]: otherId }` from retargeting\n // the write when opts is forwarded from untrusted input.\n ...opts,\n [this.leftField]: leftId,\n [this.rightField]: rightId,\n } as SmrtCreateInput<TItem>)) as TItem;\n }\n\n /**\n * Delete all junction rows matching `leftId` + `rightId` (+ optional filter `opts`).\n *\n * @param opts - Additional WHERE filters (e.g. `{ relationship: 'thumbnail' }`)\n */\n async detach(\n leftId: string,\n rightId: string,\n opts: JunctionFilterOptions = {},\n ): Promise<void> {\n const links = (await this.list({\n where: {\n ...opts,\n [this.leftField]: leftId,\n [this.rightField]: rightId,\n },\n })) as TItem[];\n for (const link of links) {\n await (link as unknown as { delete(): Promise<void> }).delete();\n }\n }\n\n /**\n * Replace the full set of right-side rows for a `leftId`, scoped by `opts`.\n *\n * Behavior:\n * 1. Snapshots and deletes existing rows matching `{ leftField: leftId, ...opts }`.\n * 2. Creates a new row for each `rightId`, spreading `opts` into the row data.\n * 3. If `positionField` is set and `opts` doesn't specify it, assigns the array index.\n *\n * Not transactional — partial failure leaves the table in a mixed state.\n * For atomic replaces, wrap the call in your own DB transaction.\n */\n async setLinks(\n leftId: string,\n rightIds: string[],\n opts: JunctionAttachOptions = {},\n ): Promise<void> {\n // Strip the right-side key from snapshot opts — leaving it in would\n // narrow the delete to one specific right id, but `setLinks` is\n // contractually \"replace the full set of right rows for leftId\n // within the opts scope\". A rightField filter contradicts that.\n const snapshotOpts: JunctionAttachOptions = { ...opts };\n delete snapshotOpts[this.rightField];\n\n const existing = (await this.list({\n where: { ...snapshotOpts, [this.leftField]: leftId },\n })) as TItem[];\n for (const link of existing) {\n await (link as unknown as { delete(): Promise<void> }).delete();\n }\n\n const positionKey = this.positionField;\n for (let i = 0; i < rightIds.length; i++) {\n const rowOpts: JunctionAttachOptions = { ...opts };\n if (positionKey && rowOpts[positionKey] === undefined) {\n rowOpts[positionKey] = i;\n }\n await this.attach(leftId, rightIds[i], rowOpts);\n }\n }\n}\n"],"names":[],"mappings":";AA4CA,SAAS,aAAa,MAAsB;AAC1C,SAAO,KAAK,QAAQ,UAAU,CAAC,MAAM,IAAI,EAAE,YAAA,CAAa,EAAE;AAC5D;AAEO,MAAe,qBAEZ,eAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,OAAgB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBxB,YAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY3B,gBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzC,MAAM,OACJ,QACA,OAA8B,IACZ;AAClB,WAAQ,MAAM,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,MAItB,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,SAAS,GAAG,OAAA;AAAA,MACpC,GAAI,KAAK,YACL,EAAE,SAAS,GAAG,aAAa,KAAK,SAAS,CAAC,WAC1C,CAAA;AAAA,IAAC,CACN;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QACJ,SACA,OAA8B,IACZ;AAClB,WAAQ,MAAM,KAAK,KAAK;AAAA,MACtB,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,UAAU,GAAG,QAAA;AAAA,MACrC,GAAI,KAAK,YACL,EAAE,SAAS,GAAG,aAAa,KAAK,SAAS,CAAC,WAC1C,CAAA;AAAA,IAAC,CACN;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,OACJ,QACA,SACA,OAA8B,CAAA,GACd;AAChB,WAAQ,MAAM,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA,MAIxB,GAAG;AAAA,MACH,CAAC,KAAK,SAAS,GAAG;AAAA,MAClB,CAAC,KAAK,UAAU,GAAG;AAAA,IAAA,CACM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OACJ,QACA,SACA,OAA8B,CAAA,GACf;AACf,UAAM,QAAS,MAAM,KAAK,KAAK;AAAA,MAC7B,OAAO;AAAA,QACL,GAAG;AAAA,QACH,CAAC,KAAK,SAAS,GAAG;AAAA,QAClB,CAAC,KAAK,UAAU,GAAG;AAAA,MAAA;AAAA,IACrB,CACD;AACD,eAAW,QAAQ,OAAO;AACxB,YAAO,KAAgD,OAAA;AAAA,IACzD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,SACJ,QACA,UACA,OAA8B,CAAA,GACf;AAKf,UAAM,eAAsC,EAAE,GAAG,KAAA;AACjD,WAAO,aAAa,KAAK,UAAU;AAEnC,UAAM,WAAY,MAAM,KAAK,KAAK;AAAA,MAChC,OAAO,EAAE,GAAG,cAAc,CAAC,KAAK,SAAS,GAAG,OAAA;AAAA,IAAO,CACpD;AACD,eAAW,QAAQ,UAAU;AAC3B,YAAO,KAAgD,OAAA;AAAA,IACzD;AAEA,UAAM,cAAc,KAAK;AACzB,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,YAAM,UAAiC,EAAE,GAAG,KAAA;AAC5C,UAAI,eAAe,QAAQ,WAAW,MAAM,QAAW;AACrD,gBAAQ,WAAW,IAAI;AAAA,MACzB;AACA,YAAM,KAAK,OAAO,QAAQ,SAAS,CAAC,GAAG,OAAO;AAAA,IAChD;AAAA,EACF;AACF;"}
@@ -42,6 +42,16 @@ export interface DiscoveryOptions {
42
42
  * - Automatically invalidates when any manifest.json changes (packages rebuilt)
43
43
  *
44
44
  * Disable with SMRT_DISABLE_DISCOVERY_CACHE=true for debugging
45
+ *
46
+ * Intentional split (#1579): this is the **build-time** discovery path —
47
+ * synchronous, scans `node_modules` for `manifest.json` files with
48
+ * `moduleType: "smrt"`, and caches by lockfile/manifest hash for fast manifest
49
+ * generation. It is deliberately distinct from the consumer-plugin's
50
+ * `discoverSmrtPackages(projectRoot)` (`src/consumer-plugin/index.ts`), which is
51
+ * **async**, reads a downstream app's `package.json` dependency names with a
52
+ * lightweight `@have/`/`smrt` heuristic, and runs inside the Vite consumer
53
+ * plugin. Different inputs, contexts, and lifecycles — not duplicated logic to
54
+ * consolidate.
45
55
  */
46
56
  export declare function discoverSmrtPackages(options?: DiscoveryOptions): string[];
47
57
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"discover-smrt-packages.d.ts","sourceRoot":"","sources":["../../src/manifest/discover-smrt-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoBH,oCAAoC;AACpC,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AA2ID,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,MAAM,GAAG,IAAI,CAoBf;AAkPD,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,EAAE,CAsE7E"}
1
+ {"version":3,"file":"discover-smrt-packages.d.ts","sourceRoot":"","sources":["../../src/manifest/discover-smrt-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoBH,oCAAoC;AACpC,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AA2ID,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,MAAM,GAAG,IAAI,CAoBf;AAkPD,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,EAAE,CAsE7E"}