@happyvertical/smrt-core 0.52.0 → 0.53.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 (63) hide show
  1. package/AGENTS.md +1 -0
  2. package/README.md +8 -2
  3. package/agents/model-moves.md +114 -0
  4. package/agents/object-runtime.md +3 -1
  5. package/agents/run-once.md +16 -7
  6. package/dist/cascade.d.ts.map +1 -1
  7. package/dist/cascade.js +4 -2
  8. package/dist/cascade.js.map +1 -1
  9. package/dist/generators/preflight-route.d.ts.map +1 -1
  10. package/dist/generators/preflight-route.js +1 -1
  11. package/dist/generators/preflight-route.js.map +1 -1
  12. package/dist/knowledge.d.ts.map +1 -1
  13. package/dist/knowledge.js +3 -0
  14. package/dist/knowledge.js.map +1 -1
  15. package/dist/manifest/static-manifest.js +1 -1
  16. package/dist/manifest/static-manifest.js.map +1 -1
  17. package/dist/manifest/store.js +1 -1
  18. package/dist/manifest.json +1 -1
  19. package/dist/migrations/index.d.ts +1 -0
  20. package/dist/migrations/index.d.ts.map +1 -1
  21. package/dist/migrations/index.js +2 -1
  22. package/dist/migrations/qualified-name-aliases.d.ts +134 -0
  23. package/dist/migrations/qualified-name-aliases.d.ts.map +1 -0
  24. package/dist/migrations/qualified-name-aliases.js +294 -0
  25. package/dist/migrations/qualified-name-aliases.js.map +1 -0
  26. package/dist/migrations.js +2 -1
  27. package/dist/polymorphic-association.d.ts +18 -0
  28. package/dist/polymorphic-association.d.ts.map +1 -1
  29. package/dist/polymorphic-association.js +27 -2
  30. package/dist/polymorphic-association.js.map +1 -1
  31. package/dist/registry/class-registration.d.ts.map +1 -1
  32. package/dist/registry/class-registration.js +27 -4
  33. package/dist/registry/class-registration.js.map +1 -1
  34. package/dist/registry/name-resolver.d.ts +8 -2
  35. package/dist/registry/name-resolver.d.ts.map +1 -1
  36. package/dist/registry/name-resolver.js +17 -8
  37. package/dist/registry/name-resolver.js.map +1 -1
  38. package/dist/registry/qualified-name-aliases.d.ts +109 -0
  39. package/dist/registry/qualified-name-aliases.d.ts.map +1 -0
  40. package/dist/registry/qualified-name-aliases.js +286 -0
  41. package/dist/registry/qualified-name-aliases.js.map +1 -0
  42. package/dist/registry/relationship-graph.d.ts.map +1 -1
  43. package/dist/registry/relationship-graph.js +1 -1
  44. package/dist/registry/relationship-graph.js.map +1 -1
  45. package/dist/registry/types.d.ts +26 -0
  46. package/dist/registry/types.d.ts.map +1 -1
  47. package/dist/registry.d.ts +59 -2
  48. package/dist/registry.d.ts.map +1 -1
  49. package/dist/registry.js +115 -6
  50. package/dist/registry.js.map +1 -1
  51. package/dist/scanner/manifest-generator.d.ts +11 -0
  52. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  53. package/dist/scanner/manifest-generator.js +36 -1
  54. package/dist/scanner/manifest-generator.js.map +1 -1
  55. package/dist/schema/conflict-target.js +8 -1
  56. package/dist/schema/conflict-target.js.map +1 -1
  57. package/dist/scripts/browser-plain-json-regression.mjs +4 -1
  58. package/dist/smrt-knowledge.json +15 -9
  59. package/dist/utils/qualified-names.d.ts +11 -0
  60. package/dist/utils/qualified-names.d.ts.map +1 -1
  61. package/dist/utils/qualified-names.js +21 -1
  62. package/dist/utils/qualified-names.js.map +1 -1
  63. package/package.json +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"class-registration.js","names":[],"sources":["../../src/registry/class-registration.ts"],"sourcesContent":["/**\n * Class registration module for the SMRT ObjectRegistry.\n *\n * Handles registering classes, collections, and manifest entries.\n *\n * Extracted from registry.ts as part of issue #1006.\n * @see https://github.com/happyvertical/smrt/issues/1006\n */\n\nimport {\n declareChangeFeedSensitiveTable,\n setChangeFeedSensitiveClassResolver,\n} from '../change-feed-sensitivity.js';\nimport { ConfigurationError } from '../errors';\nimport {\n discoverManifestSync,\n discoverSTISiblingsSync,\n getPackageName,\n lookupInManifest,\n readProjectManifestSync,\n} from '../manifest/manifest-loader.js';\nimport {\n cloneManifestSchemaColumns,\n findWorkspaceRootSync,\n getLocalTestManifestCache,\n getManifestCache,\n getNodeBuiltins,\n getStaticManifestCache,\n getTestManifestCache,\n} from '../manifest/store.js';\nimport { SmrtObject } from '../object';\nimport type {\n FieldDefinition,\n FieldMeta,\n MethodDefinition,\n QualifiedClassName,\n SmartObjectDefinition,\n SmartObjectManifest,\n SmrtVisibility,\n} from '../scanner/types.js';\nimport type {\n ColumnDefinition,\n IndexDefinition,\n SchemaDefinition,\n} from '../schema/types.js';\nimport { tableNameFromClass, toSnakeCase } from '../utils';\nimport {\n createQualifiedName,\n isQualifiedName,\n parseQualifiedName,\n} from '../utils/qualified-names.js';\nimport {\n type CollisionInputs,\n decideCollisionPolicy,\n type MatchKind,\n} from './collision-policy.js';\nimport { isFrameworkBaseClass } from './framework-base-classes.js';\nimport { bumpRegistryGeneration } from './generation';\nimport { buildInheritanceChain } from './inheritance-resolver';\nimport {\n createFieldFromManifest,\n mergeManifestField,\n} from './manifest-field-merge.js';\nimport {\n findClass,\n findClassesByName,\n getCanonicalClassName,\n hasClassCaseInsensitive,\n qualifyExtendsName,\n} from './name-resolver';\nimport {\n getClasses,\n getCollections,\n getConstructorFieldDecorators,\n getConstructorIndex,\n getConstructorTenantScopedDeclarations,\n getInheritanceCache,\n getLegacyFieldDecorators,\n getSourceFileFromStack,\n getStiSiblingsLoaded,\n verboseLog,\n} from './shared-state';\nimport type {\n RegisteredClass,\n RegisteredField,\n SmartObjectConfig,\n ValidatorFunction,\n} from './types.js';\nimport { compileValidators } from './validator';\n\n/**\n * Compute the pluralized endpoint/collection name from a class name, using\n * the SAME simple inflection rules as the scanner's manifest adapter\n * (`packages/scanner/src/manifest-adapter.ts`). Used only as a fallback when\n * a registered class has no manifest-provided `collection` (e.g. inline test\n * classes registered purely via the decorator path). Keep in sync with the\n * scanner; the manifest value is always preferred when present. (smrt#1311.)\n *\n * Currency -> currencies (y -> ies)\n * CompanyResearch -> companyresearches (ch -> ches)\n * SourceCrawl -> sourcecrawls (+ s)\n * EmploymentPerson -> employmentpersons (naive + s, NOT \"people\")\n */\nfunction pluralizeCollection(className: string): string {\n const lower = className.toLowerCase();\n if (lower.endsWith('y')) return `${lower.slice(0, -1)}ies`;\n if (lower.endsWith('s') || lower.endsWith('x') || lower.endsWith('z')) {\n return `${lower}es`;\n }\n if (lower.endsWith('ch') || lower.endsWith('sh')) return `${lower}es`;\n return `${lower}s`;\n}\n\n/**\n * The collection an STI subtype shares with its STI base, for a class that\n * registers with no manifest `collection` (#3125). The manifest generator\n * gives every STI subtype its base's collection (`findSTIBase`: the oldest\n * ancestor declaring `tableStrategy: 'sti'`); a subtype decorated before its\n * manifest loads — a consumer's bundled model chunk — must resolve the same\n * one, or permission slugs and route segments derived from it name a\n * collection nothing catalogues. Ancestors resolve by constructor identity, so\n * a same-named class in another package cannot stand in for the base.\n */\nfunction inheritedStiCollection(ctor: typeof SmrtObject): string | undefined {\n let base: RegisteredClass | undefined;\n for (\n let parent = Object.getPrototypeOf(ctor);\n parent && parent !== Function.prototype;\n parent = Object.getPrototypeOf(parent)\n ) {\n const key = getConstructorIndex().get(parent as typeof SmrtObject);\n const registered = key ? getClasses().get(key) : undefined;\n if (registered?.config?.tableStrategy === 'sti') base = registered;\n }\n return base?.collection;\n}\n\n/**\n * Shared bundled-context detector. Source files in these output\n * directories come from a bundler (Vite library mode, webpack, Next.js,\n * Nuxt, svelte-kit) that can duplicate module code across chunks.\n */\nexport function isBundledOutputPath(sourceFile: string | undefined): boolean {\n if (!sourceFile) return false;\n return (\n sourceFile.includes('.svelte-kit/output/') ||\n sourceFile.includes('/dist/') ||\n sourceFile.includes('/build/') ||\n sourceFile.includes('.next/') ||\n sourceFile.includes('.nuxt/')\n );\n}\n\nfunction normalizeSourcePath(path: string): string {\n return path\n .replace(/^file:\\/\\//, '')\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\//, '');\n}\n\nfunction isAbsoluteSourcePath(path: string): boolean {\n return path.startsWith('/') || /^[a-z]:\\//i.test(path);\n}\n\n/**\n * Directories a relative manifest `filePath` can be relative to: the scanned\n * project (the process's working directory) and its workspace root.\n */\nfunction relativeSourceRoots(): string[] {\n if (typeof process === 'undefined' || typeof process.cwd !== 'function') {\n return [];\n }\n const cwd = normalizeSourcePath(process.cwd());\n const workspaceRoot = findWorkspaceRootSync(process.cwd());\n return workspaceRoot && normalizeSourcePath(workspaceRoot) !== cwd\n ? [cwd, normalizeSourcePath(workspaceRoot)]\n : [cwd];\n}\n\n/**\n * Whether two source paths name the same file. A stack frame reports an\n * absolute path; a manifest's `filePath` is absolute or relative to the\n * project or workspace root it was scanned from (anytown scans\n * `packages/cloud-network/src/models/*.ts` into the dashboard's manifest,\n * #3110), so a relative path is resolved against those roots, never matched by\n * suffix alone.\n */\nexport function isSameSourcePath(\n left: string | undefined,\n right: string | undefined,\n): boolean {\n if (!left || !right) return false;\n const a = normalizeSourcePath(left);\n const b = normalizeSourcePath(right);\n if (a === b) return true;\n const aAbsolute = isAbsoluteSourcePath(a);\n const bAbsolute = isAbsoluteSourcePath(b);\n if (aAbsolute === bAbsolute) return false;\n const [absolute, relative] = aAbsolute ? [a, b] : [b, a];\n const path = getNodeBuiltins()?.path;\n if (!path) return false;\n // Platform `resolve` keeps a Windows drive-letter root absolute.\n return relativeSourceRoots().some(\n (root) => normalizeSourcePath(path.resolve(root, relative)) === absolute,\n );\n}\n\n/**\n * The package whose loaded manifest describes the class declared in\n * `sourceFile` — the class's identity when its nearest `package.json` is not\n * the package that scanned it (#3110). An app manifest commonly scans workspace\n * packages' sources under the app's own package name (anytown's\n * `packages/cloud-network` models are `@anytown/dashboard:*`), so the\n * stack-derived package of a source-consumed class (Vite dev server, Vitest,\n * tsx) never declares it.\n *\n * When several packages' entries describe the file, the stack-derived package\n * wins if it is one of them; otherwise a single candidate, or the one owned by\n * the manifest it appears in. Anything else is ambiguous and yields\n * `undefined`.\n */\nfunction findManifestPackageForSource(\n name: string,\n sourceFile: string | undefined,\n stackPackageName: string | undefined,\n): SourceManifestMatch | undefined {\n if (!sourceFile) return undefined;\n const manifests = new Set<SmartObjectManifest>();\n for (const manifest of [\n getLocalTestManifestCache(),\n getTestManifestCache(),\n getStaticManifestCache(),\n ...getManifestCache().values(),\n ]) {\n if (manifest?.objects) manifests.add(manifest);\n }\n\n const resolved = resolveSourceManifestPackage(\n name,\n sourceFile,\n stackPackageName,\n manifests,\n );\n if (resolved) return resolved;\n // No loaded manifest describes the file: a plain Node/tsx script has not\n // loaded the project's manifest yet (#3109).\n const projectManifest = readProjectManifestSync();\n return projectManifest?.objects && !manifests.has(projectManifest)\n ? resolveSourceManifestPackage(\n name,\n sourceFile,\n stackPackageName,\n new Set([projectManifest]),\n )\n : undefined;\n}\n\ninterface SourceManifestMatch {\n packageName: string;\n /** The describing entry, used when the package's own manifest is not loaded. */\n entry: SmartObjectDefinition;\n}\n\nfunction resolveSourceManifestPackage(\n name: string,\n sourceFile: string,\n stackPackageName: string | undefined,\n manifests: Set<SmartObjectManifest>,\n): SourceManifestMatch | undefined {\n const candidates = new Map<string, SmartObjectDefinition>();\n const ownedByTheirManifest = new Set<string>();\n for (const manifest of manifests) {\n for (const [key, entry] of Object.entries(manifest.objects)) {\n const qualified = isQualifiedName(key)\n ? parseQualifiedName(key)\n : undefined;\n const className = entry.className ?? qualified?.className ?? key;\n if (className !== name) continue;\n if (!isSameSourcePath(sourceFile, entry.filePath)) continue;\n const entryPackage =\n entry.packageName ?? qualified?.packageName ?? manifest.packageName;\n if (!entryPackage) continue;\n if (!candidates.has(entryPackage)) {\n candidates.set(entryPackage, { ...entry, packageName: entryPackage });\n }\n if (entryPackage === manifest.packageName) {\n ownedByTheirManifest.add(entryPackage);\n }\n }\n }\n\n const pick = (packageName: string): SourceManifestMatch => ({\n packageName,\n entry: candidates.get(packageName) as SmartObjectDefinition,\n });\n if (stackPackageName && candidates.has(stackPackageName)) {\n return pick(stackPackageName);\n }\n if (candidates.size === 1) return pick([...candidates.keys()][0]);\n if (ownedByTheirManifest.size === 1)\n return pick([...ownedByTheirManifest][0]);\n return undefined;\n}\n\n/**\n * Build `CollisionInputs` for the decorator-origin path (`register()`).\n * Manifest-origin inputs are built separately inside `registerFromManifest`.\n */\nfunction buildDecoratorCollisionInputs(args: {\n ctor: typeof SmrtObject;\n name: string;\n newPackageName: string | undefined;\n newSourceFile: string | undefined;\n newInBundledContext: boolean;\n newDeclaredTableName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n matchKind: MatchKind;\n}): CollisionInputs {\n const {\n ctor,\n name,\n newPackageName,\n newSourceFile,\n newInBundledContext,\n newDeclaredTableName,\n existing,\n existingKey,\n matchKind,\n } = args;\n const existingTableName =\n existing.schema?.tableName || existing.config?.tableName;\n\n let newExtendsExisting = false;\n let existingExtendsNew = false;\n try {\n newExtendsExisting = ctor.prototype instanceof existing.constructor;\n existingExtendsNew = existing.constructor.prototype instanceof ctor;\n } catch {\n // `instanceof` can throw for non-function constructors. Keep both false.\n }\n\n const bothSourceFilesKnown = !!(newSourceFile && existing.sourceFilePath);\n const sameSourceFile =\n bothSourceFilesKnown &&\n isSameSourcePath(newSourceFile, existing.sourceFilePath);\n const existingIsPackageQualified = !!existing.packageName?.startsWith('@');\n const samePackage =\n !!newPackageName &&\n !!existing.packageName &&\n newPackageName === existing.packageName;\n const hasNewQualifiedKey = !!newPackageName;\n const existingKeyIsQualified = isQualifiedName(existingKey);\n\n return {\n origin: 'decorator',\n matchKind,\n sameConstructor: existing.constructor === ctor,\n sameSourceFile,\n bothSourceFilesKnown,\n existingIsManifestStub:\n (existing.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true,\n newInBundledContext,\n newExtendsExisting,\n existingExtendsNew,\n samePackage,\n existingIsPackageQualified,\n sameName: name === existing.name,\n hasNewQualifiedKey,\n existingKeyIsQualified,\n existingHasAnyPackage: !!existing.packageName,\n // Manifest-only fields; filled with safe defaults for decorator origin.\n hasManifestContent: false,\n registrationKeyDiffersFromExistingKey: false,\n existingHasNoPackage: !existing.packageName,\n declaresDifferentTable:\n !!newDeclaredTableName &&\n !!existingTableName &&\n newDeclaredTableName !== existingTableName,\n };\n}\n\n/**\n * Execute the collision policy for `register()`. Returns `true` if the\n * policy resolved the collision (caller should return from `register`);\n * `false` means no policy match (the decision table is exhaustive so\n * that never actually happens — the default row throws).\n *\n * All state mutation (`upsertExistingEntry`, verboseLog) stays in this\n * caller-side helper; the policy function itself is pure.\n */\nfunction applyRegisterCollisionPolicy(args: {\n ctor: typeof SmrtObject;\n name: string;\n newPackageName: string | undefined;\n newSourceFile: string | undefined;\n newInBundledContext: boolean;\n newDeclaredTableName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n matchKind: MatchKind;\n upsertExistingEntry: (\n existingKey: string,\n existing: RegisteredClass,\n ) => string;\n}): boolean {\n const inputs = buildDecoratorCollisionInputs(args);\n const decision = decideCollisionPolicy(inputs);\n\n switch (decision.policy) {\n case 'accept':\n case 'replace': {\n // Both map to the same operation for the decorator path:\n // update the existing slot's constructor + metadata. `replace`\n // only differs in verboseLog flavor so a reviewer reading the log\n // can tell which scenario fired.\n const newKey = args.upsertExistingEntry(args.existingKey, args.existing);\n if (\n decision.scenario === 'sti-child-wins' ||\n decision.scenario === 'manifest-stub-replacement'\n ) {\n verboseLog(\n `[registry] ${decision.scenario}: '${args.name}' → key='${newKey}' (${decision.reason})`,\n );\n }\n return true;\n }\n case 'skip':\n verboseLog(\n `[registry] ${decision.scenario}: skipping '${args.name}' (${decision.reason})`,\n );\n return true;\n case 'throw': {\n const matchSuffix =\n args.matchKind === 'case-insensitive'\n ? ` (case-insensitive match with \"${args.existingKey}\")`\n : '';\n throw new Error(\n `SMRT Class Name Collision: \"${args.name}\"${matchSuffix}\\n\\n` +\n `A class with this name is already registered, but with a different constructor.\\n` +\n `This usually happens when:\\n` +\n ` 1. Multiple test files define classes with the same name\\n` +\n ` 2. Different packages export classes with the same name\\n\\n` +\n `The collision will cause the wrong field definitions to be used,\\n` +\n `leading to properties not being initialized correctly.\\n\\n` +\n `To fix:\\n` +\n ` - Use unique class names (e.g., ${args.name}_UniqueId)\\n` +\n ` - Or use @smrt({ name: 'unique_name' }) to override the registration name`,\n );\n }\n case 'coexist-qualified':\n // A different package's class: leave its entry alone and let the new\n // class register under its own qualified key (#3106).\n verboseLog(\n `[registry] ${decision.scenario}: '${args.name}' coexists with '${args.existingKey}' (${decision.reason})`,\n );\n return false;\n case 'merge-manifest':\n // Only reachable from the manifest path; if we somehow get here from\n // `register()`, something is miswired.\n throw new Error(\n `decideCollisionPolicy returned '${decision.policy}' for decorator origin (scenario: ${decision.scenario}). This is a bug.`,\n );\n }\n}\n\n/**\n * Build `CollisionInputs` for the manifest-origin path\n * (`registerFromManifest`). Manifest entries have string-based inheritance\n * (`objectDef.extends`) rather than prototype-based, and no real\n * constructor to compare — `sameConstructor` is always false here.\n */\nfunction buildManifestCollisionInputs(args: {\n name: string;\n objectDef: SmartObjectDefinition;\n packageName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n registrationKey: string;\n matchKind: MatchKind;\n}): CollisionInputs {\n const {\n name,\n objectDef,\n packageName,\n existing,\n existingKey,\n registrationKey,\n matchKind,\n } = args;\n const newClassName = objectDef.className || name;\n const newExtends = objectDef.extends;\n\n // When an incoming manifest's `extends` points at the existing entry,\n // OR the existing entry's `extends` points at the incoming class, we\n // have an STI inheritance relationship. Each side checks:\n // - the simple name of the other\n // - the key under which the other is registered\n // - a case-insensitive fallback\n //\n // The `existingKey` comparison is load-bearing for cross-package STI:\n // `existing.extends` is stored post-`qualifyExtendsName()`, so it may\n // be the fully-qualified parent key like `@pkg:Parent`. Without this\n // comparison, `existingExtendsNew` falsely reads as false and the\n // arriving parent manifest would be registered as a duplicate instead\n // of skipped. See the deep-review report on #1140 for the fix rationale.\n const newExtendsExisting = !!(\n newExtends &&\n (newExtends === existing.name ||\n newExtends === existingKey ||\n newExtends.toLowerCase() === existing.name.toLowerCase())\n );\n const existingExtendsNew = !!(\n existing.extends &&\n (existing.extends === newClassName ||\n existing.extends === name ||\n existing.extends === registrationKey ||\n existing.extends.toLowerCase() === newClassName.toLowerCase())\n );\n\n const newSourceFile = objectDef.filePath;\n const bothSourceFilesKnown = !!(newSourceFile && existing.sourceFilePath);\n const sameSourceFile =\n bothSourceFilesKnown && newSourceFile === existing.sourceFilePath;\n const existingIsPackageQualified = !!existing.packageName?.startsWith('@');\n const samePackage =\n !!packageName &&\n !!existing.packageName &&\n packageName === existing.packageName;\n\n return {\n origin: 'manifest',\n matchKind,\n sameConstructor: false,\n sameSourceFile,\n bothSourceFilesKnown,\n existingIsManifestStub:\n (existing.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true,\n newInBundledContext: false,\n newExtendsExisting,\n existingExtendsNew,\n samePackage,\n existingIsPackageQualified,\n sameName: newClassName === existing.name,\n hasNewQualifiedKey: isQualifiedName(registrationKey),\n existingKeyIsQualified: isQualifiedName(existingKey),\n existingHasAnyPackage: !!existing.packageName,\n hasManifestContent: !!(\n objectDef.fields ||\n objectDef.methods ||\n objectDef.schema ||\n objectDef.decoratorConfig\n ),\n registrationKeyDiffersFromExistingKey: registrationKey !== existingKey,\n existingHasNoPackage: !existing.packageName,\n declaresDifferentTable: false,\n };\n // Note: manifest-origin sets hasNewQualifiedKey from the final\n // registrationKey (not packageName) because registerFromManifest accepts\n // an objectDef.qualifiedName fallback when packageName is omitted —\n // deriving from packageName alone would miss that case and misroute the\n // coexistence rows. See PR #1140 review (Copilot P1 at line 287).\n}\n\n/**\n * Execute the collision policy for `registerFromManifest()`. Returns\n * `'return'` when the policy fully resolves the collision (caller should\n * early-return from `registerFromManifest`) or `'continue'` when the new\n * registration should proceed to the fresh-entry code below the collision\n * block (either a child-wins delete-then-register or a different-package\n * coexist-qualified scenario).\n *\n * Implements the `merge-manifest` contract end-to-end: fold fields via\n * `mergeManifestIntoExistingRegistration`, then conditionally alias the\n * existing entry under `registrationKey` when it differs from the\n * canonical key — both steps preserve `issue-951:144-200`.\n */\nfunction applyManifestCollisionPolicy(args: {\n name: string;\n objectDef: SmartObjectDefinition;\n packageName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n registrationKey: string;\n matchKind: MatchKind;\n}): 'return' | 'continue' {\n const inputs = buildManifestCollisionInputs(args);\n const decision = decideCollisionPolicy(inputs);\n\n switch (decision.policy) {\n case 'skip':\n verboseLog(\n `[registry] ${decision.scenario}: skipping manifest '${args.name}' (${decision.reason})`,\n );\n return 'return';\n case 'replace':\n // STI child-wins: delete existing so the new entry can register fresh.\n getClasses().delete(args.existingKey);\n verboseLog(\n `[registry] ${decision.scenario}: '${args.name}' replaces '${args.existingKey}' (${decision.reason})`,\n );\n return 'continue';\n case 'merge-manifest': {\n mergeManifestIntoExistingRegistration(\n args.existing,\n args.objectDef,\n args.packageName,\n );\n if (args.registrationKey !== args.existingKey) {\n const classes = getClasses();\n classes.set(args.registrationKey, args.existing);\n getConstructorIndex().set(\n args.existing.constructor,\n args.registrationKey,\n );\n }\n return 'return';\n }\n case 'coexist-qualified':\n // Both registrations live under their qualified keys; caller falls\n // through to register the new one fresh.\n return 'continue';\n case 'accept':\n // Manifest origin never returns 'accept' (that's a decorator-path\n // policy). Treat defensively as return-no-op.\n return 'return';\n case 'throw':\n // Manifest collisions default to skip, never throw — this branch is\n // unreachable from the manifest origin. Guard against future drift.\n throw new Error(\n `decideCollisionPolicy returned 'throw' for manifest origin (scenario: ${decision.scenario}). This is a bug.`,\n );\n }\n}\n\nfunction resolveTableName(\n ctor: typeof SmrtObject,\n name: string,\n config: SmartObjectConfig,\n): string {\n // A known package resolves by qualified identity so a same-named class in\n // another package cannot supply this one's table (#3098).\n const manifestEntry = config._manifest\n ? lookupRegistrationManifest(\n config._manifest,\n name,\n config.packageName,\n config._manifestKey,\n )\n : discoverManifestSync(\n config.packageName\n ? createQualifiedName(config.packageName, name)\n : name,\n );\n\n return (\n manifestEntry?.schema?.tableName ||\n manifestEntry?.decoratorConfig?.tableName ||\n config.tableName ||\n tableNameFromClass(ctor)\n );\n}\n\n/**\n * Whether `packageName` itself declares the class `qualifiedKey` names: it is\n * registered under that key (a manifest stub or an earlier registration), or\n * a manifest owned by that package describes it. A stack-derived package is\n * only trusted as a class's identity on this evidence — a consumer bundle\n * that inlined a dependency reports the consumer's package, whose manifest\n * describes the dependency's classes under the dependency's name (#3098).\n */\nfunction packageDeclaresClass(\n packageName: string,\n qualifiedKey: string,\n): boolean {\n if (getClasses().has(qualifiedKey)) return true;\n const entry = discoverManifestSync(qualifiedKey);\n return (\n !!entry &&\n (entry.packageName === undefined || entry.packageName === packageName)\n );\n}\n\nfunction lookupRegistrationManifest(\n manifest: SmartObjectManifest,\n name: string,\n _packageName: string | undefined,\n manifestKey: string | undefined,\n): SmartObjectDefinition | undefined {\n if (manifestKey) return manifest.objects[manifestKey];\n // `_manifest` predates generated keyed registrations and accepts package-less,\n // unqualified manifests. Preserve that public compatibility path. Generated\n // code supplies `_manifestKey`, which is validated before this lookup and is\n // therefore never resolved through the ambiguous simple-name index.\n return lookupInManifest(manifest, name);\n}\n\nfunction validateIsolatedRegistrationManifest(\n manifest: SmartObjectManifest,\n manifestKey: string,\n name: string,\n packageName: string,\n): SmartObjectDefinition {\n const entries = Object.entries(manifest.objects);\n const targetKey = createQualifiedName(packageName, name);\n const [actualKey, objectDef] = entries[0] ?? [];\n const keyMatchesIdentity =\n actualKey === name ||\n (isQualifiedName(actualKey || '') && actualKey === targetKey);\n const packageMatches =\n (!manifest.packageName || manifest.packageName === packageName) &&\n (!objectDef?.packageName || objectDef.packageName === packageName);\n\n if (\n entries.length !== 1 ||\n actualKey !== manifestKey ||\n !keyMatchesIdentity ||\n objectDef?.className !== name ||\n !packageMatches ||\n (objectDef?.qualifiedName !== undefined &&\n objectDef.qualifiedName !== targetKey)\n ) {\n throw new ConfigurationError(\n `Invalid isolated registration manifest for \"${targetKey}\".`,\n 'CONFIG_INVALID_ISOLATED_MANIFEST',\n { manifestKey, targetKey },\n );\n }\n return objectDef;\n}\n\n/**\n * Publish a `@smrt({ sensitive: true })` declaration to the change feed\n * (issue #2937).\n *\n * Declares **every candidate name**, not just one. The name a class declares\n * and the name its rows are recorded under can diverge: a manifest stub\n * derives the name from `decoratorConfig` but installs\n * `objectDef.schema.tableName`, and the merge path can overwrite\n * `existing.schema.tableName`. A declaration landing on a name nothing writes\n * under is a silent fail-open, and the set is monotonic, so a superset is the\n * safe direction. (The STI case — a child declaring `sensitive` while writing\n * to its base class's table — is closed authoritatively at the write path by\n * `isChangeFeedSensitiveWrite`, which sees the real name.)\n *\n * Only `true` is acted on: the sensitive set is one-way by design, so there is\n * nothing here to undo a previous declaration.\n */\n/**\n * Whether any config source declares the object credential-bearing (#2937).\n *\n * `sensitive` is one-way, so it is combined across sources with OR rather than\n * by spread precedence: only `=== true` carries meaning, and a `false` from any\n * source must never erase a `true` from another.\n */\nfunction anySensitive(...configs: (SmartObjectConfig | undefined)[]): boolean {\n return configs.some((config) => config?.sensitive === true);\n}\n\nfunction declareSensitiveTable(\n config: SmartObjectConfig,\n ...tableNames: (string | undefined)[]\n): void {\n if (config.sensitive !== true) return;\n for (const tableName of tableNames) {\n if (tableName) declareChangeFeedSensitiveTable(tableName);\n }\n}\n\n// The registry's class-level `sensitive` lookup, handed to the change feed so\n// its write path can ask about an instance's class without importing the\n// registry — `class.ts` already imports `change-feed.ts`, so the reverse edge\n// would be a cycle. Installed once at module load (#2937).\nsetChangeFeedSensitiveClassResolver((ctor) => {\n if (typeof ctor !== 'function') return false;\n const key = getConstructorIndex().get(ctor as typeof SmrtObject);\n if (!key) return false;\n return getClasses().get(key)?.config?.sensitive === true;\n});\n\nfunction setSmrtTableName(ctor: typeof SmrtObject, tableName: string): void {\n const existing = Object.getOwnPropertyDescriptor(ctor, 'SMRT_TABLE_NAME');\n if (existing?.value === tableName) {\n return;\n }\n\n Object.defineProperty(ctor, 'SMRT_TABLE_NAME', {\n value: tableName,\n writable: false,\n enumerable: false,\n configurable: true,\n });\n}\n\n/**\n * Attach the registry's qualified name to the constructor as a static\n * property. Mirrors the `SMRT_TABLE_NAME` pattern.\n *\n * Survives:\n * - Minification (the property is set on the constructor itself).\n * - HMR / module duplication / federated-module boundaries where the\n * `constructorIndex` WeakMap holds an older constructor identity than\n * the one a caller has in hand.\n *\n * Acts as a belt-and-suspenders fallback for runtime code that has a\n * constructor reference and wants its registry identity without going\n * through a Map lookup (e.g. `SmrtHierarchical._hierarchyCollection`).\n */\nfunction setSmrtQualifiedName(\n ctor: typeof SmrtObject,\n qualifiedName: string | undefined,\n): void {\n if (!qualifiedName) return;\n const existing = Object.getOwnPropertyDescriptor(ctor, '_smrtQualifiedName');\n if (existing?.value === qualifiedName) {\n return;\n }\n\n Object.defineProperty(ctor, '_smrtQualifiedName', {\n value: qualifiedName,\n writable: false,\n enumerable: false,\n configurable: true,\n });\n}\n\n/**\n * Register (or re-register) a class. Every registration can add, replace or\n * mutate a registered class in place, so it invalidates the generation-keyed\n * registry memos before and after (#3047) — including when it throws partway.\n */\nexport function register(\n ctor: typeof SmrtObject,\n config: SmartObjectConfig = {},\n): void {\n bumpRegistryGeneration();\n try {\n registerUntracked(ctor, config);\n } finally {\n bumpRegistryGeneration();\n }\n}\n\nfunction registerUntracked(\n ctor: typeof SmrtObject,\n config: SmartObjectConfig = {},\n): void {\n const name = config.name || ctor.name;\n const explicitPackageName = config.packageName;\n let promotedCollectionConstructor: RegisteredClass['collectionConstructor'];\n let promotedRuntimeConfig: SmartObjectConfig | undefined;\n let isolatedManifestEntry: SmartObjectDefinition | undefined;\n\n if (config._manifestKey) {\n if (!explicitPackageName || !config._manifest) {\n throw new ConfigurationError(\n 'Generated isolated manifest registration requires packageName and _manifest.',\n 'CONFIG_INVALID_ISOLATED_MANIFEST',\n );\n }\n isolatedManifestEntry = validateIsolatedRegistrationManifest(\n config._manifest,\n config._manifestKey,\n name,\n explicitPackageName,\n );\n // Validate before promotion removes or rewrites an existing exact\n // constructor registration. A generated isolated manifest is authoritative\n // for schema, so it cannot silently erase a live @TenantScoped contract.\n if (\n config.tenantScoped === undefined &&\n normalizeTenantScopedConfig(\n isolatedManifestEntry.decoratorConfig?.tenantScoped,\n ) === undefined &&\n getConstructorTenantScopedDeclarations().get(ctor)\n ) {\n throw new ConfigurationError(\n `Manifest for '${name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`,\n 'CONFIG_TENANT_MANIFEST_CONFLICT',\n );\n }\n }\n\n function upsertExistingEntry(\n existingKey: string,\n existing: RegisteredClass,\n ): string {\n const nextPackageName = explicitPackageName || existing.packageName;\n const nextKey = nextPackageName\n ? createQualifiedName(nextPackageName, name)\n : name;\n // Capture pre-mutation identity so descendants whose `extends` still\n // references the old name/qualifiedName are caught by the post-mutation\n // invalidation sweep (#1139 Gap 2).\n const previousIdentity = {\n name: existing.name,\n qualifiedName: existing.qualifiedName as string | undefined,\n };\n\n existing.name = name;\n existing.packageName = nextPackageName;\n bumpRegistryGeneration();\n existing.qualifiedName = nextPackageName\n ? (createQualifiedName(nextPackageName, name) as QualifiedClassName)\n : undefined;\n const nextTableName = resolveTableName(ctor, name, {\n ...existing.config,\n ...config,\n ...(nextPackageName ? { packageName: nextPackageName } : {}),\n });\n existing.config = {\n ...existing.config,\n ...config,\n tableName: nextTableName,\n // OR, never last-wins — see `anySensitive` (#2937). A re-registration\n // must not be able to clear a declaration a previous one made.\n ...(anySensitive(existing.config, config)\n ? { sensitive: true as const }\n : {}),\n };\n if (!existing.schema) {\n existing.schema = {\n ddl: '',\n indexes: [],\n triggers: [],\n tableName: nextTableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n };\n }\n existing.schema.tableName = nextTableName;\n // A manifest stub carries the manifest's `filePath` (a build-time source\n // path). Once a real class takes the entry over, later collision checks\n // compare against where that class actually loaded from (#3106).\n if (\n (existing.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true &&\n newSourceFile\n ) {\n existing.sourceFilePath = newSourceFile;\n }\n existing.constructor = ctor;\n setSmrtTableName(ctor, nextTableName);\n declareSensitiveTable(\n existing.config,\n nextTableName,\n existing.schema?.tableName,\n );\n setSmrtQualifiedName(ctor, existing.qualifiedName);\n\n if (existingKey !== nextKey) {\n const classes = getClasses();\n const existingAtNextKey = classes.get(nextKey);\n\n if (existingAtNextKey && existingAtNextKey !== existing) {\n throw new ConfigurationError(\n `Class registry collision while promoting \"${existingKey}\" to \"${nextKey}\". ` +\n 'A different class is already registered under the target key.',\n 'CONFIG_REGISTRY_PROMOTION_COLLISION',\n {\n existingKey,\n nextKey,\n className: name,\n },\n );\n }\n\n classes.delete(existingKey);\n classes.set(nextKey, existing);\n }\n\n getConstructorIndex().set(ctor, nextKey);\n\n // Release C follow-up #1139 Gap 2: we just mutated `existing.name`,\n // `existing.packageName`, `existing.qualifiedName`, `existing.config`,\n // `existing.constructor`, and `existing.schema.tableName`. Any\n // descendant whose cached `inheritedFields` was computed against the\n // prior identity now carries stale data. Invalidate `existing` and\n // every descendant whose `extends` matches the pre- or post-mutation\n // identity so the next field read re-merges from the current state.\n invalidateInheritanceEntries(existing, previousIdentity);\n\n return nextKey;\n }\n\n // Release C (#1134): collision resolution for both exact-match and\n // case-insensitive paths now routes through decideCollisionPolicy, which\n // consolidates the 11-branch if/else tree from pre-C.\n const newSourceFile = getSourceFileFromStack();\n const newInBundledContext = isBundledOutputPath(newSourceFile);\n\n // Generated consumer registration carries both an explicit package and the\n // exact constructor imported from the production bundle. Treat that pair as\n // authoritative identity: discard the earlier decorator registration (whose\n // runtime name/package may have been rewritten by bundling) and rebuild it\n // from the isolated manifest so fields, schema, and decorator config all\n // come from the correct object. This avoids guessing identity from paths,\n // names, or derived table names.\n const constructorKey = getConstructorIndex().get(ctor);\n const constructorEntry = constructorKey\n ? getClasses().get(constructorKey)\n : undefined;\n if (\n constructorKey &&\n constructorEntry &&\n Object.is(constructorEntry.constructor, ctor)\n ) {\n if (explicitPackageName && isolatedManifestEntry) {\n const targetKey = createQualifiedName(explicitPackageName, name);\n const targetEntry = getClasses().get(targetKey);\n const targetCollectionConstructor = targetEntry?.collectionConstructor;\n const targetIsManifestStub =\n targetEntry &&\n targetEntry !== constructorEntry &&\n (targetEntry.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true;\n\n if (\n targetEntry &&\n targetEntry !== constructorEntry &&\n !targetIsManifestStub\n ) {\n throw new ConfigurationError(\n `Class registry collision while promoting \"${constructorKey}\" to \"${targetKey}\". ` +\n 'A different class is already registered under the target key.',\n 'CONFIG_REGISTRY_PROMOTION_COLLISION',\n { existingKey: constructorKey, nextKey: targetKey, className: name },\n );\n }\n\n promotedCollectionConstructor =\n constructorEntry.collectionConstructor || targetCollectionConstructor;\n // Generated manifests are JSON data and cannot carry runtime-only\n // values such as function-valued lifecycle hooks. Preserve the exact\n // constructor's decorator-time config as the lowest-priority layer;\n // the authoritative manifest and explicit generated config still win\n // for serializable identity, schema, and policy fields.\n promotedRuntimeConfig = constructorEntry.config;\n getClasses().delete(constructorKey);\n getConstructorIndex().delete(ctor);\n if (targetIsManifestStub && targetEntry) {\n getClasses().delete(targetKey);\n getConstructorIndex().delete(targetEntry.constructor);\n }\n } else {\n upsertExistingEntry(constructorKey, constructorEntry);\n return;\n }\n }\n\n // The class's package identity: an explicit `packageName`; else the\n // package owning the declaring file (stack-derived) when that package\n // declares the class; else the package whose loaded manifest describes the\n // declaring file (a workspace package's source scanned into an app's\n // manifest, #3110); else the stack-derived package, unconfirmed.\n const stackPackageName = explicitPackageName\n ? undefined\n : getPackageName(ctor, true) || undefined;\n const stackPackageDeclaresClass =\n !!stackPackageName &&\n packageDeclaresClass(\n stackPackageName,\n createQualifiedName(stackPackageName, name),\n );\n const sourceManifestPackage =\n explicitPackageName || stackPackageDeclaresClass\n ? undefined\n : findManifestPackageForSource(name, newSourceFile, stackPackageName);\n const newPackageName =\n explicitPackageName ||\n sourceManifestPackage?.packageName ||\n stackPackageName;\n\n // #3098: when this constructor's own package is known and that package\n // declares this class (its manifest stub or an earlier registration sits\n // under the qualified key, or its manifest describes it), never adopt\n // another package's same-named registration below — `Account` exists in\n // both smrt-ledgers and smrt-messages, and a simple-name match would hand\n // one package's constructor the other's fields and table.\n const ownQualifiedKey = newPackageName\n ? createQualifiedName(newPackageName, name)\n : undefined;\n const ownPackageDeclaresClass =\n !!ownQualifiedKey &&\n (!!explicitPackageName ||\n stackPackageDeclaresClass ||\n !!sourceManifestPackage);\n const belongsToAnotherPackage = (existing: RegisteredClass): boolean =>\n ownPackageDeclaresClass &&\n !!existing.packageName &&\n existing.packageName !== newPackageName;\n\n // 1. Exact-match check (existingKey === name)\n const exactExisting = getClasses().get(name);\n if (exactExisting && !belongsToAnotherPackage(exactExisting)) {\n const existing = exactExisting;\n const handled = applyRegisterCollisionPolicy({\n ctor,\n name,\n newPackageName,\n newSourceFile,\n newInBundledContext,\n newDeclaredTableName: config.tableName,\n existing,\n existingKey: name,\n matchKind: 'exact-key',\n upsertExistingEntry,\n });\n if (handled) return;\n }\n\n // 2. Case-insensitive check for manifest stubs (Issue #531, #847) and\n // other same-name-different-case collisions.\n const lowerName = name.toLowerCase();\n for (const [existingKey, existing] of getClasses().entries()) {\n const keyMatches = existingKey.toLowerCase() === lowerName;\n const nameMatches = existing.name?.toLowerCase() === lowerName;\n if (!(keyMatches || nameMatches) || existingKey === name) continue;\n\n // Distinct explicitly named packages are intentionally allowed to export\n // the same simple class name. Their qualified keys are unambiguous; do not\n // route them through the bundled-duplicate collision policy.\n if (\n explicitPackageName &&\n existing.packageName &&\n explicitPackageName !== existing.packageName &&\n isQualifiedName(existingKey)\n ) {\n continue;\n }\n // The same holds for a package identity the registry already knows this\n // class under (see ownPackageDeclaresClass above, #3098).\n if (belongsToAnotherPackage(existing)) {\n continue;\n }\n\n const handled = applyRegisterCollisionPolicy({\n ctor,\n name,\n newPackageName,\n newSourceFile,\n newInBundledContext,\n newDeclaredTableName: config.tableName,\n existing,\n existingKey,\n matchKind: 'case-insensitive',\n upsertExistingEntry,\n });\n if (handled) return;\n }\n\n // CRITICAL: Capture package name NOW, while stack trace still shows external package\n // This is called from the @smrt() decorator during import, so the stack trace\n // includes the external package file path. Later calls won't have this context.\n // Skip registry check to avoid circular dependency - class isn't registered yet!\n // This solves issue #159 where external package manifests couldn't be loaded.\n const packageNameFromStack = newPackageName;\n\n // Capture source file path for collision detection during module re-evaluation\n // (Issue #555: Test isolation - class name collision during vitest collection)\n const sourceFilePath = getSourceFileFromStack();\n\n // Get field definitions from manifest\n // Priority order (Issue #270 Phase 1 - synchronous manifest loading):\n // 1. Explicitly provided manifest (_manifest parameter)\n // 2. Test manifests (for test classes)\n // 3. Static manifests (for core framework classes)\n // 4. Cached external manifests (if already loaded)\n // For external packages not yet loaded, manifest discovery happens lazily during schema generation\n // Issue #713: Use lookupInManifest for qualified name support\n // The simple-name entry is a last resort for a class with a known package\n // identity. It never applies while another package registers a class of\n // this name, and a stack-derived identity nothing confirmed (outside\n // bundled output, where the stack package is the declaring file's own) also\n // refuses an entry another package owns: an app manifest that declares a\n // dependency loads that dependency's manifest before any of its classes\n // register, and its same-named entry would otherwise hand a consumer class\n // the dependency's identity, fields and table (#3106). In bundled output\n // (where the stack package is the bundle's) the entry is refused only when\n // the table the decorator resolved for the class differs from the entry's.\n // A class whose package is unknown still refuses a packaged entry that\n // describes another file (#3112): bundled output keeps it, where the stack\n // cannot name the declaring package, as for a stack-derived identity.\n const unknownPackageManifestEntry = () => {\n const entry = discoverManifestSync(name);\n if (\n !entry?.packageName ||\n newInBundledContext ||\n isSameSourcePath(newSourceFile, entry.filePath)\n ) {\n return entry;\n }\n return undefined;\n };\n const simpleNameManifestFallback = () => {\n if (\n findClassesByName(name).some(\n (candidate) =>\n !!candidate.packageName && candidate.packageName !== newPackageName,\n )\n ) {\n return undefined;\n }\n const entry = discoverManifestSync(name);\n const foreignEntry =\n !!entry?.packageName && entry.packageName !== newPackageName;\n if (!foreignEntry) return entry;\n // Another package's entry describes this class only when it describes\n // this class's own file: a class scanned into another package's\n // manifest under that package's key (core's own fixtures with an\n // explicit `packageName`, #3098).\n if (isSameSourcePath(newSourceFile, entry?.filePath)) return entry;\n if (ownPackageDeclaresClass) return undefined;\n const entryTable =\n entry?.schema?.tableName || entry?.decoratorConfig?.tableName;\n const declaresOtherTable =\n !!config.tableName && !!entryTable && config.tableName !== entryTable;\n return !newInBundledContext || declaresOtherTable ? undefined : entry;\n };\n let manifestEntry: ReturnType<typeof lookupInManifest> | undefined;\n if (config._manifest) {\n manifestEntry = lookupRegistrationManifest(\n config._manifest,\n name,\n explicitPackageName,\n config._manifestKey,\n );\n }\n if (!manifestEntry) {\n // A class whose own package is known resolves its manifest by qualified\n // identity only; a simple-name lookup could return another package's\n // same-named class (#3098).\n // When that identity has no manifest entry (e.g. an explicit\n // `packageName` on a class scanned into another package's manifest), the\n // simple-name entry still applies unless another package registers a\n // class of this name.\n // The same guard applies to an unconfirmed package identity: another\n // package's same-named entry must not become this class's manifest\n // (#3106).\n manifestEntry = ownQualifiedKey\n ? (discoverManifestSync(ownQualifiedKey) ??\n sourceManifestPackage?.entry ??\n simpleNameManifestFallback())\n : unknownPackageManifestEntry();\n }\n const runtimeTenantScopedDeclaration =\n getConstructorTenantScopedDeclarations().get(ctor);\n if (\n manifestEntry &&\n config.tenantScoped === undefined &&\n normalizeTenantScopedConfig(manifestEntry.decoratorConfig?.tenantScoped) ===\n undefined &&\n runtimeTenantScopedDeclaration\n ) {\n throw new ConfigurationError(\n `Manifest for '${name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`,\n 'CONFIG_TENANT_MANIFEST_CONFLICT',\n );\n }\n const fields = new Map<string, RegisteredField>();\n const methods = new Map<string, MethodDefinition>();\n let packageName: string | undefined;\n\n verboseLog(\n `[registry] Registering ${name}: manifestEntry =`,\n manifestEntry ? 'found' : 'not found',\n );\n if (manifestEntry?.fields) {\n verboseLog(\n `[registry] Manifest has ${Object.keys(manifestEntry.fields).length} fields:`,\n Object.keys(manifestEntry.fields),\n );\n }\n\n if (manifestEntry?.fields) {\n // Use manifest fields (from build-time AST scanning)\n // Store field definitions as plain objects with nested options\n for (const [fieldName, fieldDef] of Object.entries(\n manifestEntry.fields,\n ) as [string, FieldDefinition][]) {\n // Build options object, only including defined values\n const options: Record<string, unknown> = { ...fieldDef._meta };\n if (fieldDef.required !== undefined) options.required = fieldDef.required;\n if (fieldDef.default !== undefined) options.default = fieldDef.default;\n if (fieldDef.description !== undefined)\n options.description = fieldDef.description;\n if (fieldDef.transient !== undefined)\n options.transient = fieldDef.transient;\n\n // Store field definition as plain object maintaining Field-like structure\n const field: RegisteredField = {\n type: fieldDef.type,\n };\n\n // Only include options if not empty\n if (Object.keys(options).length > 0) {\n field._meta = options;\n }\n\n // Preserve top-level flags from manifest\n if (fieldDef.transient !== undefined) {\n field.transient = fieldDef.transient;\n }\n if (fieldDef.required !== undefined) {\n field.required = fieldDef.required;\n }\n if (fieldDef.sensitive !== undefined) {\n field.sensitive = fieldDef.sensitive;\n }\n if (fieldDef.readonly !== undefined) {\n field.readonly = fieldDef.readonly;\n }\n if (fieldDef.readPermission !== undefined) {\n field.readPermission = fieldDef.readPermission;\n }\n\n // Hoist related to top level for relationship fields\n // Check both fieldDef.related (new manifests) and _meta.related (old manifests)\n if (fieldDef.related !== undefined) {\n field.related = fieldDef.related;\n } else if (options.related !== undefined) {\n // `related` carries the related class name (always a string at runtime).\n field.related = options.related as string;\n delete field._meta?.related;\n }\n\n fields.set(fieldName, field);\n }\n\n verboseLog(\n `[registry] ✅ Loaded ${fields.size} fields for ${name} from manifest`,\n );\n\n // Use packageName from manifest if available, otherwise from stack trace\n // Priority: explicit manifest > manifestEntry > stack trace\n packageName =\n explicitPackageName ||\n config._manifest?.packageName ||\n manifestEntry.packageName ||\n packageNameFromStack;\n } else {\n // No manifest found yet - use package name from stack trace\n // This will be used later by ensureManifestLoaded() to load the external manifest\n verboseLog(\n `[registry] ⚠️ No manifest entry for ${name} - fields will be loaded later`,\n );\n packageName = packageNameFromStack;\n }\n\n // Apply decorator metadata to override/extend manifest fields\n // Decorators take priority over AST-scanned types (Issue #316)\n const decoratorKey = isolatedManifestEntry ? ctor.name : name;\n // Only explicit string-only registrations are ownerless legacy metadata.\n // Public decorators also expose a simple-name inspection mirror, but that\n // mirror must never become another constructor's schema.\n const simpleDecorators = getLegacyFieldDecorators().get(decoratorKey);\n const constructorDecorators = getConstructorFieldDecorators().get(ctor);\n const decorators = new Map(simpleDecorators);\n for (const [fieldName, options] of constructorDecorators ?? []) {\n decorators.set(fieldName, { ...decorators.get(fieldName), ...options });\n }\n if (decorators && decorators.size > 0) {\n verboseLog(\n `[registry] Applying ${decorators.size} field decorators for ${name}`,\n );\n\n for (const [fieldName, decoratorOptions] of decorators) {\n // Typed read-view of the raw `Record<string, unknown>` decorator bag so\n // the member reads below narrow to the `RegisteredField` member types\n // they feed (instead of `unknown`). Same runtime object, type-only view.\n const opts: DecoratorFieldOptions = decoratorOptions;\n const existingField = fields.get(fieldName);\n\n if (existingField) {\n // Merge decorator options with manifest field\n // Decorator type takes priority over AST-scanned type\n const mergedMeta: FieldMeta = {\n ...existingField._meta,\n ...decoratorOptions,\n };\n const mergedField: RegisteredField = {\n type: opts.type || existingField.type,\n _meta: mergedMeta,\n };\n\n // Remove 'type' from _meta if it was moved to top level\n if (mergedMeta.type) {\n delete mergedMeta.type;\n }\n\n // Preserve top-level flags (transient, required, etc.)\n if (opts.transient !== undefined) {\n mergedField.transient = opts.transient;\n } else if (existingField.transient !== undefined) {\n mergedField.transient = existingField.transient;\n }\n if (opts.sensitive !== undefined) {\n mergedField.sensitive = opts.sensitive;\n } else if (existingField.sensitive !== undefined) {\n mergedField.sensitive = existingField.sensitive;\n }\n if (opts.readonly !== undefined) {\n mergedField.readonly = opts.readonly;\n } else if (existingField.readonly !== undefined) {\n mergedField.readonly = existingField.readonly;\n }\n if (typeof opts.readPermission === 'string') {\n mergedField.readPermission = opts.readPermission;\n } else if (typeof existingField.readPermission === 'string') {\n mergedField.readPermission = existingField.readPermission;\n }\n\n // Handle required flag: nullable fields should not be required\n if (opts.nullable === true) {\n // Nullable explicitly set to true means field is NOT required\n mergedField.required = false;\n mergedMeta.required = false;\n } else if (opts.required !== undefined) {\n mergedField.required = opts.required;\n } else if (existingField.required !== undefined) {\n mergedField.required = existingField.required;\n }\n\n // Hoist related to top level for relationship fields\n if (opts.related !== undefined) {\n mergedField.related = opts.related;\n delete mergedField._meta?.related;\n } else if (existingField.related !== undefined) {\n mergedField.related = existingField.related;\n }\n\n fields.set(fieldName, mergedField);\n verboseLog(\n `[registry] ✅ Merged decorator for ${fieldName}: type=${mergedField.type}`,\n );\n } else {\n // Decorator for field not in manifest - add it\n const newMeta: FieldMeta = decoratorOptions;\n const newField: RegisteredField = {\n type: opts.type || 'text',\n _meta: newMeta,\n };\n\n // Set top-level flags from decorator options\n if (opts.transient !== undefined) {\n newField.transient = opts.transient;\n }\n if (opts.sensitive !== undefined) {\n newField.sensitive = opts.sensitive;\n }\n if (opts.readonly !== undefined) {\n newField.readonly = opts.readonly;\n }\n if (typeof opts.readPermission === 'string') {\n newField.readPermission = opts.readPermission;\n }\n // Handle required flag: nullable fields should not be required\n if (opts.nullable === true) {\n newField.required = false;\n newMeta.required = false;\n } else if (opts.required !== undefined) {\n newField.required = opts.required;\n }\n\n // Hoist related to top level for relationship fields (Issue #746)\n // This is critical for getRelationshipMap() to detect relationships\n if (opts.related !== undefined) {\n newField.related = opts.related;\n delete newField._meta?.related;\n }\n\n fields.set(fieldName, newField);\n verboseLog(\n `[registry] ✅ Added field ${fieldName} from decorator: type=${opts.type || 'text'}`,\n );\n }\n }\n }\n\n // Handle tenantScoped configuration (Issue #688)\n // External manifests can carry tenantScoped only in decoratorConfig, so\n // registration must honor the merged view rather than only explicit config.\n // `@TenantScoped()` is intentionally implemented by smrt-tenancy, not core;\n // when a standalone runtime imports an external model before its manifest is\n // cached, the tenant field decorator is the core-visible declaration of that\n // contract. Preserve it here so runtime registration and the manifest path\n // agree on the conflict target (#2763).\n let tenantScopedConfig: RegisteredClass['tenantScopedConfig'] | undefined;\n const constructorTenantScopedDeclaration = manifestEntry\n ? undefined\n : (runtimeTenantScopedDeclaration as\n | RegisteredClass['tenantScopedConfig']\n | undefined);\n const fieldTenantScopedConfig = tenantScopedConfigFromFieldMetadata(fields);\n const tenantScopedConfigSource: RegisteredClass['tenantScopedConfigSource'] =\n config.tenantScoped !== undefined\n ? 'explicit'\n : manifestEntry?.decoratorConfig?.tenantScoped !== undefined\n ? 'manifest'\n : manifestEntry\n ? 'manifest'\n : constructorTenantScopedDeclaration\n ? 'tenant-decorator'\n : fieldTenantScopedConfig\n ? 'field-fallback'\n : undefined;\n const effectiveTenantScoped =\n config.tenantScoped ??\n manifestEntry?.decoratorConfig?.tenantScoped ??\n (manifestEntry\n ? undefined\n : (constructorTenantScopedDeclaration ?? fieldTenantScopedConfig));\n if (effectiveTenantScoped) {\n tenantScopedConfig = normalizeTenantScopedConfig(effectiveTenantScoped);\n if (!tenantScopedConfig) return;\n\n // Inject or enrich tenantId field\n const fieldName = tenantScopedConfig.field;\n const hadTenantField = fields.has(fieldName);\n ensureTenantScopedField(fields, tenantScopedConfig);\n if (!hadTenantField) {\n verboseLog(\n `[registry] ✅ Injected ${fieldName} field for tenant-scoped class ${name}`,\n );\n }\n }\n\n if (manifestEntry?.methods) {\n // Load method definitions from manifest (for custom CLI/API/MCP generation)\n for (const [methodName, methodDef] of Object.entries(\n manifestEntry.methods,\n )) {\n methods.set(methodName, methodDef);\n }\n }\n\n // Also load methods from _manifestMethods in config (from consumer plugin register.js)\n // This is how external package methods are passed to the registry.\n // `_manifestMethods` is an undeclared escape-hatch carried on the config bag\n // by generated consumer `register.js`, so read it through a narrowed view.\n const manifestMethods = (\n config as unknown as {\n _manifestMethods?: Record<string, MethodDefinition>;\n }\n )._manifestMethods;\n if (manifestMethods) {\n for (const [methodName, methodDef] of Object.entries(manifestMethods)) {\n methods.set(methodName, methodDef);\n }\n verboseLog(\n `[registry] Loaded ${methods.size} methods for ${name} from _manifestMethods`,\n );\n }\n\n // Note: If manifest not found here, it will be loaded asynchronously when needed\n // via ensureManifestLoaded(). This allows decorators to remain synchronous while\n // supporting dynamic external package manifest loading.\n\n // Build inheritance chain from constructor (needed for STI table name resolution)\n const inheritanceChain = buildInheritanceChain(ctor);\n\n // Validate table strategy compatibility with parent (STI requirement)\n if (inheritanceChain.length > 1) {\n // This class has a parent - validate strategy compatibility\n const parentName = inheritanceChain[inheritanceChain.length - 2]; // Second-to-last is parent\n const parentEntry = findClass(parentName);\n\n // A framework base class (SmrtObject, SmrtHierarchical, SmrtJunction, …)\n // has no independent existence as a resource and carries no `@smrt()`\n // decorator of its own (see framework-base-classes.ts) — any table\n // strategy it appears to have once registered is just the registry's\n // undecorated-entry default, not an authored constraint later\n // subclasses must match. Every other one of this identity check's nine\n // existing call sites already exempts these classes; this STI-strategy\n // consistency check must too, or a framework base class that reaches\n // `ObjectRegistry` before its first concrete decorated descendant (e.g.\n // via #2750's worker-side manifest bulk-registration bulk-loading\n // `@happyvertical/smrt-core`'s manifest, which lists every class\n // extending `SmrtObject` including undecorated abstract bases) makes\n // that descendant's OWN, correctly-declared `tableStrategy` look like a\n // mismatch against its abstract parent's meaningless placeholder one.\n const parentIsFrameworkBase =\n parentEntry !== undefined &&\n isFrameworkBaseClass(parentEntry.name, parentEntry.packageName);\n\n if (parentEntry && !parentIsFrameworkBase) {\n const parentStrategy = parentEntry.config?.tableStrategy || 'default';\n const childStrategy = config.tableStrategy; // Don't default - undefined means inherit\n\n // Only validate if child has an EXPLICIT strategy that differs from parent\n // undefined childStrategy means it will inherit from parent\n if (childStrategy !== undefined && parentStrategy !== childStrategy) {\n throw ConfigurationError.incompatibleStrategy(\n name,\n childStrategy,\n parentName,\n parentStrategy,\n );\n }\n }\n }\n\n // Defer schema generation until needed (generateSchema now uses dynamic import)\n // Store table name for lazy schema generation\n // Priority for STI: manifest's tableName > decorator config > derived from class name\n // The manifest's tableName is computed at build-time when full class hierarchy is known,\n // which correctly handles STI inheritance. The decorator may derive wrong tableName\n // if parent class isn't registered yet at decorator execution time.\n // The table comes from the manifest entry selected above, which already\n // refuses another package's same-named entry: a fresh simple-name lookup\n // here bound a consumer's `LicenseSale` (`license_sales`) to smrt-commerce's\n // `contracts` table (#3106).\n const tableName =\n manifestEntry?.schema?.tableName ||\n manifestEntry?.decoratorConfig?.tableName ||\n config.tableName ||\n tableNameFromClass(ctor);\n setSmrtTableName(ctor, tableName);\n\n // Load pre-generated schema from manifest if available, otherwise placeholder\n let schema: SchemaDefinition;\n if (manifestEntry?.schema) {\n // Pre-generated schema from manifest (build-time)\n // Keep indexes as IndexDefinition objects for DDL strategies\n schema = {\n ddl: manifestEntry.schema.ddl,\n indexes:\n manifestEntry.schema.indexes?.map((idx: IndexDefinition) => ({\n name: idx.name,\n columns: idx.columns || [],\n unique: idx.unique || false,\n ...(idx.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: idx.where,\n description: idx.description,\n jsonPath: idx.jsonPath,\n })) || [],\n triggers: [],\n tableName: manifestEntry.schema.tableName || tableName,\n // Cast manifest columns to ColumnDefinition (same shape, TypeScript just needs help)\n columns: cloneManifestSchemaColumns(manifestEntry.schema.columns),\n foreignKeys: [],\n dependencies: [],\n version: manifestEntry.schema.version || '',\n packageName: manifestEntry.packageName,\n };\n verboseLog(\n `[registry] Loaded pre-generated schema for ${name} (${Object.keys(manifestEntry.schema.columns || {}).length} columns)`,\n );\n } else {\n // Placeholder schema - will be generated lazily when first needed\n schema = {\n ddl: '', // Generated lazily\n indexes: [], // Parsed from DDL lazily\n triggers: [], // No longer using database triggers - timestamps managed by application\n tableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n packageName: undefined,\n };\n }\n\n if (schema.columns) {\n applySqlTypeOverrides(schema.columns, fields.entries());\n if (decorators && decorators.size > 0) {\n applySqlTypeOverrides(schema.columns, decorators.entries());\n }\n }\n\n // Use pre-computed validation rules from manifest if available (Issue #782)\n // For decorator-based registration, manifest may have pre-computed rules\n const validationRules = manifestEntry?.validationRules;\n let validators: ValidatorFunction[] | undefined;\n\n // Only compile validators if no pre-computed rules exist\n if (validationRules === undefined) {\n validators = compileValidators(name, fields);\n } else {\n verboseLog(\n `[registry] Using ${validationRules.length} pre-computed validation rules for ${name}`,\n );\n }\n\n // Derive extends from prototype chain if not available from manifest\n // This is critical for inline test classes that use decorators\n let extendsClass: string | undefined = manifestEntry?.extends;\n if (!extendsClass) {\n const proto = Object.getPrototypeOf(ctor);\n if (proto?.name && proto.name !== 'SmrtObject' && proto.name !== 'Object') {\n extendsClass = proto.name;\n }\n }\n\n // Merge manifest's decoratorConfig into config\n // Use the computed tableName which prioritizes manifest's value for STI correctness\n const mergedConfig = {\n ...promotedRuntimeConfig,\n ...manifestEntry?.decoratorConfig,\n ...config,\n tableName, // Override with correctly computed tableName\n // `sensitive` is an OR across every source, not last-wins (#2937). Ordinary\n // spread precedence would let an explicit `sensitive: false` from a\n // lower-priority-but-later source erase a `true` — for instance a stale\n // manifest disagreeing with the class — which is a silent fail-OPEN in a\n // control documented as one-way (\"`sensitive: false` is not an opt-out\").\n // Only `=== true` is meaningful anywhere, so OR is the whole rule.\n ...(anySensitive(\n promotedRuntimeConfig,\n manifestEntry?.decoratorConfig,\n config,\n )\n ? { sensitive: true as const }\n : {}),\n };\n\n // Declare from the MERGED config, not the raw one: generated consumer\n // registration passes the declaration through `manifestEntry.decoratorConfig`\n // rather than the call's own `config` (#2937). Both the resolved name and the\n // schema's own, which can differ.\n declareSensitiveTable(\n mergedConfig,\n tableName,\n schema?.tableName,\n manifestEntry?.schema?.tableName,\n );\n\n // Generate qualified name if we have a package name\n // Format: \"@package/name:ClassName\"\n const qualifiedName = packageName\n ? createQualifiedName(packageName, name)\n : undefined;\n\n // Determine visibility from config, manifest, or default to 'public'\n // Priority: explicit config > manifest > default\n const visibility: SmrtVisibility =\n config.visibility || manifestEntry?.visibility || 'public';\n\n // Issue #951: Use qualified name as primary key when available\n const registrationKey = qualifiedName || name;\n\n getClasses().set(registrationKey, {\n name,\n qualifiedName, // Qualified name for cross-package identification\n constructor: ctor,\n config: mergedConfig,\n fields,\n methods,\n schema,\n validators,\n validationRules, // Pre-computed rules from manifest (Issue #782)\n tools: manifestEntry?.tools, // AI-callable tool schemas (CLI param schemas)\n // Pluralized endpoint name. Prefer the manifest's computed value (handles\n // STI inheritance + any future inflection changes); fall back to the same\n // simple pluralization the scanner uses for inline/test classes that have\n // no manifest entry. (smrt#1311.) An STI subtype with no manifest entry\n // takes its registered STI base's, as the manifest would (#3125).\n collection:\n manifestEntry?.collection ??\n inheritedStiCollection(ctor) ??\n pluralizeCollection(name),\n collectionConstructor: promotedCollectionConstructor,\n packageName, // Store package name from manifest for getPackageName() lookup\n sourceFilePath, // Store source file for collision detection (Issue #555)\n extends: extendsClass, // Capture parent class name from manifest OR prototype chain\n extendsTypeArg: manifestEntry?.extendsTypeArg, // SmrtCollection<T> generic arg\n tenantScopedConfig, // Multi-tenancy config (Issue #688)\n tenantScopedConfigSource,\n visibility, // Visibility control for manifest filtering\n // NOTE: Don't pre-compute inheritanceChain here - let getInheritanceChain() compute\n // it lazily using the `extends` field. This ensures correct chain for both\n // decorator-registered and manifest-loaded classes.\n });\n\n // Release B (#1133): case-insensitive lookups iterate the classes Map\n // directly instead of maintaining a parallel classNameMap index.\n\n // Index constructor for O(1) reverse lookups (Issue #713: constructor-based lookup)\n getConstructorIndex().set(ctor, registrationKey);\n // Stamp the qualified name on the constructor itself as a fallback for\n // runtime code that has a constructor reference but might hit a\n // WeakMap miss (HMR / federated modules / multiple-copy edge cases).\n setSmrtQualifiedName(ctor, qualifiedName);\n\n verboseLog(\n `🎯 Registered smrt object: ${name} (key: ${registrationKey}) with schema for ${schema.tableName} and ${(validators?.length || 0) + (validationRules?.length || 0)} validators/rules`,\n );\n\n // STI sibling auto-loading (Issue #430)\n // When a class is registered that shares a table with other classes (STI),\n // we need to discover and register ALL siblings so that getAllSchemas()\n // can merge columns from all subtypes for the database adapter.\n //\n // IMPORTANT: Only auto-load siblings from EXTERNAL packages.\n // For test classes or classes in the same package, they will be registered\n // by their own @smrt() decorators. Auto-loading them as stubs would cause collisions.\n const collection = manifestEntry?.collection;\n if (collection && !getStiSiblingsLoaded().has(collection)) {\n // Mark this collection as processed to prevent infinite recursion\n getStiSiblingsLoaded().add(collection);\n\n verboseLog(\n `[registry] Checking for STI siblings for collection: ${collection}`,\n );\n\n // Discover all classes that share this collection (table)\n const siblings = discoverSTISiblingsSync(collection);\n\n // Register any siblings that aren't already registered\n // Only load siblings from DIFFERENT packages to avoid collisions with local classes\n for (const sibling of siblings) {\n // Use case-insensitive check to prevent registering 'Praeco' when 'praeco' exists\n if (!hasClassCaseInsensitive(sibling.className)) {\n // Skip siblings from the same package - they will be registered by their own decorators\n if (\n sibling.packageName &&\n packageName &&\n sibling.packageName === packageName\n ) {\n verboseLog(\n `[registry] Skipping STI sibling ${sibling.className} from same package: ${packageName}`,\n );\n continue;\n }\n\n verboseLog(\n `[registry] Auto-loading STI sibling: ${sibling.className} for collection: ${collection}`,\n );\n registerFromManifest(\n sibling.className,\n sibling.entry,\n sibling.packageName,\n );\n }\n }\n }\n}\n\n/**\n * Resolve the core-visible tenancy contract from a `@tenantId()` field when a\n * runtime registration has no manifest entry. `@TenantScoped()` lives in the\n * tenancy package, so core cannot import its registry without a cycle; the\n * field decorator runs before `@smrt()`. A nullable tenant identifier is the\n * runtime representation of optional tenancy used by that decorator.\n */\nfunction tenantScopedConfigFromFieldMetadata(\n fields: Map<string, RegisteredField>,\n): SmartObjectConfig['tenantScoped'] | undefined {\n for (const [fieldName, field] of fields) {\n const tenancy = field._meta?.__tenancy as\n | {\n isTenantIdField?: unknown;\n mode?: unknown;\n field?: unknown;\n autoFilter?: unknown;\n autoPopulate?: unknown;\n allowSuperAdminBypass?: unknown;\n }\n | undefined;\n if (tenancy?.isTenantIdField !== true) continue;\n\n return {\n mode:\n tenancy.mode === 'required'\n ? 'required'\n : tenancy.mode === 'optional' || field._meta?.nullable === true\n ? 'optional'\n : 'required',\n field: typeof tenancy.field === 'string' ? tenancy.field : fieldName,\n autoFilter: tenancy.autoFilter !== false,\n autoPopulate: tenancy.autoPopulate !== false,\n allowSuperAdminBypass: tenancy.allowSuperAdminBypass === true,\n };\n }\n return undefined;\n}\n\nexport function registerCollection(\n objectName: string,\n // `new (options: any) => SmrtCollection<any>` is the irreducible\n // collection-constructor shape (S4 #1579): the public\n // `ObjectRegistry.registerCollection` wrapper hands a non-generic constructor\n // of exactly this form, which is not assignable to the generic\n // `typeof SmrtCollection`. Mirrors `RegisteredClass.collectionConstructor`.\n collectionConstructor: NonNullable<RegisteredClass['collectionConstructor']>,\n): void {\n const registered = findClass(objectName);\n if (registered) {\n registered.collectionConstructor = collectionConstructor;\n }\n\n // The collections map stores `typeof SmrtCollection`; the runtime value is a\n // SmrtCollection subclass constructor. Bridge the loose constructor shape to\n // the map's element type without `any`.\n getCollections().set(\n objectName,\n collectionConstructor as unknown as Parameters<\n ReturnType<typeof getCollections>['set']\n >[1],\n );\n}\n\n// resolveManifestCollision was removed in Release C (#1134). Its three-branch\n// decision is now represented as explicit rows in the collision-policy\n// decision table — see `manifest-same-source-file`, `manifest-sti-child-wins`,\n// `manifest-sti-parent-skip`, `manifest-default-skip` scenarios in\n// packages/core/src/registry/collision-policy.ts.\n\ntype TenantScopedOptions = Exclude<\n SmartObjectConfig['tenantScoped'],\n boolean | undefined\n>;\n\nfunction normalizeTenantScopedConfig(\n tenantScoped: SmartObjectConfig['tenantScoped'],\n): RegisteredClass['tenantScopedConfig'] | undefined {\n if (!tenantScoped) {\n return undefined;\n }\n\n const tenantOpts: TenantScopedOptions =\n typeof tenantScoped === 'boolean' ? {} : tenantScoped;\n return {\n mode: tenantOpts.mode ?? 'required',\n field: tenantOpts.field ?? 'tenantId',\n autoFilter: tenantOpts.autoFilter ?? true,\n autoPopulate: tenantOpts.autoPopulate ?? true,\n allowSuperAdminBypass: tenantOpts.allowSuperAdminBypass ?? false,\n };\n}\n\nexport function ensureTenantScopedField(\n fields: Map<string, RegisteredField>,\n tenantScopedConfig: RegisteredClass['tenantScopedConfig'] | undefined,\n): void {\n if (!tenantScopedConfig) {\n return;\n }\n // Mutates a registered class's field map in place (#3047).\n bumpRegistryGeneration();\n\n const fieldName = tenantScopedConfig.field;\n const existingField = fields.get(fieldName);\n if (existingField) {\n fields.set(fieldName, {\n ...existingField,\n required:\n existingField.required ?? tenantScopedConfig.mode === 'required',\n _meta: {\n ...existingField._meta,\n reference: existingField._meta?.reference ?? 'Tenant',\n sqlType: 'UUID',\n __tenancy: {\n ...existingField._meta?.__tenancy,\n isTenantIdField: true,\n ...tenantScopedConfig,\n },\n },\n });\n return;\n }\n\n fields.set(fieldName, {\n type: 'foreignKey',\n related: 'Tenant',\n required: tenantScopedConfig.mode === 'required',\n _meta: {\n reference: 'Tenant',\n sqlType: 'UUID',\n __tenancy: {\n isTenantIdField: true,\n ...tenantScopedConfig,\n },\n },\n });\n}\n\nfunction mergeIndexDefinitions(\n existingIndexes: IndexDefinition[] | undefined,\n manifestIndexes: IndexDefinition[] | undefined,\n): IndexDefinition[] {\n const merged = [...(existingIndexes || [])];\n const seen = new Set(merged.map((index) => index?.name).filter(Boolean));\n\n for (const index of manifestIndexes || []) {\n if (!index?.name || seen.has(index.name)) {\n continue;\n }\n merged.push(index);\n seen.add(index.name);\n }\n\n return merged;\n}\n\n// cloneManifestSchemaColumns lives in ../manifest/store.ts — imported above.\n// (Hoisted out of the duplicate definition here and in registry.ts.)\n\n/**\n * Typed read-view of a raw decorator option bag.\n *\n * `getFieldDecorators()` stores decorator options as\n * `Map<string, Record<string, unknown>>`, so the individual reads come back as\n * `unknown` and won't narrow to the typed `RegisteredField` members they feed.\n * This interface re-types only the members the decorator-merge loop reads, with\n * exactly the target member types, and keeps the open index signature so a raw\n * `Record<string, unknown>` bag is assignable to it without `any`. (The bag's\n * runtime values are field-helper options; this view mirrors that contract.)\n */\ninterface DecoratorFieldOptions {\n type?: FieldDefinition['type'];\n required?: boolean;\n nullable?: boolean;\n transient?: boolean;\n sensitive?: boolean;\n readonly?: boolean;\n readPermission?: unknown;\n related?: string;\n [key: string]: unknown;\n}\n\n/**\n * Read-only field shape consumed by the SQL-type override helpers.\n *\n * `applySqlTypeOverrides` runs over two sources: the canonical\n * `Map<string, RegisteredField>` AND the raw decorator bag\n * (`Map<string, Record<string, unknown>>` from `getFieldDecorators()`). Both\n * satisfy this shape — every member is optional and the open index signature\n * matches both `RegisteredField`'s index signature and `Record<string, unknown>`\n * — so the helpers read the same overrides off either source without `any`.\n */\ninterface SqlTypeOverrideField {\n type?: unknown;\n sqlType?: unknown;\n __tenancy?: FieldMeta['__tenancy'];\n _meta?: FieldMeta;\n [key: string]: unknown;\n}\n\nfunction getReferenceKindFromFieldOptions(\n fieldOptions: SqlTypeOverrideField,\n): ColumnDefinition['referenceKind'] | undefined {\n if (\n fieldOptions?.__tenancy?.isTenantIdField ||\n fieldOptions?._meta?.__tenancy?.isTenantIdField\n ) {\n return 'tenantId';\n }\n\n if (fieldOptions?.type === 'foreignKey') {\n return 'foreignKey';\n }\n\n if (fieldOptions?.type === 'crossPackageRef') {\n return 'crossPackageRef';\n }\n\n return undefined;\n}\n\nfunction applySqlTypeOverrides(\n columns: Record<string, ColumnDefinition>,\n fieldEntries: Iterable<[string, SqlTypeOverrideField]> | undefined,\n): void {\n if (!fieldEntries) {\n return;\n }\n\n for (const [fieldName, fieldOptions] of fieldEntries) {\n const sqlType = fieldOptions?.sqlType ?? fieldOptions?._meta?.sqlType;\n const referenceKind = getReferenceKindFromFieldOptions(fieldOptions);\n if (!sqlType && !referenceKind) {\n continue;\n }\n\n const columnName = toSnakeCase(fieldName);\n const existingColumn = columns[columnName];\n if (!existingColumn) {\n continue;\n }\n\n columns[columnName] = {\n ...existingColumn,\n ...(sqlType\n ? { type: String(sqlType).toUpperCase() as ColumnDefinition['type'] }\n : {}),\n ...(referenceKind ? { referenceKind } : {}),\n };\n }\n}\n\n/**\n * Invalidate cached inheritance state (chain + inheritedFields +\n * inheritedMethods) on `existing` AND every descendant whose `extends` or\n * `inheritanceChain` references it.\n *\n * This covers both simple-name and qualified-name `extends` matches, which\n * is why `ObjectRegistry.invalidateInheritanceCache` delegates here (Release\n * C follow-up #1139 Gap 1 — the old recursive public helper only matched\n * `extends === className` by exact string, silently missing qualified\n * descendants like `@pkg:Parent`).\n *\n * `previousIdentity` is used by `upsertExistingEntry` (Gap 2): when a class\n * is promoted (its name/packageName/qualifiedName are mutated in place),\n * descendants registered against the pre-mutation identity need to be\n * invalidated too. Pass the pre-mutation `{ name, qualifiedName }` so this\n * sweep matches against both the old and new identity.\n *\n * Exported for the public `ObjectRegistry.invalidateInheritanceCache`\n * shim in registry.ts.\n */\nexport function invalidateInheritanceEntries(\n existing: RegisteredClass,\n previousIdentity?: {\n name?: string;\n qualifiedName?: string;\n },\n): void {\n bumpRegistryGeneration();\n const cache = getInheritanceCache();\n const affectedNames = new Set<string>();\n\n const remember = (name: string | undefined): void => {\n if (name) {\n affectedNames.add(name);\n }\n };\n\n const matchNames = new Set<string>();\n const rememberMatch = (name: string | undefined): void => {\n if (name) matchNames.add(name);\n };\n rememberMatch(existing.name);\n rememberMatch(existing.qualifiedName);\n rememberMatch(previousIdentity?.name);\n rememberMatch(previousIdentity?.qualifiedName);\n\n for (const name of matchNames) {\n remember(name);\n }\n\n for (const [key, candidate] of getClasses()) {\n const extendsMatches =\n !!candidate.extends && matchNames.has(candidate.extends);\n const chainMatches =\n !!candidate.inheritanceChain &&\n candidate.inheritanceChain.some((n) => matchNames.has(n));\n\n if (candidate === existing || extendsMatches || chainMatches) {\n candidate.inheritanceChain = undefined;\n candidate.inheritedFields = undefined;\n candidate.inheritedMethods = undefined;\n remember(key);\n remember(candidate.name);\n remember(candidate.qualifiedName);\n }\n }\n\n for (const name of affectedNames) {\n cache.delete(name);\n }\n}\n\nfunction mergeManifestIntoExistingRegistration(\n existing: RegisteredClass,\n objectDef: SmartObjectDefinition,\n packageName?: string,\n): void {\n const manifestConfig = objectDef.decoratorConfig || {};\n const runtimeTenantScopedDeclaration =\n getConstructorTenantScopedDeclarations().get(existing.constructor);\n if (\n existing.tenantScopedConfigSource !== 'explicit' &&\n normalizeTenantScopedConfig(manifestConfig.tenantScoped) === undefined &&\n runtimeTenantScopedDeclaration\n ) {\n throw new ConfigurationError(\n `Manifest for '${existing.qualifiedName || existing.name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`,\n 'CONFIG_TENANT_MANIFEST_CONFLICT',\n );\n }\n const manifestTableName =\n objectDef.schema?.tableName ||\n manifestConfig.tableName ||\n existing.schema?.tableName ||\n existing.config.tableName ||\n tableNameFromClass(existing.constructor);\n\n existing.config = {\n ...manifestConfig,\n ...existing.config,\n tableName: manifestTableName,\n // OR, never last-wins — see `anySensitive` (#2937).\n ...(anySensitive(manifestConfig, existing.config)\n ? { sensitive: true as const }\n : {}),\n };\n\n // The merge can move the recorded name onto the manifest's (#2937). Nothing\n // else on this path re-declares, so a sensitive class merged here would\n // otherwise keep its declaration on the pre-merge name only.\n declareSensitiveTable(\n existing.config,\n manifestTableName,\n objectDef.schema?.tableName,\n existing.schema?.tableName,\n );\n\n if (objectDef.fields) {\n for (const [fieldName, fd] of Object.entries(objectDef.fields)) {\n if (!existing.fields.has(fieldName)) {\n existing.fields.set(fieldName, createFieldFromManifest(fd));\n continue;\n }\n\n const existingField = existing.fields.get(fieldName);\n if (!existingField) {\n continue;\n }\n\n existing.fields.set(fieldName, mergeManifestField(existingField, fd));\n }\n }\n\n // An explicit core declaration remains authoritative. Otherwise a manifest\n // is authoritative even when it is silent: discard provisional decorator or\n // field-fallback tenancy so lazy manifest loading matches preloaded runtime.\n if (existing.tenantScopedConfigSource !== 'explicit') {\n const tenantScopedConfig = normalizeTenantScopedConfig(\n manifestConfig.tenantScoped,\n );\n existing.tenantScopedConfig = tenantScopedConfig;\n existing.tenantScopedConfigSource = 'manifest';\n if (tenantScopedConfig) {\n ensureTenantScopedField(existing.fields, tenantScopedConfig);\n }\n }\n\n if (objectDef.methods) {\n for (const [methodName, methodDef] of Object.entries(objectDef.methods)) {\n existing.methods.set(methodName, methodDef);\n }\n }\n\n if (objectDef.schema) {\n const manifestSchema: SchemaDefinition = {\n ddl: objectDef.schema.ddl || '',\n indexes:\n objectDef.schema.indexes?.map((idx: IndexDefinition) => ({\n name: idx.name,\n columns: idx.columns || [],\n unique: idx.unique || false,\n ...(idx.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: idx.where,\n description: idx.description,\n jsonPath: idx.jsonPath,\n })) || [],\n triggers: [],\n tableName: objectDef.schema.tableName || manifestTableName,\n columns: cloneManifestSchemaColumns(objectDef.schema.columns),\n foreignKeys: [],\n dependencies: [],\n version: objectDef.schema.version || '',\n packageName: packageName,\n };\n\n applySqlTypeOverrides(manifestSchema.columns, existing.fields.entries());\n\n existing.schema = {\n ...(existing.schema || {}),\n ...manifestSchema,\n tableName: manifestSchema.tableName,\n ddl: manifestSchema.ddl || existing.schema?.ddl || '',\n columns: {\n ...(existing.schema?.columns || {}),\n ...(manifestSchema.columns || {}),\n },\n indexes: mergeIndexDefinitions(\n existing.schema?.indexes,\n manifestSchema.indexes,\n ),\n packageName: packageName || existing.schema?.packageName,\n };\n } else if (!existing.schema) {\n existing.schema = {\n ddl: '',\n indexes: [],\n triggers: [],\n tableName: manifestTableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n packageName: packageName,\n };\n } else {\n existing.schema.tableName = manifestTableName;\n existing.schema.packageName = packageName || existing.schema.packageName;\n }\n\n if (objectDef.validationRules !== undefined) {\n existing.validationRules = objectDef.validationRules;\n existing.validators = undefined;\n } else if (!existing.validationRules && !existing.validators) {\n existing.validators = compileValidators(existing.name, existing.fields);\n }\n\n if (packageName) {\n existing.packageName = packageName;\n existing.qualifiedName = createQualifiedName(\n packageName,\n existing.name,\n ) as QualifiedClassName;\n } else if (!existing.packageName && objectDef.packageName) {\n existing.packageName = objectDef.packageName;\n }\n\n if (objectDef.extends) {\n existing.extends = packageName\n ? qualifyExtendsName(objectDef.extends, packageName)\n : objectDef.extends;\n }\n\n if (!existing.sourceFilePath && objectDef.filePath) {\n existing.sourceFilePath = objectDef.filePath;\n }\n\n // The manifest's collection is authoritative (it carries STI inheritance):\n // a class decorated before its manifest loaded registered a derived one,\n // which permission slugs and route segments would otherwise keep (#3125).\n if (objectDef.collection) {\n existing.collection = objectDef.collection;\n }\n\n existing.visibility =\n objectDef.visibility || manifestConfig.visibility || existing.visibility;\n invalidateInheritanceEntries(existing);\n}\n\nexport function registerFromManifest(\n name: string,\n objectDef: SmartObjectDefinition,\n manifestPackageName?: string,\n): void {\n // Same invalidation contract as register() (#3047).\n bumpRegistryGeneration();\n try {\n registerFromManifestUntracked(name, objectDef, manifestPackageName);\n } finally {\n bumpRegistryGeneration();\n }\n}\n\nfunction registerFromManifestUntracked(\n name: string,\n objectDef: SmartObjectDefinition,\n manifestPackageName?: string,\n): void {\n // Issue #2970: `manifestPackageName` identifies the package that owns the\n // manifest FILE this entry was read from, which is not always the package\n // that declares the class. A consumer app's generated `.smrt/manifest.json`\n // is an aggregate: it carries every consumed package's objects verbatim,\n // each keyed by its qualified name and each stating its own `packageName`.\n // Deriving identity from the file's owner re-attributed all of them to the\n // consumer, so a class reached through both that aggregate and its own\n // package's manifest became two registry entries under two packages and its\n // simple name went ambiguous in `findClassStrict()` — reported for\n // `SmrtHierarchical`, but true of any aggregated object.\n //\n // The entry's own declaration therefore wins; the caller's value stays as\n // the fallback for a local manifest whose entries name no package. This is\n // identity-based, so two packages genuinely declaring the same class name\n // still produce two entries and are still reported as ambiguous.\n const packageName = objectDef.packageName || manifestPackageName;\n\n // Issue #951: Compute simple class name and registration key early\n // `name` may be a qualified key from manifest (e.g., '@happyvertical/smrt-events:Event')\n // `simpleClassName` is always the plain class name (e.g., 'Event')\n const simpleClassName = objectDef.className || name;\n const qualifiedNameEarly = packageName\n ? createQualifiedName(packageName, simpleClassName)\n : objectDef.qualifiedName;\n const registrationKey = (qualifiedNameEarly || name) as string;\n\n // Release C (#1134): collision resolution routes through\n // decideCollisionPolicy. See collision-policy.ts for the 16-row decision\n // table; applyManifestCollisionPolicy below turns a policy into registry\n // mutations.\n //\n // Two collision checks, matching pre-C behavior:\n // 1. Canonical-name lookup (case-insensitive simple-name match; covers\n // issue #950's STI child-wins and issue #951's qualified coexistence).\n // 2. Exact-key match (handles re-registration with same qualified key).\n //\n // The ambiguous case (multiple existing entries share the simple name —\n // `getCanonicalClassName` returns undefined) is NOT fed through the table.\n // It falls through both checks into the new-registration code below,\n // preserving issue #951's coexistence semantics.\n const existingCanonical = getCanonicalClassName(simpleClassName);\n if (existingCanonical) {\n const existing = getClasses().get(existingCanonical);\n if (existing) {\n const outcome = applyManifestCollisionPolicy({\n name,\n objectDef,\n packageName,\n existing,\n existingKey: existingCanonical,\n registrationKey,\n matchKind: 'canonical-name',\n });\n if (outcome === 'return') return;\n // outcome === 'continue' means policy was replace (child-wins) or\n // coexist — fall through into the new-registration code below.\n }\n // else: stale map entry (key exists but class was removed) — allow registration\n }\n\n if (getClasses().has(registrationKey)) {\n const existing = getClasses().get(registrationKey);\n if (!existing) return;\n const outcome = applyManifestCollisionPolicy({\n name,\n objectDef,\n packageName,\n existing,\n existingKey: registrationKey,\n registrationKey,\n matchKind: 'exact-key',\n });\n if (outcome === 'return') return;\n }\n\n // Issue #1004: Qualify the `extends` value BEFORE inserting this class\n // into the classes Map. Otherwise qualifyExtendsName would iterate and\n // find the child's own entry, creating a circular extends chain\n // (e.g., @test/sports:TestEvent extends itself). Release B (#1133) swapped\n // the underlying classNameMap lookup for an iteration over `classes`, but\n // the ordering invariant still holds.\n const qualifiedExtends =\n objectDef.extends && packageName\n ? qualifyExtendsName(objectDef.extends, packageName)\n : objectDef.extends;\n\n // Release B (#1133): case-insensitive lookups iterate the classes Map\n // directly; no parallel classNameMap index to maintain.\n\n // Create stub constructor - not needed for CLI command generation\n // The CLI only needs metadata (fields, methods, config)\n // Mark as manifest stub so real class can replace it during decorator registration\n const stubConstructor = class extends SmrtObject {\n static readonly _isManifestStub = true;\n } as typeof SmrtObject;\n Object.defineProperty(stubConstructor, 'name', { value: simpleClassName });\n\n // Convert manifest field definitions to Field objects\n const fields = new Map<string, RegisteredField>();\n const decorators = getLegacyFieldDecorators().get(simpleClassName);\n if (objectDef.fields) {\n for (const [fieldName, fd] of Object.entries(objectDef.fields)) {\n fields.set(fieldName, createFieldFromManifest(fd));\n }\n }\n\n // Load method definitions\n const methods = new Map<string, MethodDefinition>();\n if (objectDef.methods) {\n for (const [methodName, methodDef] of Object.entries(objectDef.methods)) {\n methods.set(methodName, methodDef);\n }\n }\n\n // Get config from manifest\n const config = objectDef.decoratorConfig || {};\n const tableName = config.tableName || tableNameFromClass(stubConstructor);\n // A manifest-only registration (a consumed package's stub) still carries the\n // credential declaration, and is often the ONLY registration a consumer app\n // performs for that class (#2937). `tableName` here is derived from\n // `decoratorConfig`, while the schema installed below uses\n // `objectDef.schema.tableName` — declare both.\n declareSensitiveTable(config, tableName, objectDef.schema?.tableName);\n\n // Load pre-generated schema from manifest if available\n // This enables efficient external package consumption without runtime schema generation\n let schema: SchemaDefinition;\n if (objectDef.schema) {\n // Pre-generated schema from manifest (build-time)\n // Keep indexes as IndexDefinition objects for DDL strategies\n schema = {\n ddl: objectDef.schema.ddl,\n indexes:\n objectDef.schema.indexes?.map((idx: IndexDefinition) => ({\n name: idx.name,\n columns: idx.columns || [],\n unique: idx.unique || false,\n ...(idx.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: idx.where,\n description: idx.description,\n jsonPath: idx.jsonPath,\n })) || [],\n triggers: [],\n tableName: objectDef.schema.tableName,\n columns: cloneManifestSchemaColumns(objectDef.schema.columns),\n foreignKeys: [],\n dependencies: [],\n version: objectDef.schema.version || '',\n packageName: packageName,\n };\n applySqlTypeOverrides(schema.columns, fields.entries());\n applySqlTypeOverrides(schema.columns, decorators?.entries());\n verboseLog(\n `[registry] Loaded pre-generated schema for ${name} (${Object.keys(objectDef.schema.columns || {}).length} columns)`,\n );\n } else {\n // Placeholder schema - will be generated at runtime if needed\n schema = {\n ddl: '',\n indexes: [],\n triggers: [],\n tableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n packageName: packageName,\n };\n }\n\n // Use pre-computed validation rules from manifest if available (Issue #782)\n // This avoids compiling validator closures at runtime, reducing startup time\n const validationRules = objectDef.validationRules;\n let validators: ValidatorFunction[] | undefined;\n\n // Only compile validators if no pre-computed rules exist\n // (backward compatibility for older manifests)\n if (validationRules === undefined) {\n validators = compileValidators(name, fields);\n verboseLog(\n `[registry] No pre-computed rules for ${name}, compiled ${validators.length} validators`,\n );\n } else {\n verboseLog(\n `[registry] Using ${validationRules.length} pre-computed validation rules for ${name}`,\n );\n }\n\n // Issue #951: Use qualifiedNameEarly computed at the top of this function\n // (uses simpleClassName, not the manifest key which may already be qualified)\n const qualifiedName = qualifiedNameEarly;\n\n // Get visibility from manifest (defaults to 'public')\n const visibility: SmrtVisibility =\n objectDef.visibility || config.visibility || 'public';\n\n // Register in ObjectRegistry (metadata only, no collection constructor)\n // Manifest registration is for command discovery and help text.\n // Runtime execution requires real classes loaded from entry point.\n //\n // Issue #847: Use className from objectDef (simple name like 'Council') for the name\n // property, not the qualified name key. This enables getFields() lookups by simple\n // class name to work correctly. simpleClassName is defined earlier in this function.\n //\n // A manifest-loaded class carries `tenantScoped` only in its decorator\n // config; normalize it the way registerClass() does so the schema owner's\n // tenant column resolves for `getConflictColumns()` / `getTenantColumn()`\n // on this registration too (#2360). The manifest pipeline already\n // materialized the tenant field (`injectTenantScopedFields`), so the field\n // map is left as the manifest describes it.\n const tenantScopedConfig = normalizeTenantScopedConfig(config.tenantScoped);\n\n // Issue #951: Use registrationKey (qualified when available) as the primary key\n getClasses().set(registrationKey, {\n name: simpleClassName,\n qualifiedName, // Qualified name for cross-package identification\n constructor: stubConstructor,\n config,\n fields,\n methods,\n schema,\n tenantScopedConfig,\n validators,\n validationRules, // Pre-computed rules from manifest (Issue #782)\n tools: objectDef.tools, // AI-callable tool schemas (used for CLI param schemas)\n // Pluralized endpoint name; fall back to simple pluralization if a\n // (legacy) manifest lacks it. (smrt#1311.)\n collection: objectDef.collection ?? pluralizeCollection(simpleClassName),\n packageName,\n sourceFilePath: objectDef.filePath, // Store source file for collision detection (Issue #555)\n extends: qualifiedExtends, // Issue #1004: Pre-computed qualified parent\n extendsTypeArg: objectDef.extendsTypeArg, // SmrtCollection<T> generic arg\n visibility, // New: Visibility control for manifest filtering\n });\n // Tag the synthetic stub constructor with the qualified name so the\n // same constructor-side identity convention holds for manifest-loaded\n // classes as well as decorator-registered ones.\n setSmrtQualifiedName(stubConstructor, qualifiedName);\n\n verboseLog(\n `📦 Registered ${simpleClassName} from manifest (key: ${registrationKey}, ${fields.size} fields, ${methods.size} methods)`,\n );\n\n // STI sibling auto-loading (Issue #430)\n // When a class is registered that shares a table with other classes (STI),\n // we need to discover and register ALL siblings so that getAllSchemas()\n // can merge columns from all subtypes for the database adapter.\n //\n // IMPORTANT: Only auto-load siblings from EXTERNAL packages.\n // For test classes or classes in the same package, they will be registered\n // by their own @smrt() decorators. Auto-loading them as stubs would cause collisions.\n const collection = objectDef.collection;\n if (collection && !getStiSiblingsLoaded().has(collection)) {\n // Mark this collection as processed to prevent infinite recursion\n getStiSiblingsLoaded().add(collection);\n\n verboseLog(\n `[registry] Checking for STI siblings for collection: ${collection}`,\n );\n\n // Discover all classes that share this collection (table)\n const siblings = discoverSTISiblingsSync(collection);\n\n // Register any siblings that aren't already registered\n // Only load siblings from DIFFERENT packages to avoid collisions with local classes\n for (const sibling of siblings) {\n // Use case-insensitive check to prevent registering 'Praeco' when 'praeco' exists\n if (!hasClassCaseInsensitive(sibling.className)) {\n // Skip siblings from the same package - they will be registered by their own decorators\n if (\n sibling.packageName &&\n packageName &&\n sibling.packageName === packageName\n ) {\n verboseLog(\n `[registry] Skipping STI sibling ${sibling.className} from same package: ${packageName}`,\n );\n continue;\n }\n\n verboseLog(\n `[registry] Auto-loading STI sibling: ${sibling.className} for collection: ${collection}`,\n );\n registerFromManifest(\n sibling.className,\n sibling.entry,\n sibling.packageName,\n );\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuGA,SAAS,oBAAoB,WAA2B;CACtD,MAAM,QAAQ,UAAU,YAAY;CACpC,IAAI,MAAM,SAAS,GAAG,GAAG,OAAO,GAAG,MAAM,MAAM,GAAG,EAAE,EAAE;CACtD,IAAI,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,GAClE,OAAO,GAAG,MAAM;CAElB,IAAI,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,IAAI,GAAG,OAAO,GAAG,MAAM;CAClE,OAAO,GAAG,MAAM;AAClB;;;;;;;;;;;AAYA,SAAS,uBAAuB,MAA6C;CAC3E,IAAI;CACJ,KACE,IAAI,SAAS,OAAO,eAAe,IAAI,GACvC,UAAU,WAAW,SAAS,WAC9B,SAAS,OAAO,eAAe,MAAM,GACrC;EACA,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,MAA2B;EACjE,MAAM,aAAa,MAAM,WAAW,CAAC,CAAC,IAAI,GAAG,IAAI,KAAA;EACjD,IAAI,YAAY,QAAQ,kBAAkB,OAAO,OAAO;CAC1D;CACA,OAAO,MAAM;AACf;;;;;;AAOA,SAAgB,oBAAoB,YAAyC;CAC3E,IAAI,CAAC,YAAY,OAAO;CACxB,OACE,WAAW,SAAS,qBAAqB,KACzC,WAAW,SAAS,QAAQ,KAC5B,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,QAAQ,KAC5B,WAAW,SAAS,QAAQ;AAEhC;AAEA,SAAS,oBAAoB,MAAsB;CACjD,OAAO,KACJ,QAAQ,cAAc,EAAE,CAAC,CACzB,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,SAAS,EAAE;AACxB;AAEA,SAAS,qBAAqB,MAAuB;CACnD,OAAO,KAAK,WAAW,GAAG,KAAK,aAAa,KAAK,IAAI;AACvD;;;;;AAMA,SAAS,sBAAgC;CACvC,IAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,QAAQ,YAC3D,OAAO,CAAC;CAEV,MAAM,MAAM,oBAAoB,QAAQ,IAAI,CAAC;CAC7C,MAAM,gBAAgB,sBAAsB,QAAQ,IAAI,CAAC;CACzD,OAAO,iBAAiB,oBAAoB,aAAa,MAAM,MAC3D,CAAC,KAAK,oBAAoB,aAAa,CAAC,IACxC,CAAC,GAAG;AACV;;;;;;;;;AAUA,SAAgB,iBACd,MACA,OACS;CACT,IAAI,CAAC,QAAQ,CAAC,OAAO,OAAO;CAC5B,MAAM,IAAI,oBAAoB,IAAI;CAClC,MAAM,IAAI,oBAAoB,KAAK;CACnC,IAAI,MAAM,GAAG,OAAO;CACpB,MAAM,YAAY,qBAAqB,CAAC;CAExC,IAAI,cADc,qBAAqB,CACrB,GAAW,OAAO;CACpC,MAAM,CAAC,UAAU,YAAY,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;CACvD,MAAM,OAAO,gBAAgB,CAAC,EAAE;CAChC,IAAI,CAAC,MAAM,OAAO;CAElB,OAAO,oBAAoB,CAAC,CAAC,MAC1B,SAAS,oBAAoB,KAAK,QAAQ,MAAM,QAAQ,CAAC,MAAM,QAClE;AACF;;;;;;;;;;;;;;;AAgBA,SAAS,6BACP,MACA,YACA,kBACiC;CACjC,IAAI,CAAC,YAAY,OAAO,KAAA;CACxB,MAAM,4BAAY,IAAI,IAAyB;CAC/C,KAAK,MAAM,YAAY;EACrB,0BAA0B;EAC1B,qBAAqB;EACrB,uBAAuB;EACvB,GAAG,iBAAiB,CAAC,CAAC,OAAO;CAC/B,GACE,IAAI,UAAU,SAAS,UAAU,IAAI,QAAQ;CAG/C,MAAM,WAAW,6BACf,MACA,YACA,kBACA,SACF;CACA,IAAI,UAAU,OAAO;CAGrB,MAAM,kBAAkB,wBAAwB;CAChD,OAAO,iBAAiB,WAAW,CAAC,UAAU,IAAI,eAAe,IAC7D,6BACE,MACA,YACA,kCACA,IAAI,IAAI,CAAC,eAAe,CAAC,CAC3B,IACA,KAAA;AACN;AAQA,SAAS,6BACP,MACA,YACA,kBACA,WACiC;CACjC,MAAM,6BAAa,IAAI,IAAmC;CAC1D,MAAM,uCAAuB,IAAI,IAAY;CAC7C,KAAK,MAAM,YAAY,WACrB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,GAAG;EAC3D,MAAM,YAAY,gBAAgB,GAAG,IACjC,mBAAmB,GAAG,IACtB,KAAA;EAEJ,KADkB,MAAM,aAAa,WAAW,aAAa,SAC3C,MAAM;EACxB,IAAI,CAAC,iBAAiB,YAAY,MAAM,QAAQ,GAAG;EACnD,MAAM,eACJ,MAAM,eAAe,WAAW,eAAe,SAAS;EAC1D,IAAI,CAAC,cAAc;EACnB,IAAI,CAAC,WAAW,IAAI,YAAY,GAC9B,WAAW,IAAI,cAAc;GAAE,GAAG;GAAO,aAAa;EAAa,CAAC;EAEtE,IAAI,iBAAiB,SAAS,aAC5B,qBAAqB,IAAI,YAAY;CAEzC;CAGF,MAAM,QAAQ,iBAA8C;EAC1D;EACA,OAAO,WAAW,IAAI,WAAW;CACnC;CACA,IAAI,oBAAoB,WAAW,IAAI,gBAAgB,GACrD,OAAO,KAAK,gBAAgB;CAE9B,IAAI,WAAW,SAAS,GAAG,OAAO,KAAK,CAAC,GAAG,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE;CAChE,IAAI,qBAAqB,SAAS,GAChC,OAAO,KAAK,CAAC,GAAG,oBAAoB,CAAC,CAAC,EAAE;AAE5C;;;;;AAMA,SAAS,8BAA8B,MAUnB;CAClB,MAAM,EACJ,MACA,MACA,gBACA,eACA,qBACA,sBACA,UACA,aACA,cACE;CACJ,MAAM,oBACJ,SAAS,QAAQ,aAAa,SAAS,QAAQ;CAEjD,IAAI,qBAAqB;CACzB,IAAI,qBAAqB;CACzB,IAAI;EACF,qBAAqB,KAAK,qBAAqB,SAAS;EACxD,qBAAqB,SAAS,YAAY,qBAAqB;CACjE,QAAQ,CAER;CAEA,MAAM,uBAAuB,CAAC,EAAE,iBAAiB,SAAS;CAC1D,MAAM,iBACJ,wBACA,iBAAiB,eAAe,SAAS,cAAc;CACzD,MAAM,6BAA6B,CAAC,CAAC,SAAS,aAAa,WAAW,GAAG;CACzE,MAAM,cACJ,CAAC,CAAC,kBACF,CAAC,CAAC,SAAS,eACX,mBAAmB,SAAS;CAC9B,MAAM,qBAAqB,CAAC,CAAC;CAC7B,MAAM,yBAAyB,gBAAgB,WAAW;CAE1D,OAAO;EACL,QAAQ;EACR;EACA,iBAAiB,SAAS,gBAAgB;EAC1C;EACA;EACA,wBACG,SAAS,YACP,oBAAoB;EACzB;EACA;EACA;EACA;EACA;EACA,UAAU,SAAS,SAAS;EAC5B;EACA;EACA,uBAAuB,CAAC,CAAC,SAAS;EAElC,oBAAoB;EACpB,uCAAuC;EACvC,sBAAsB,CAAC,SAAS;EAChC,wBACE,CAAC,CAAC,wBACF,CAAC,CAAC,qBACF,yBAAyB;CAC7B;AACF;;;;;;;;;;AAWA,SAAS,6BAA6B,MAc1B;CAEV,MAAM,WAAW,sBADF,8BAA8B,IACN,CAAM;CAE7C,QAAQ,SAAS,QAAjB;EACE,KAAK;EACL,KAAK,WAAW;GAKd,MAAM,SAAS,KAAK,oBAAoB,KAAK,aAAa,KAAK,QAAQ;GACvE,IACE,SAAS,aAAa,oBACtB,SAAS,aAAa,6BAEtB,WACE,cAAc,SAAS,SAAS,KAAK,KAAK,KAAK,WAAW,OAAO,KAAK,SAAS,OAAO,EACxF;GAEF,OAAO;EACT;EACA,KAAK;GACH,WACE,cAAc,SAAS,SAAS,cAAc,KAAK,KAAK,KAAK,SAAS,OAAO,EAC/E;GACA,OAAO;EACT,KAAK,SAAS;GACZ,MAAM,cACJ,KAAK,cAAc,qBACf,kCAAkC,KAAK,YAAY,MACnD;GACN,MAAM,IAAI,MACR,+BAA+B,KAAK,KAAK,GAAG,YAAY,mZAQjB,KAAK,KAAK,wFAEnD;EACF;EACA,KAAK;GAGH,WACE,cAAc,SAAS,SAAS,KAAK,KAAK,KAAK,mBAAmB,KAAK,YAAY,KAAK,SAAS,OAAO,EAC1G;GACA,OAAO;EACT,KAAK,kBAGH,MAAM,IAAI,MACR,mCAAmC,SAAS,OAAO,oCAAoC,SAAS,SAAS,kBAC3G;CACJ;AACF;;;;;;;AAQA,SAAS,6BAA6B,MAQlB;CAClB,MAAM,EACJ,MACA,WACA,aACA,UACA,aACA,iBACA,cACE;CACJ,MAAM,eAAe,UAAU,aAAa;CAC5C,MAAM,aAAa,UAAU;CAe7B,MAAM,qBAAqB,CAAC,EAC1B,eACC,eAAe,SAAS,QACvB,eAAe,eACf,WAAW,YAAY,MAAM,SAAS,KAAK,YAAY;CAE3D,MAAM,qBAAqB,CAAC,EAC1B,SAAS,YACR,SAAS,YAAY,gBACpB,SAAS,YAAY,QACrB,SAAS,YAAY,mBACrB,SAAS,QAAQ,YAAY,MAAM,aAAa,YAAY;CAGhE,MAAM,gBAAgB,UAAU;CAChC,MAAM,uBAAuB,CAAC,EAAE,iBAAiB,SAAS;CAC1D,MAAM,iBACJ,wBAAwB,kBAAkB,SAAS;CACrD,MAAM,6BAA6B,CAAC,CAAC,SAAS,aAAa,WAAW,GAAG;CACzE,MAAM,cACJ,CAAC,CAAC,eACF,CAAC,CAAC,SAAS,eACX,gBAAgB,SAAS;CAE3B,OAAO;EACL,QAAQ;EACR;EACA,iBAAiB;EACjB;EACA;EACA,wBACG,SAAS,YACP,oBAAoB;EACzB,qBAAqB;EACrB;EACA;EACA;EACA;EACA,UAAU,iBAAiB,SAAS;EACpC,oBAAoB,gBAAgB,eAAe;EACnD,wBAAwB,gBAAgB,WAAW;EACnD,uBAAuB,CAAC,CAAC,SAAS;EAClC,oBAAoB,CAAC,EACnB,UAAU,UACV,UAAU,WACV,UAAU,UACV,UAAU;EAEZ,uCAAuC,oBAAoB;EAC3D,sBAAsB,CAAC,SAAS;EAChC,wBAAwB;CAC1B;AAMF;;;;;;;;;;;;;;AAeA,SAAS,6BAA6B,MAQZ;CAExB,MAAM,WAAW,sBADF,6BAA6B,IACL,CAAM;CAE7C,QAAQ,SAAS,QAAjB;EACE,KAAK;GACH,WACE,cAAc,SAAS,SAAS,uBAAuB,KAAK,KAAK,KAAK,SAAS,OAAO,EACxF;GACA,OAAO;EACT,KAAK;GAEH,WAAW,CAAC,CAAC,OAAO,KAAK,WAAW;GACpC,WACE,cAAc,SAAS,SAAS,KAAK,KAAK,KAAK,cAAc,KAAK,YAAY,KAAK,SAAS,OAAO,EACrG;GACA,OAAO;EACT,KAAK;GACH,sCACE,KAAK,UACL,KAAK,WACL,KAAK,WACP;GACA,IAAI,KAAK,oBAAoB,KAAK,aAAa;IAE7C,WAAA,CAAA,CAAQ,IAAI,KAAK,iBAAiB,KAAK,QAAQ;IAC/C,oBAAoB,CAAC,CAAC,IACpB,KAAK,SAAS,aACd,KAAK,eACP;GACF;GACA,OAAO;EAET,KAAK,qBAGH,OAAO;EACT,KAAK,UAGH,OAAO;EACT,KAAK,SAGH,MAAM,IAAI,MACR,yEAAyE,SAAS,SAAS,kBAC7F;CACJ;AACF;AAEA,SAAS,iBACP,MACA,MACA,QACQ;CAGR,MAAM,gBAAgB,OAAO,YACzB,2BACE,OAAO,WACP,MACA,OAAO,aACP,OAAO,YACT,IACA,qBACE,OAAO,cACH,oBAAoB,OAAO,aAAa,IAAI,IAC5C,IACN;CAEJ,OACE,eAAe,QAAQ,aACvB,eAAe,iBAAiB,aAChC,OAAO,aACP,mBAAmB,IAAI;AAE3B;;;;;;;;;AAUA,SAAS,qBACP,aACA,cACS;CACT,IAAI,WAAW,CAAC,CAAC,IAAI,YAAY,GAAG,OAAO;CAC3C,MAAM,QAAQ,qBAAqB,YAAY;CAC/C,OACE,CAAC,CAAC,UACD,MAAM,gBAAgB,KAAA,KAAa,MAAM,gBAAgB;AAE9D;AAEA,SAAS,2BACP,UACA,MACA,cACA,aACmC;CACnC,IAAI,aAAa,OAAO,SAAS,QAAQ;CAKzC,OAAO,iBAAiB,UAAU,IAAI;AACxC;AAEA,SAAS,qCACP,UACA,aACA,MACA,aACuB;CACvB,MAAM,UAAU,OAAO,QAAQ,SAAS,OAAO;CAC/C,MAAM,YAAY,oBAAoB,aAAa,IAAI;CACvD,MAAM,CAAC,WAAW,aAAa,QAAQ,MAAM,CAAC;CAC9C,MAAM,qBACJ,cAAc,QACb,gBAAgB,aAAa,EAAE,KAAK,cAAc;CACrD,MAAM,kBACH,CAAC,SAAS,eAAe,SAAS,gBAAgB,iBAClD,CAAC,WAAW,eAAe,UAAU,gBAAgB;CAExD,IACE,QAAQ,WAAW,KACnB,cAAc,eACd,CAAC,sBACD,WAAW,cAAc,QACzB,CAAC,kBACA,WAAW,kBAAkB,KAAA,KAC5B,UAAU,kBAAkB,WAE9B,MAAM,IAAI,mBACR,+CAA+C,UAAU,KACzD,oCACA;EAAE;EAAa;CAAU,CAC3B;CAEF,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAS,aAAa,GAAG,SAAqD;CAC5E,OAAO,QAAQ,MAAM,WAAW,QAAQ,cAAc,IAAI;AAC5D;AAEA,SAAS,sBACP,QACA,GAAG,YACG;CACN,IAAI,OAAO,cAAc,MAAM;CAC/B,KAAK,MAAM,aAAa,YACtB,IAAI,WAAW,gCAAgC,SAAS;AAE5D;AAMA,qCAAqC,SAAS;CAC5C,IAAI,OAAO,SAAS,YAAY,OAAO;CACvC,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,IAAyB;CAC/D,IAAI,CAAC,KAAK,OAAO;CACjB,OAAO,WAAW,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,QAAQ,cAAc;AACtD,CAAC;AAED,SAAS,iBAAiB,MAAyB,WAAyB;CAE1E,IADiB,OAAO,yBAAyB,MAAM,iBACnD,CAAA,EAAU,UAAU,WACtB;CAGF,OAAO,eAAe,MAAM,mBAAmB;EAC7C,OAAO;EACP,UAAU;EACV,YAAY;EACZ,cAAc;CAChB,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAS,qBACP,MACA,eACM;CACN,IAAI,CAAC,eAAe;CAEpB,IADiB,OAAO,yBAAyB,MAAM,oBACnD,CAAA,EAAU,UAAU,eACtB;CAGF,OAAO,eAAe,MAAM,sBAAsB;EAChD,OAAO;EACP,UAAU;EACV,YAAY;EACZ,cAAc;CAChB,CAAC;AACH;;;;;;AAOA,SAAgB,SACd,MACA,SAA4B,CAAC,GACvB;CACN,uBAAuB;CACvB,IAAI;EACF,kBAAkB,MAAM,MAAM;CAChC,UAAU;EACR,uBAAuB;CACzB;AACF;AAEA,SAAS,kBACP,MACA,SAA4B,CAAC,GACvB;CACN,MAAM,OAAO,OAAO,QAAQ,KAAK;CACjC,MAAM,sBAAsB,OAAO;CACnC,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,IAAI,OAAO,cAAc;EACvB,IAAI,CAAC,uBAAuB,CAAC,OAAO,WAClC,MAAM,IAAI,mBACR,gFACA,kCACF;EAEF,wBAAwB,qCACtB,OAAO,WACP,OAAO,cACP,MACA,mBACF;EAIA,IACE,OAAO,iBAAiB,KAAA,KACxB,4BACE,sBAAsB,iBAAiB,YACzC,MAAM,KAAA,KACN,uCAAuC,CAAC,CAAC,IAAI,IAAI,GAEjD,MAAM,IAAI,mBACR,iBAAiB,KAAK,2KACtB,iCACF;CAEJ;CAEA,SAAS,oBACP,aACA,UACQ;EACR,MAAM,kBAAkB,uBAAuB,SAAS;EACxD,MAAM,UAAU,kBACZ,oBAAoB,iBAAiB,IAAI,IACzC;EAIJ,MAAM,mBAAmB;GACvB,MAAM,SAAS;GACf,eAAe,SAAS;EAC1B;EAEA,SAAS,OAAO;EAChB,SAAS,cAAc;EACvB,uBAAuB;EACvB,SAAS,gBAAgB,kBACpB,oBAAoB,iBAAiB,IAAI,IAC1C,KAAA;EACJ,MAAM,gBAAgB,iBAAiB,MAAM,MAAM;GACjD,GAAG,SAAS;GACZ,GAAG;GACH,GAAI,kBAAkB,EAAE,aAAa,gBAAgB,IAAI,CAAC;EAC5D,CAAC;EACD,SAAS,SAAS;GAChB,GAAG,SAAS;GACZ,GAAG;GACH,WAAW;GAGX,GAAI,aAAa,SAAS,QAAQ,MAAM,IACpC,EAAE,WAAW,KAAc,IAC3B,CAAC;EACP;EACA,IAAI,CAAC,SAAS,QACZ,SAAS,SAAS;GAChB,KAAK;GACL,SAAS,CAAC;GACV,UAAU,CAAC;GACX,WAAW;GACX,SAAS,CAAC;GACV,aAAa,CAAC;GACd,cAAc,CAAC;GACf,SAAS;EACX;EAEF,SAAS,OAAO,YAAY;EAI5B,IACG,SAAS,YACP,oBAAoB,QACvB,eAEA,SAAS,iBAAiB;EAE5B,SAAS,cAAc;EACvB,iBAAiB,MAAM,aAAa;EACpC,sBACE,SAAS,QACT,eACA,SAAS,QAAQ,SACnB;EACA,qBAAqB,MAAM,SAAS,aAAa;EAEjD,IAAI,gBAAgB,SAAS;GAC3B,MAAM,UAAU,WAAW;GAC3B,MAAM,oBAAoB,QAAQ,IAAI,OAAO;GAE7C,IAAI,qBAAqB,sBAAsB,UAC7C,MAAM,IAAI,mBACR,6CAA6C,YAAY,QAAQ,QAAQ,mEAEzE,uCACA;IACE;IACA;IACA,WAAW;GACb,CACF;GAGF,QAAQ,OAAO,WAAW;GAC1B,QAAQ,IAAI,SAAS,QAAQ;EAC/B;EAEA,oBAAoB,CAAC,CAAC,IAAI,MAAM,OAAO;EASvC,6BAA6B,UAAU,gBAAgB;EAEvD,OAAO;CACT;CAKA,MAAM,gBAAgB,uBAAuB;CAC7C,MAAM,sBAAsB,oBAAoB,aAAa;CAS7D,MAAM,iBAAiB,oBAAoB,CAAC,CAAC,IAAI,IAAI;CACrD,MAAM,mBAAmB,iBACrB,WAAW,CAAC,CAAC,IAAI,cAAc,IAC/B,KAAA;CACJ,IACE,kBACA,oBACA,OAAO,GAAG,iBAAiB,aAAa,IAAI,GAE5C,IAAI,uBAAuB,uBAAuB;EAChD,MAAM,YAAY,oBAAoB,qBAAqB,IAAI;EAC/D,MAAM,cAAc,WAAW,CAAC,CAAC,IAAI,SAAS;EAC9C,MAAM,8BAA8B,aAAa;EACjD,MAAM,uBACJ,eACA,gBAAgB,oBACf,YAAY,YACV,oBAAoB;EAEzB,IACE,eACA,gBAAgB,oBAChB,CAAC,sBAED,MAAM,IAAI,mBACR,6CAA6C,eAAe,QAAQ,UAAU,mEAE9E,uCACA;GAAE,aAAa;GAAgB,SAAS;GAAW,WAAW;EAAK,CACrE;EAGF,gCACE,iBAAiB,yBAAyB;EAM5C,wBAAwB,iBAAiB;EACzC,WAAW,CAAC,CAAC,OAAO,cAAc;EAClC,oBAAoB,CAAC,CAAC,OAAO,IAAI;EACjC,IAAI,wBAAwB,aAAa;GACvC,WAAW,CAAC,CAAC,OAAO,SAAS;GAC7B,oBAAoB,CAAC,CAAC,OAAO,YAAY,WAAW;EACtD;CACF,OAAO;EACL,oBAAoB,gBAAgB,gBAAgB;EACpD;CACF;CAQF,MAAM,mBAAmB,sBACrB,KAAA,IACA,eAAe,MAAM,IAAI,KAAK,KAAA;CAClC,MAAM,4BACJ,CAAC,CAAC,oBACF,qBACE,kBACA,oBAAoB,kBAAkB,IAAI,CAC5C;CACF,MAAM,wBACJ,uBAAuB,4BACnB,KAAA,IACA,6BAA6B,MAAM,eAAe,gBAAgB;CACxE,MAAM,iBACJ,uBACA,uBAAuB,eACvB;CAQF,MAAM,kBAAkB,iBACpB,oBAAoB,gBAAgB,IAAI,IACxC,KAAA;CACJ,MAAM,0BACJ,CAAC,CAAC,oBACD,CAAC,CAAC,uBACD,6BACA,CAAC,CAAC;CACN,MAAM,2BAA2B,aAC/B,2BACA,CAAC,CAAC,SAAS,eACX,SAAS,gBAAgB;CAG3B,MAAM,gBAAgB,WAAW,CAAC,CAAC,IAAI,IAAI;CAC3C,IAAI,iBAAiB,CAAC,wBAAwB,aAAa,GAAG;EAC5D,MAAM,WAAW;EAajB,IAZgB,6BAA6B;GAC3C;GACA;GACA;GACA;GACA;GACA,sBAAsB,OAAO;GAC7B;GACA,aAAa;GACb,WAAW;GACX;EACF,CACI,GAAS;CACf;CAIA,MAAM,YAAY,KAAK,YAAY;CACnC,KAAK,MAAM,CAAC,aAAa,aAAa,WAAW,CAAC,CAAC,QAAQ,GAAG;EAC5D,MAAM,aAAa,YAAY,YAAY,MAAM;EACjD,MAAM,cAAc,SAAS,MAAM,YAAY,MAAM;EACrD,IAAI,EAAE,cAAc,gBAAgB,gBAAgB,MAAM;EAK1D,IACE,uBACA,SAAS,eACT,wBAAwB,SAAS,eACjC,gBAAgB,WAAW,GAE3B;EAIF,IAAI,wBAAwB,QAAQ,GAClC;EAeF,IAZgB,6BAA6B;GAC3C;GACA;GACA;GACA;GACA;GACA,sBAAsB,OAAO;GAC7B;GACA;GACA,WAAW;GACX;EACF,CACI,GAAS;CACf;CAOA,MAAM,uBAAuB;CAI7B,MAAM,iBAAiB,uBAAuB;CAuB9C,MAAM,oCAAoC;EACxC,MAAM,QAAQ,qBAAqB,IAAI;EACvC,IACE,CAAC,OAAO,eACR,uBACA,iBAAiB,eAAe,MAAM,QAAQ,GAE9C,OAAO;CAGX;CACA,MAAM,mCAAmC;EACvC,IACE,kBAAkB,IAAI,CAAC,CAAC,MACrB,cACC,CAAC,CAAC,UAAU,eAAe,UAAU,gBAAgB,cACzD,GAEA;EAEF,MAAM,QAAQ,qBAAqB,IAAI;EAGvC,IAAI,EADF,CAAC,CAAC,OAAO,eAAe,MAAM,gBAAgB,iBAC7B,OAAO;EAK1B,IAAI,iBAAiB,eAAe,OAAO,QAAQ,GAAG,OAAO;EAC7D,IAAI,yBAAyB,OAAO,KAAA;EACpC,MAAM,aACJ,OAAO,QAAQ,aAAa,OAAO,iBAAiB;EACtD,MAAM,qBACJ,CAAC,CAAC,OAAO,aAAa,CAAC,CAAC,cAAc,OAAO,cAAc;EAC7D,OAAO,CAAC,uBAAuB,qBAAqB,KAAA,IAAY;CAClE;CACA,IAAI;CACJ,IAAI,OAAO,WACT,gBAAgB,2BACd,OAAO,WACP,MACA,qBACA,OAAO,YACT;CAEF,IAAI,CAAC,eAWH,gBAAgB,kBACX,qBAAqB,eAAe,KACrC,uBAAuB,SACvB,2BAA2B,IAC3B,4BAA4B;CAElC,MAAM,iCACJ,uCAAuC,CAAC,CAAC,IAAI,IAAI;CACnD,IACE,iBACA,OAAO,iBAAiB,KAAA,KACxB,4BAA4B,cAAc,iBAAiB,YAAY,MACrE,KAAA,KACF,gCAEA,MAAM,IAAI,mBACR,iBAAiB,KAAK,2KACtB,iCACF;CAEF,MAAM,yBAAS,IAAI,IAA6B;CAChD,MAAM,0BAAU,IAAI,IAA8B;CAClD,IAAI;CAEJ,WACE,0BAA0B,KAAK,oBAC/B,gBAAgB,UAAU,WAC5B;CACA,IAAI,eAAe,QACjB,WACE,2BAA2B,OAAO,KAAK,cAAc,MAAM,CAAC,CAAC,OAAO,WACpE,OAAO,KAAK,cAAc,MAAM,CAClC;CAGF,IAAI,eAAe,QAAQ;EAGzB,KAAK,MAAM,CAAC,WAAW,aAAa,OAAO,QACzC,cAAc,MAChB,GAAkC;GAEhC,MAAM,UAAmC,EAAE,GAAG,SAAS,MAAM;GAC7D,IAAI,SAAS,aAAa,KAAA,GAAW,QAAQ,WAAW,SAAS;GACjE,IAAI,SAAS,YAAY,KAAA,GAAW,QAAQ,UAAU,SAAS;GAC/D,IAAI,SAAS,gBAAgB,KAAA,GAC3B,QAAQ,cAAc,SAAS;GACjC,IAAI,SAAS,cAAc,KAAA,GACzB,QAAQ,YAAY,SAAS;GAG/B,MAAM,QAAyB,EAC7B,MAAM,SAAS,KACjB;GAGA,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GAChC,MAAM,QAAQ;GAIhB,IAAI,SAAS,cAAc,KAAA,GACzB,MAAM,YAAY,SAAS;GAE7B,IAAI,SAAS,aAAa,KAAA,GACxB,MAAM,WAAW,SAAS;GAE5B,IAAI,SAAS,cAAc,KAAA,GACzB,MAAM,YAAY,SAAS;GAE7B,IAAI,SAAS,aAAa,KAAA,GACxB,MAAM,WAAW,SAAS;GAE5B,IAAI,SAAS,mBAAmB,KAAA,GAC9B,MAAM,iBAAiB,SAAS;GAKlC,IAAI,SAAS,YAAY,KAAA,GACvB,MAAM,UAAU,SAAS;QACpB,IAAI,QAAQ,YAAY,KAAA,GAAW;IAExC,MAAM,UAAU,QAAQ;IACxB,OAAO,MAAM,OAAO;GACtB;GAEA,OAAO,IAAI,WAAW,KAAK;EAC7B;EAEA,WACE,uBAAuB,OAAO,KAAK,cAAc,KAAK,eACxD;EAIA,cACE,uBACA,OAAO,WAAW,eAClB,cAAc,eACd;CACJ,OAAO;EAGL,WACE,wCAAwC,KAAK,+BAC/C;EACA,cAAc;CAChB;CAIA,MAAM,eAAe,wBAAwB,KAAK,OAAO;CAIzD,MAAM,mBAAmB,yBAAyB,CAAC,CAAC,IAAI,YAAY;CACpE,MAAM,wBAAwB,8BAA8B,CAAC,CAAC,IAAI,IAAI;CACtE,MAAM,aAAa,IAAI,IAAI,gBAAgB;CAC3C,KAAK,MAAM,CAAC,WAAW,YAAY,yBAAyB,CAAC,GAC3D,WAAW,IAAI,WAAW;EAAE,GAAG,WAAW,IAAI,SAAS;EAAG,GAAG;CAAQ,CAAC;CAExE,IAAI,cAAc,WAAW,OAAO,GAAG;EACrC,WACE,uBAAuB,WAAW,KAAK,wBAAwB,MACjE;EAEA,KAAK,MAAM,CAAC,WAAW,qBAAqB,YAAY;GAItD,MAAM,OAA8B;GACpC,MAAM,gBAAgB,OAAO,IAAI,SAAS;GAE1C,IAAI,eAAe;IAGjB,MAAM,aAAwB;KAC5B,GAAG,cAAc;KACjB,GAAG;IACL;IACA,MAAM,cAA+B;KACnC,MAAM,KAAK,QAAQ,cAAc;KACjC,OAAO;IACT;IAGA,IAAI,WAAW,MACb,OAAO,WAAW;IAIpB,IAAI,KAAK,cAAc,KAAA,GACrB,YAAY,YAAY,KAAK;SACxB,IAAI,cAAc,cAAc,KAAA,GACrC,YAAY,YAAY,cAAc;IAExC,IAAI,KAAK,cAAc,KAAA,GACrB,YAAY,YAAY,KAAK;SACxB,IAAI,cAAc,cAAc,KAAA,GACrC,YAAY,YAAY,cAAc;IAExC,IAAI,KAAK,aAAa,KAAA,GACpB,YAAY,WAAW,KAAK;SACvB,IAAI,cAAc,aAAa,KAAA,GACpC,YAAY,WAAW,cAAc;IAEvC,IAAI,OAAO,KAAK,mBAAmB,UACjC,YAAY,iBAAiB,KAAK;SAC7B,IAAI,OAAO,cAAc,mBAAmB,UACjD,YAAY,iBAAiB,cAAc;IAI7C,IAAI,KAAK,aAAa,MAAM;KAE1B,YAAY,WAAW;KACvB,WAAW,WAAW;IACxB,OAAO,IAAI,KAAK,aAAa,KAAA,GAC3B,YAAY,WAAW,KAAK;SACvB,IAAI,cAAc,aAAa,KAAA,GACpC,YAAY,WAAW,cAAc;IAIvC,IAAI,KAAK,YAAY,KAAA,GAAW;KAC9B,YAAY,UAAU,KAAK;KAC3B,OAAO,YAAY,OAAO;IAC5B,OAAO,IAAI,cAAc,YAAY,KAAA,GACnC,YAAY,UAAU,cAAc;IAGtC,OAAO,IAAI,WAAW,WAAW;IACjC,WACE,uCAAuC,UAAU,SAAS,YAAY,MACxE;GACF,OAAO;IAEL,MAAM,UAAqB;IAC3B,MAAM,WAA4B;KAChC,MAAM,KAAK,QAAQ;KACnB,OAAO;IACT;IAGA,IAAI,KAAK,cAAc,KAAA,GACrB,SAAS,YAAY,KAAK;IAE5B,IAAI,KAAK,cAAc,KAAA,GACrB,SAAS,YAAY,KAAK;IAE5B,IAAI,KAAK,aAAa,KAAA,GACpB,SAAS,WAAW,KAAK;IAE3B,IAAI,OAAO,KAAK,mBAAmB,UACjC,SAAS,iBAAiB,KAAK;IAGjC,IAAI,KAAK,aAAa,MAAM;KAC1B,SAAS,WAAW;KACpB,QAAQ,WAAW;IACrB,OAAO,IAAI,KAAK,aAAa,KAAA,GAC3B,SAAS,WAAW,KAAK;IAK3B,IAAI,KAAK,YAAY,KAAA,GAAW;KAC9B,SAAS,UAAU,KAAK;KACxB,OAAO,SAAS,OAAO;IACzB;IAEA,OAAO,IAAI,WAAW,QAAQ;IAC9B,WACE,8BAA8B,UAAU,wBAAwB,KAAK,QAAQ,QAC/E;GACF;EACF;CACF;CAUA,IAAI;CACJ,MAAM,qCAAqC,gBACvC,KAAA,IACC;CAGL,MAAM,0BAA0B,oCAAoC,MAAM;CAC1E,MAAM,2BACJ,OAAO,iBAAiB,KAAA,IACpB,aACA,eAAe,iBAAiB,iBAAiB,KAAA,IAC/C,aACA,gBACE,aACA,qCACE,qBACA,0BACE,mBACA,KAAA;CACd,MAAM,wBACJ,OAAO,gBACP,eAAe,iBAAiB,iBAC/B,gBACG,KAAA,IACC,sCAAsC;CAC7C,IAAI,uBAAuB;EACzB,qBAAqB,4BAA4B,qBAAqB;EACtE,IAAI,CAAC,oBAAoB;EAGzB,MAAM,YAAY,mBAAmB;EACrC,MAAM,iBAAiB,OAAO,IAAI,SAAS;EAC3C,wBAAwB,QAAQ,kBAAkB;EAClD,IAAI,CAAC,gBACH,WACE,yBAAyB,UAAU,iCAAiC,MACtE;CAEJ;CAEA,IAAI,eAAe,SAEjB,KAAK,MAAM,CAAC,YAAY,cAAc,OAAO,QAC3C,cAAc,OAChB,GACE,QAAQ,IAAI,YAAY,SAAS;CAQrC,MAAM,kBACJ,OAGA;CACF,IAAI,iBAAiB;EACnB,KAAK,MAAM,CAAC,YAAY,cAAc,OAAO,QAAQ,eAAe,GAClE,QAAQ,IAAI,YAAY,SAAS;EAEnC,WACE,qBAAqB,QAAQ,KAAK,eAAe,KAAK,uBACxD;CACF;CAOA,MAAM,mBAAmB,sBAAsB,IAAI;CAGnD,IAAI,iBAAiB,SAAS,GAAG;EAE/B,MAAM,aAAa,iBAAiB,iBAAiB,SAAS;EAC9D,MAAM,cAAc,UAAU,UAAU;EAgBxC,MAAM,wBACJ,gBAAgB,KAAA,KAChB,qBAAqB,YAAY,MAAM,YAAY,WAAW;EAEhE,IAAI,eAAe,CAAC,uBAAuB;GACzC,MAAM,iBAAiB,YAAY,QAAQ,iBAAiB;GAC5D,MAAM,gBAAgB,OAAO;GAI7B,IAAI,kBAAkB,KAAA,KAAa,mBAAmB,eACpD,MAAM,mBAAmB,qBACvB,MACA,eACA,YACA,cACF;EAEJ;CACF;CAYA,MAAM,YACJ,eAAe,QAAQ,aACvB,eAAe,iBAAiB,aAChC,OAAO,aACP,mBAAmB,IAAI;CACzB,iBAAiB,MAAM,SAAS;CAGhC,IAAI;CACJ,IAAI,eAAe,QAAQ;EAGzB,SAAS;GACP,KAAK,cAAc,OAAO;GAC1B,SACE,cAAc,OAAO,SAAS,KAAK,SAA0B;IAC3D,MAAM,IAAI;IACV,SAAS,IAAI,WAAW,CAAC;IACzB,QAAQ,IAAI,UAAU;IACtB,GAAI,IAAI,mBAAmB,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACzD,OAAO,IAAI;IACX,aAAa,IAAI;IACjB,UAAU,IAAI;GAChB,EAAE,KAAK,CAAC;GACV,UAAU,CAAC;GACX,WAAW,cAAc,OAAO,aAAa;GAE7C,SAAS,2BAA2B,cAAc,OAAO,OAAO;GAChE,aAAa,CAAC;GACd,cAAc,CAAC;GACf,SAAS,cAAc,OAAO,WAAW;GACzC,aAAa,cAAc;EAC7B;EACA,WACE,8CAA8C,KAAK,IAAI,OAAO,KAAK,cAAc,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,UAChH;CACF,OAEE,SAAS;EACP,KAAK;EACL,SAAS,CAAC;EACV,UAAU,CAAC;EACX;EACA,SAAS,CAAC;EACV,aAAa,CAAC;EACd,cAAc,CAAC;EACf,SAAS;EACT,aAAa,KAAA;CACf;CAGF,IAAI,OAAO,SAAS;EAClB,sBAAsB,OAAO,SAAS,OAAO,QAAQ,CAAC;EACtD,IAAI,cAAc,WAAW,OAAO,GAClC,sBAAsB,OAAO,SAAS,WAAW,QAAQ,CAAC;CAE9D;CAIA,MAAM,kBAAkB,eAAe;CACvC,IAAI;CAGJ,IAAI,oBAAoB,KAAA,GACtB,aAAa,kBAAkB,MAAM,MAAM;MAE3C,WACE,oBAAoB,gBAAgB,OAAO,qCAAqC,MAClF;CAKF,IAAI,eAAmC,eAAe;CACtD,IAAI,CAAC,cAAc;EACjB,MAAM,QAAQ,OAAO,eAAe,IAAI;EACxC,IAAI,OAAO,QAAQ,MAAM,SAAS,gBAAgB,MAAM,SAAS,UAC/D,eAAe,MAAM;CAEzB;CAIA,MAAM,eAAe;EACnB,GAAG;EACH,GAAG,eAAe;EAClB,GAAG;EACH;EAOA,GAAI,aACF,uBACA,eAAe,iBACf,MACF,IACI,EAAE,WAAW,KAAc,IAC3B,CAAC;CACP;CAMA,sBACE,cACA,WACA,QAAQ,WACR,eAAe,QAAQ,SACzB;CAIA,MAAM,gBAAgB,cAClB,oBAAoB,aAAa,IAAI,IACrC,KAAA;CAIJ,MAAM,aACJ,OAAO,cAAc,eAAe,cAAc;CAGpD,MAAM,kBAAkB,iBAAiB;CAEzC,WAAW,CAAC,CAAC,IAAI,iBAAiB;EAChC;EACA;EACA,aAAa;EACb,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA,OAAO,eAAe;EAMtB,YACE,eAAe,cACf,uBAAuB,IAAI,KAC3B,oBAAoB,IAAI;EAC1B,uBAAuB;EACvB;EACA;EACA,SAAS;EACT,gBAAgB,eAAe;EAC/B;EACA;EACA;CAIF,CAAC;CAMD,oBAAoB,CAAC,CAAC,IAAI,MAAM,eAAe;CAI/C,qBAAqB,MAAM,aAAa;CAExC,WACE,8BAA8B,KAAK,SAAS,gBAAgB,oBAAoB,OAAO,UAAU,QAAQ,YAAY,UAAU,MAAM,iBAAiB,UAAU,GAAG,kBACrK;CAUA,MAAM,aAAa,eAAe;CAClC,IAAI,cAAc,CAAC,qBAAqB,CAAC,CAAC,IAAI,UAAU,GAAG;EAEzD,qBAAqB,CAAC,CAAC,IAAI,UAAU;EAErC,WACE,wDAAwD,YAC1D;EAGA,MAAM,WAAW,wBAAwB,UAAU;EAInD,KAAK,MAAM,WAAW,UAEpB,IAAI,CAAC,wBAAwB,QAAQ,SAAS,GAAG;GAE/C,IACE,QAAQ,eACR,eACA,QAAQ,gBAAgB,aACxB;IACA,WACE,mCAAmC,QAAQ,UAAU,sBAAsB,aAC7E;IACA;GACF;GAEA,WACE,wCAAwC,QAAQ,UAAU,mBAAmB,YAC/E;GACA,qBACE,QAAQ,WACR,QAAQ,OACR,QAAQ,WACV;EACF;CAEJ;AACF;;;;;;;;AASA,SAAS,oCACP,QAC+C;CAC/C,KAAK,MAAM,CAAC,WAAW,UAAU,QAAQ;EACvC,MAAM,UAAU,MAAM,OAAO;EAU7B,IAAI,SAAS,oBAAoB,MAAM;EAEvC,OAAO;GACL,MACE,QAAQ,SAAS,aACb,aACA,QAAQ,SAAS,cAAc,MAAM,OAAO,aAAa,OACvD,aACA;GACR,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ;GAC3D,YAAY,QAAQ,eAAe;GACnC,cAAc,QAAQ,iBAAiB;GACvC,uBAAuB,QAAQ,0BAA0B;EAC3D;CACF;AAEF;AAEA,SAAgB,mBACd,YAMA,uBACM;CACN,MAAM,aAAa,UAAU,UAAU;CACvC,IAAI,YACF,WAAW,wBAAwB;CAMrC,eAAe,CAAC,CAAC,IACf,YACA,qBAGF;AACF;AAaA,SAAS,4BACP,cACmD;CACnD,IAAI,CAAC,cACH;CAGF,MAAM,aACJ,OAAO,iBAAiB,YAAY,CAAC,IAAI;CAC3C,OAAO;EACL,MAAM,WAAW,QAAQ;EACzB,OAAO,WAAW,SAAS;EAC3B,YAAY,WAAW,cAAc;EACrC,cAAc,WAAW,gBAAgB;EACzC,uBAAuB,WAAW,yBAAyB;CAC7D;AACF;AAEA,SAAgB,wBACd,QACA,oBACM;CACN,IAAI,CAAC,oBACH;CAGF,uBAAuB;CAEvB,MAAM,YAAY,mBAAmB;CACrC,MAAM,gBAAgB,OAAO,IAAI,SAAS;CAC1C,IAAI,eAAe;EACjB,OAAO,IAAI,WAAW;GACpB,GAAG;GACH,UACE,cAAc,YAAY,mBAAmB,SAAS;GACxD,OAAO;IACL,GAAG,cAAc;IACjB,WAAW,cAAc,OAAO,aAAa;IAC7C,SAAS;IACT,WAAW;KACT,GAAG,cAAc,OAAO;KACxB,iBAAiB;KACjB,GAAG;IACL;GACF;EACF,CAAC;EACD;CACF;CAEA,OAAO,IAAI,WAAW;EACpB,MAAM;EACN,SAAS;EACT,UAAU,mBAAmB,SAAS;EACtC,OAAO;GACL,WAAW;GACX,SAAS;GACT,WAAW;IACT,iBAAiB;IACjB,GAAG;GACL;EACF;CACF,CAAC;AACH;AAEA,SAAS,sBACP,iBACA,iBACmB;CACnB,MAAM,SAAS,CAAC,GAAI,mBAAmB,CAAC,CAAE;CAC1C,MAAM,OAAO,IAAI,IAAI,OAAO,KAAK,UAAU,OAAO,IAAI,CAAC,CAAC,OAAO,OAAO,CAAC;CAEvE,KAAK,MAAM,SAAS,mBAAmB,CAAC,GAAG;EACzC,IAAI,CAAC,OAAO,QAAQ,KAAK,IAAI,MAAM,IAAI,GACrC;EAEF,OAAO,KAAK,KAAK;EACjB,KAAK,IAAI,MAAM,IAAI;CACrB;CAEA,OAAO;AACT;AA8CA,SAAS,iCACP,cAC+C;CAC/C,IACE,cAAc,WAAW,mBACzB,cAAc,OAAO,WAAW,iBAEhC,OAAO;CAGT,IAAI,cAAc,SAAS,cACzB,OAAO;CAGT,IAAI,cAAc,SAAS,mBACzB,OAAO;AAIX;AAEA,SAAS,sBACP,SACA,cACM;CACN,IAAI,CAAC,cACH;CAGF,KAAK,MAAM,CAAC,WAAW,iBAAiB,cAAc;EACpD,MAAM,UAAU,cAAc,WAAW,cAAc,OAAO;EAC9D,MAAM,gBAAgB,iCAAiC,YAAY;EACnE,IAAI,CAAC,WAAW,CAAC,eACf;EAGF,MAAM,aAAa,YAAY,SAAS;EACxC,MAAM,iBAAiB,QAAQ;EAC/B,IAAI,CAAC,gBACH;EAGF,QAAQ,cAAc;GACpB,GAAG;GACH,GAAI,UACA,EAAE,MAAM,OAAO,OAAO,CAAC,CAAC,YAAY,EAA8B,IAClE,CAAC;GACL,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;EAC3C;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,6BACd,UACA,kBAIM;CACN,uBAAuB;CACvB,MAAM,QAAQ,oBAAoB;CAClC,MAAM,gCAAgB,IAAI,IAAY;CAEtC,MAAM,YAAY,SAAmC;EACnD,IAAI,MACF,cAAc,IAAI,IAAI;CAE1B;CAEA,MAAM,6BAAa,IAAI,IAAY;CACnC,MAAM,iBAAiB,SAAmC;EACxD,IAAI,MAAM,WAAW,IAAI,IAAI;CAC/B;CACA,cAAc,SAAS,IAAI;CAC3B,cAAc,SAAS,aAAa;CACpC,cAAc,kBAAkB,IAAI;CACpC,cAAc,kBAAkB,aAAa;CAE7C,KAAK,MAAM,QAAQ,YACjB,SAAS,IAAI;CAGf,KAAK,MAAM,CAAC,KAAK,cAAc,WAAW,GAAG;EAC3C,MAAM,iBACJ,CAAC,CAAC,UAAU,WAAW,WAAW,IAAI,UAAU,OAAO;EACzD,MAAM,eACJ,CAAC,CAAC,UAAU,oBACZ,UAAU,iBAAiB,MAAM,MAAM,WAAW,IAAI,CAAC,CAAC;EAE1D,IAAI,cAAc,YAAY,kBAAkB,cAAc;GAC5D,UAAU,mBAAmB,KAAA;GAC7B,UAAU,kBAAkB,KAAA;GAC5B,UAAU,mBAAmB,KAAA;GAC7B,SAAS,GAAG;GACZ,SAAS,UAAU,IAAI;GACvB,SAAS,UAAU,aAAa;EAClC;CACF;CAEA,KAAK,MAAM,QAAQ,eACjB,MAAM,OAAO,IAAI;AAErB;AAEA,SAAS,sCACP,UACA,WACA,aACM;CACN,MAAM,iBAAiB,UAAU,mBAAmB,CAAC;CACrD,MAAM,iCACJ,uCAAuC,CAAC,CAAC,IAAI,SAAS,WAAW;CACnE,IACE,SAAS,6BAA6B,cACtC,4BAA4B,eAAe,YAAY,MAAM,KAAA,KAC7D,gCAEA,MAAM,IAAI,mBACR,iBAAiB,SAAS,iBAAiB,SAAS,KAAK,2KACzD,iCACF;CAEF,MAAM,oBACJ,UAAU,QAAQ,aAClB,eAAe,aACf,SAAS,QAAQ,aACjB,SAAS,OAAO,aAChB,mBAAmB,SAAS,WAAW;CAEzC,SAAS,SAAS;EAChB,GAAG;EACH,GAAG,SAAS;EACZ,WAAW;EAEX,GAAI,aAAa,gBAAgB,SAAS,MAAM,IAC5C,EAAE,WAAW,KAAc,IAC3B,CAAC;CACP;CAKA,sBACE,SAAS,QACT,mBACA,UAAU,QAAQ,WAClB,SAAS,QAAQ,SACnB;CAEA,IAAI,UAAU,QACZ,KAAK,MAAM,CAAC,WAAW,OAAO,OAAO,QAAQ,UAAU,MAAM,GAAG;EAC9D,IAAI,CAAC,SAAS,OAAO,IAAI,SAAS,GAAG;GACnC,SAAS,OAAO,IAAI,WAAW,wBAAwB,EAAE,CAAC;GAC1D;EACF;EAEA,MAAM,gBAAgB,SAAS,OAAO,IAAI,SAAS;EACnD,IAAI,CAAC,eACH;EAGF,SAAS,OAAO,IAAI,WAAW,mBAAmB,eAAe,EAAE,CAAC;CACtE;CAMF,IAAI,SAAS,6BAA6B,YAAY;EACpD,MAAM,qBAAqB,4BACzB,eAAe,YACjB;EACA,SAAS,qBAAqB;EAC9B,SAAS,2BAA2B;EACpC,IAAI,oBACF,wBAAwB,SAAS,QAAQ,kBAAkB;CAE/D;CAEA,IAAI,UAAU,SACZ,KAAK,MAAM,CAAC,YAAY,cAAc,OAAO,QAAQ,UAAU,OAAO,GACpE,SAAS,QAAQ,IAAI,YAAY,SAAS;CAI9C,IAAI,UAAU,QAAQ;EACpB,MAAM,iBAAmC;GACvC,KAAK,UAAU,OAAO,OAAO;GAC7B,SACE,UAAU,OAAO,SAAS,KAAK,SAA0B;IACvD,MAAM,IAAI;IACV,SAAS,IAAI,WAAW,CAAC;IACzB,QAAQ,IAAI,UAAU;IACtB,GAAI,IAAI,mBAAmB,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACzD,OAAO,IAAI;IACX,aAAa,IAAI;IACjB,UAAU,IAAI;GAChB,EAAE,KAAK,CAAC;GACV,UAAU,CAAC;GACX,WAAW,UAAU,OAAO,aAAa;GACzC,SAAS,2BAA2B,UAAU,OAAO,OAAO;GAC5D,aAAa,CAAC;GACd,cAAc,CAAC;GACf,SAAS,UAAU,OAAO,WAAW;GACxB;EACf;EAEA,sBAAsB,eAAe,SAAS,SAAS,OAAO,QAAQ,CAAC;EAEvE,SAAS,SAAS;GAChB,GAAI,SAAS,UAAU,CAAC;GACxB,GAAG;GACH,WAAW,eAAe;GAC1B,KAAK,eAAe,OAAO,SAAS,QAAQ,OAAO;GACnD,SAAS;IACP,GAAI,SAAS,QAAQ,WAAW,CAAC;IACjC,GAAI,eAAe,WAAW,CAAC;GACjC;GACA,SAAS,sBACP,SAAS,QAAQ,SACjB,eAAe,OACjB;GACA,aAAa,eAAe,SAAS,QAAQ;EAC/C;CACF,OAAO,IAAI,CAAC,SAAS,QACnB,SAAS,SAAS;EAChB,KAAK;EACL,SAAS,CAAC;EACV,UAAU,CAAC;EACX,WAAW;EACX,SAAS,CAAC;EACV,aAAa,CAAC;EACd,cAAc,CAAC;EACf,SAAS;EACI;CACf;MACK;EACL,SAAS,OAAO,YAAY;EAC5B,SAAS,OAAO,cAAc,eAAe,SAAS,OAAO;CAC/D;CAEA,IAAI,UAAU,oBAAoB,KAAA,GAAW;EAC3C,SAAS,kBAAkB,UAAU;EACrC,SAAS,aAAa,KAAA;CACxB,OAAO,IAAI,CAAC,SAAS,mBAAmB,CAAC,SAAS,YAChD,SAAS,aAAa,kBAAkB,SAAS,MAAM,SAAS,MAAM;CAGxE,IAAI,aAAa;EACf,SAAS,cAAc;EACvB,SAAS,gBAAgB,oBACvB,aACA,SAAS,IACX;CACF,OAAO,IAAI,CAAC,SAAS,eAAe,UAAU,aAC5C,SAAS,cAAc,UAAU;CAGnC,IAAI,UAAU,SACZ,SAAS,UAAU,cACf,mBAAmB,UAAU,SAAS,WAAW,IACjD,UAAU;CAGhB,IAAI,CAAC,SAAS,kBAAkB,UAAU,UACxC,SAAS,iBAAiB,UAAU;CAMtC,IAAI,UAAU,YACZ,SAAS,aAAa,UAAU;CAGlC,SAAS,aACP,UAAU,cAAc,eAAe,cAAc,SAAS;CAChE,6BAA6B,QAAQ;AACvC;AAEA,SAAgB,qBACd,MACA,WACA,qBACM;CAEN,uBAAuB;CACvB,IAAI;EACF,8BAA8B,MAAM,WAAW,mBAAmB;CACpE,UAAU;EACR,uBAAuB;CACzB;AACF;AAEA,SAAS,8BACP,MACA,WACA,qBACM;CAgBN,MAAM,cAAc,UAAU,eAAe;CAK7C,MAAM,kBAAkB,UAAU,aAAa;CAC/C,MAAM,qBAAqB,cACvB,oBAAoB,aAAa,eAAe,IAChD,UAAU;CACd,MAAM,kBAAmB,sBAAsB;CAgB/C,MAAM,oBAAoB,sBAAsB,eAAe;CAC/D,IAAI,mBAAmB;EACrB,MAAM,WAAW,WAAW,CAAC,CAAC,IAAI,iBAAiB;EACnD,IAAI;OACc,6BAA6B;IAC3C;IACA;IACA;IACA;IACA,aAAa;IACb;IACA,WAAW;GACb,CACI,MAAY,UAAU;EAAA;CAK9B;CAEA,IAAI,WAAW,CAAC,CAAC,IAAI,eAAe,GAAG;EACrC,MAAM,WAAW,WAAW,CAAC,CAAC,IAAI,eAAe;EACjD,IAAI,CAAC,UAAU;EAUf,IATgB,6BAA6B;GAC3C;GACA;GACA;GACA;GACA,aAAa;GACb;GACA,WAAW;EACb,CACI,MAAY,UAAU;CAC5B;CAQA,MAAM,mBACJ,UAAU,WAAW,cACjB,mBAAmB,UAAU,SAAS,WAAW,IACjD,UAAU;CAQhB,MAAM,kBAAkB,cAAc,WAAW;EAC/C,OAAgB,kBAAkB;CACpC;CACA,OAAO,eAAe,iBAAiB,QAAQ,EAAE,OAAO,gBAAgB,CAAC;CAGzE,MAAM,yBAAS,IAAI,IAA6B;CAChD,MAAM,aAAa,yBAAyB,CAAC,CAAC,IAAI,eAAe;CACjE,IAAI,UAAU,QACZ,KAAK,MAAM,CAAC,WAAW,OAAO,OAAO,QAAQ,UAAU,MAAM,GAC3D,OAAO,IAAI,WAAW,wBAAwB,EAAE,CAAC;CAKrD,MAAM,0BAAU,IAAI,IAA8B;CAClD,IAAI,UAAU,SACZ,KAAK,MAAM,CAAC,YAAY,cAAc,OAAO,QAAQ,UAAU,OAAO,GACpE,QAAQ,IAAI,YAAY,SAAS;CAKrC,MAAM,SAAS,UAAU,mBAAmB,CAAC;CAC7C,MAAM,YAAY,OAAO,aAAa,mBAAmB,eAAe;CAMxE,sBAAsB,QAAQ,WAAW,UAAU,QAAQ,SAAS;CAIpE,IAAI;CACJ,IAAI,UAAU,QAAQ;EAGpB,SAAS;GACP,KAAK,UAAU,OAAO;GACtB,SACE,UAAU,OAAO,SAAS,KAAK,SAA0B;IACvD,MAAM,IAAI;IACV,SAAS,IAAI,WAAW,CAAC;IACzB,QAAQ,IAAI,UAAU;IACtB,GAAI,IAAI,mBAAmB,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACzD,OAAO,IAAI;IACX,aAAa,IAAI;IACjB,UAAU,IAAI;GAChB,EAAE,KAAK,CAAC;GACV,UAAU,CAAC;GACX,WAAW,UAAU,OAAO;GAC5B,SAAS,2BAA2B,UAAU,OAAO,OAAO;GAC5D,aAAa,CAAC;GACd,cAAc,CAAC;GACf,SAAS,UAAU,OAAO,WAAW;GACxB;EACf;EACA,sBAAsB,OAAO,SAAS,OAAO,QAAQ,CAAC;EACtD,sBAAsB,OAAO,SAAS,YAAY,QAAQ,CAAC;EAC3D,WACE,8CAA8C,KAAK,IAAI,OAAO,KAAK,UAAU,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,UAC5G;CACF,OAEE,SAAS;EACP,KAAK;EACL,SAAS,CAAC;EACV,UAAU,CAAC;EACX;EACA,SAAS,CAAC;EACV,aAAa,CAAC;EACd,cAAc,CAAC;EACf,SAAS;EACI;CACf;CAKF,MAAM,kBAAkB,UAAU;CAClC,IAAI;CAIJ,IAAI,oBAAoB,KAAA,GAAW;EACjC,aAAa,kBAAkB,MAAM,MAAM;EAC3C,WACE,wCAAwC,KAAK,aAAa,WAAW,OAAO,YAC9E;CACF,OACE,WACE,oBAAoB,gBAAgB,OAAO,qCAAqC,MAClF;CAKF,MAAM,gBAAgB;CAGtB,MAAM,aACJ,UAAU,cAAc,OAAO,cAAc;CAgB/C,MAAM,qBAAqB,4BAA4B,OAAO,YAAY;CAG1E,WAAW,CAAC,CAAC,IAAI,iBAAiB;EAChC,MAAM;EACN;EACA,aAAa;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OAAO,UAAU;EAGjB,YAAY,UAAU,cAAc,oBAAoB,eAAe;EACvE;EACA,gBAAgB,UAAU;EAC1B,SAAS;EACT,gBAAgB,UAAU;EAC1B;CACF,CAAC;CAID,qBAAqB,iBAAiB,aAAa;CAEnD,WACE,iBAAiB,gBAAgB,uBAAuB,gBAAgB,IAAI,OAAO,KAAK,WAAW,QAAQ,KAAK,UAClH;CAUA,MAAM,aAAa,UAAU;CAC7B,IAAI,cAAc,CAAC,qBAAqB,CAAC,CAAC,IAAI,UAAU,GAAG;EAEzD,qBAAqB,CAAC,CAAC,IAAI,UAAU;EAErC,WACE,wDAAwD,YAC1D;EAGA,MAAM,WAAW,wBAAwB,UAAU;EAInD,KAAK,MAAM,WAAW,UAEpB,IAAI,CAAC,wBAAwB,QAAQ,SAAS,GAAG;GAE/C,IACE,QAAQ,eACR,eACA,QAAQ,gBAAgB,aACxB;IACA,WACE,mCAAmC,QAAQ,UAAU,sBAAsB,aAC7E;IACA;GACF;GAEA,WACE,wCAAwC,QAAQ,UAAU,mBAAmB,YAC/E;GACA,qBACE,QAAQ,WACR,QAAQ,OACR,QAAQ,WACV;EACF;CAEJ;AACF"}
1
+ {"version":3,"file":"class-registration.js","names":[],"sources":["../../src/registry/class-registration.ts"],"sourcesContent":["/**\n * Class registration module for the SMRT ObjectRegistry.\n *\n * Handles registering classes, collections, and manifest entries.\n *\n * Extracted from registry.ts as part of issue #1006.\n * @see https://github.com/happyvertical/smrt/issues/1006\n */\n\nimport {\n declareChangeFeedSensitiveTable,\n setChangeFeedSensitiveClassResolver,\n} from '../change-feed-sensitivity.js';\nimport { ConfigurationError } from '../errors';\nimport {\n discoverManifestSync,\n discoverSTISiblingsSync,\n getPackageName,\n lookupInManifest,\n readProjectManifestSync,\n} from '../manifest/manifest-loader.js';\nimport {\n cloneManifestSchemaColumns,\n findWorkspaceRootSync,\n getLocalTestManifestCache,\n getManifestCache,\n getNodeBuiltins,\n getStaticManifestCache,\n getTestManifestCache,\n} from '../manifest/store.js';\nimport { SmrtObject } from '../object';\nimport type {\n FieldDefinition,\n FieldMeta,\n MethodDefinition,\n QualifiedClassName,\n SmartObjectDefinition,\n SmartObjectManifest,\n SmrtVisibility,\n} from '../scanner/types.js';\nimport type {\n ColumnDefinition,\n IndexDefinition,\n SchemaDefinition,\n} from '../schema/types.js';\nimport { tableNameFromClass, toSnakeCase } from '../utils';\nimport {\n createQualifiedName,\n isQualifiedName,\n parseQualifiedName,\n} from '../utils/qualified-names.js';\nimport {\n type CollisionInputs,\n decideCollisionPolicy,\n type MatchKind,\n} from './collision-policy.js';\nimport { isFrameworkBaseClass } from './framework-base-classes.js';\nimport { bumpRegistryGeneration } from './generation';\nimport { buildInheritanceChain } from './inheritance-resolver';\nimport {\n createFieldFromManifest,\n mergeManifestField,\n} from './manifest-field-merge.js';\nimport {\n findClass,\n findClassesByName,\n getCanonicalClassName,\n hasClassCaseInsensitive,\n qualifyExtendsName,\n} from './name-resolver';\nimport { assertQualifiedNameAliasesAvailable } from './qualified-name-aliases';\nimport {\n getClasses,\n getCollections,\n getConstructorFieldDecorators,\n getConstructorIndex,\n getConstructorTenantScopedDeclarations,\n getInheritanceCache,\n getLegacyFieldDecorators,\n getSourceFileFromStack,\n getStiSiblingsLoaded,\n verboseLog,\n} from './shared-state';\nimport type {\n RegisteredClass,\n RegisteredField,\n SmartObjectConfig,\n ValidatorFunction,\n} from './types.js';\nimport { compileValidators } from './validator';\n\n/**\n * Compute the pluralized endpoint/collection name from a class name, using\n * the SAME simple inflection rules as the scanner's manifest adapter\n * (`packages/scanner/src/manifest-adapter.ts`). Used only as a fallback when\n * a registered class has no manifest-provided `collection` (e.g. inline test\n * classes registered purely via the decorator path). Keep in sync with the\n * scanner; the manifest value is always preferred when present. (smrt#1311.)\n *\n * Currency -> currencies (y -> ies)\n * CompanyResearch -> companyresearches (ch -> ches)\n * SourceCrawl -> sourcecrawls (+ s)\n * EmploymentPerson -> employmentpersons (naive + s, NOT \"people\")\n */\nfunction pluralizeCollection(className: string): string {\n const lower = className.toLowerCase();\n if (lower.endsWith('y')) return `${lower.slice(0, -1)}ies`;\n if (lower.endsWith('s') || lower.endsWith('x') || lower.endsWith('z')) {\n return `${lower}es`;\n }\n if (lower.endsWith('ch') || lower.endsWith('sh')) return `${lower}es`;\n return `${lower}s`;\n}\n\n/**\n * The collection an STI subtype shares with its STI base, for a class that\n * registers with no manifest `collection` (#3125). The manifest generator\n * gives every STI subtype its base's collection (`findSTIBase`: the oldest\n * ancestor declaring `tableStrategy: 'sti'`); a subtype decorated before its\n * manifest loads — a consumer's bundled model chunk — must resolve the same\n * one, or permission slugs and route segments derived from it name a\n * collection nothing catalogues. Ancestors resolve by constructor identity, so\n * a same-named class in another package cannot stand in for the base.\n */\nfunction inheritedStiCollection(ctor: typeof SmrtObject): string | undefined {\n let base: RegisteredClass | undefined;\n for (\n let parent = Object.getPrototypeOf(ctor);\n parent && parent !== Function.prototype;\n parent = Object.getPrototypeOf(parent)\n ) {\n const key = getConstructorIndex().get(parent as typeof SmrtObject);\n const registered = key ? getClasses().get(key) : undefined;\n if (registered?.config?.tableStrategy === 'sti') base = registered;\n }\n return base?.collection;\n}\n\n/**\n * Shared bundled-context detector. Source files in these output\n * directories come from a bundler (Vite library mode, webpack, Next.js,\n * Nuxt, svelte-kit) that can duplicate module code across chunks.\n */\nexport function isBundledOutputPath(sourceFile: string | undefined): boolean {\n if (!sourceFile) return false;\n return (\n sourceFile.includes('.svelte-kit/output/') ||\n sourceFile.includes('/dist/') ||\n sourceFile.includes('/build/') ||\n sourceFile.includes('.next/') ||\n sourceFile.includes('.nuxt/')\n );\n}\n\nfunction normalizeSourcePath(path: string): string {\n return path\n .replace(/^file:\\/\\//, '')\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\//, '');\n}\n\nfunction isAbsoluteSourcePath(path: string): boolean {\n return path.startsWith('/') || /^[a-z]:\\//i.test(path);\n}\n\n/**\n * Directories a relative manifest `filePath` can be relative to: the scanned\n * project (the process's working directory) and its workspace root.\n */\nfunction relativeSourceRoots(): string[] {\n if (typeof process === 'undefined' || typeof process.cwd !== 'function') {\n return [];\n }\n const cwd = normalizeSourcePath(process.cwd());\n const workspaceRoot = findWorkspaceRootSync(process.cwd());\n return workspaceRoot && normalizeSourcePath(workspaceRoot) !== cwd\n ? [cwd, normalizeSourcePath(workspaceRoot)]\n : [cwd];\n}\n\n/**\n * Whether two source paths name the same file. A stack frame reports an\n * absolute path; a manifest's `filePath` is absolute or relative to the\n * project or workspace root it was scanned from (anytown scans\n * `packages/cloud-network/src/models/*.ts` into the dashboard's manifest,\n * #3110), so a relative path is resolved against those roots, never matched by\n * suffix alone.\n */\nexport function isSameSourcePath(\n left: string | undefined,\n right: string | undefined,\n): boolean {\n if (!left || !right) return false;\n const a = normalizeSourcePath(left);\n const b = normalizeSourcePath(right);\n if (a === b) return true;\n const aAbsolute = isAbsoluteSourcePath(a);\n const bAbsolute = isAbsoluteSourcePath(b);\n if (aAbsolute === bAbsolute) return false;\n const [absolute, relative] = aAbsolute ? [a, b] : [b, a];\n const path = getNodeBuiltins()?.path;\n if (!path) return false;\n // Platform `resolve` keeps a Windows drive-letter root absolute.\n return relativeSourceRoots().some(\n (root) => normalizeSourcePath(path.resolve(root, relative)) === absolute,\n );\n}\n\n/**\n * The package whose loaded manifest describes the class declared in\n * `sourceFile` — the class's identity when its nearest `package.json` is not\n * the package that scanned it (#3110). An app manifest commonly scans workspace\n * packages' sources under the app's own package name (anytown's\n * `packages/cloud-network` models are `@anytown/dashboard:*`), so the\n * stack-derived package of a source-consumed class (Vite dev server, Vitest,\n * tsx) never declares it.\n *\n * When several packages' entries describe the file, the stack-derived package\n * wins if it is one of them; otherwise a single candidate, or the one owned by\n * the manifest it appears in. Anything else is ambiguous and yields\n * `undefined`.\n */\nfunction findManifestPackageForSource(\n name: string,\n sourceFile: string | undefined,\n stackPackageName: string | undefined,\n): SourceManifestMatch | undefined {\n if (!sourceFile) return undefined;\n const manifests = new Set<SmartObjectManifest>();\n for (const manifest of [\n getLocalTestManifestCache(),\n getTestManifestCache(),\n getStaticManifestCache(),\n ...getManifestCache().values(),\n ]) {\n if (manifest?.objects) manifests.add(manifest);\n }\n\n const resolved = resolveSourceManifestPackage(\n name,\n sourceFile,\n stackPackageName,\n manifests,\n );\n if (resolved) return resolved;\n // No loaded manifest describes the file: a plain Node/tsx script has not\n // loaded the project's manifest yet (#3109).\n const projectManifest = readProjectManifestSync();\n return projectManifest?.objects && !manifests.has(projectManifest)\n ? resolveSourceManifestPackage(\n name,\n sourceFile,\n stackPackageName,\n new Set([projectManifest]),\n )\n : undefined;\n}\n\ninterface SourceManifestMatch {\n packageName: string;\n /** The describing entry, used when the package's own manifest is not loaded. */\n entry: SmartObjectDefinition;\n}\n\nfunction resolveSourceManifestPackage(\n name: string,\n sourceFile: string,\n stackPackageName: string | undefined,\n manifests: Set<SmartObjectManifest>,\n): SourceManifestMatch | undefined {\n const candidates = new Map<string, SmartObjectDefinition>();\n const ownedByTheirManifest = new Set<string>();\n for (const manifest of manifests) {\n for (const [key, entry] of Object.entries(manifest.objects)) {\n const qualified = isQualifiedName(key)\n ? parseQualifiedName(key)\n : undefined;\n const className = entry.className ?? qualified?.className ?? key;\n if (className !== name) continue;\n if (!isSameSourcePath(sourceFile, entry.filePath)) continue;\n const entryPackage =\n entry.packageName ?? qualified?.packageName ?? manifest.packageName;\n if (!entryPackage) continue;\n if (!candidates.has(entryPackage)) {\n candidates.set(entryPackage, { ...entry, packageName: entryPackage });\n }\n if (entryPackage === manifest.packageName) {\n ownedByTheirManifest.add(entryPackage);\n }\n }\n }\n\n const pick = (packageName: string): SourceManifestMatch => ({\n packageName,\n entry: candidates.get(packageName) as SmartObjectDefinition,\n });\n if (stackPackageName && candidates.has(stackPackageName)) {\n return pick(stackPackageName);\n }\n if (candidates.size === 1) return pick([...candidates.keys()][0]);\n if (ownedByTheirManifest.size === 1)\n return pick([...ownedByTheirManifest][0]);\n return undefined;\n}\n\n/**\n * Build `CollisionInputs` for the decorator-origin path (`register()`).\n * Manifest-origin inputs are built separately inside `registerFromManifest`.\n */\nfunction buildDecoratorCollisionInputs(args: {\n ctor: typeof SmrtObject;\n name: string;\n newPackageName: string | undefined;\n newSourceFile: string | undefined;\n newInBundledContext: boolean;\n newDeclaredTableName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n matchKind: MatchKind;\n}): CollisionInputs {\n const {\n ctor,\n name,\n newPackageName,\n newSourceFile,\n newInBundledContext,\n newDeclaredTableName,\n existing,\n existingKey,\n matchKind,\n } = args;\n const existingTableName =\n existing.schema?.tableName || existing.config?.tableName;\n\n let newExtendsExisting = false;\n let existingExtendsNew = false;\n try {\n newExtendsExisting = ctor.prototype instanceof existing.constructor;\n existingExtendsNew = existing.constructor.prototype instanceof ctor;\n } catch {\n // `instanceof` can throw for non-function constructors. Keep both false.\n }\n\n const bothSourceFilesKnown = !!(newSourceFile && existing.sourceFilePath);\n const sameSourceFile =\n bothSourceFilesKnown &&\n isSameSourcePath(newSourceFile, existing.sourceFilePath);\n const existingIsPackageQualified = !!existing.packageName?.startsWith('@');\n const samePackage =\n !!newPackageName &&\n !!existing.packageName &&\n newPackageName === existing.packageName;\n const hasNewQualifiedKey = !!newPackageName;\n const existingKeyIsQualified = isQualifiedName(existingKey);\n\n return {\n origin: 'decorator',\n matchKind,\n sameConstructor: existing.constructor === ctor,\n sameSourceFile,\n bothSourceFilesKnown,\n existingIsManifestStub:\n (existing.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true,\n newInBundledContext,\n newExtendsExisting,\n existingExtendsNew,\n samePackage,\n existingIsPackageQualified,\n sameName: name === existing.name,\n hasNewQualifiedKey,\n existingKeyIsQualified,\n existingHasAnyPackage: !!existing.packageName,\n // Manifest-only fields; filled with safe defaults for decorator origin.\n hasManifestContent: false,\n registrationKeyDiffersFromExistingKey: false,\n existingHasNoPackage: !existing.packageName,\n declaresDifferentTable:\n !!newDeclaredTableName &&\n !!existingTableName &&\n newDeclaredTableName !== existingTableName,\n };\n}\n\n/**\n * Execute the collision policy for `register()`. Returns `true` if the\n * policy resolved the collision (caller should return from `register`);\n * `false` means no policy match (the decision table is exhaustive so\n * that never actually happens — the default row throws).\n *\n * All state mutation (`upsertExistingEntry`, verboseLog) stays in this\n * caller-side helper; the policy function itself is pure.\n */\nfunction applyRegisterCollisionPolicy(args: {\n ctor: typeof SmrtObject;\n name: string;\n newPackageName: string | undefined;\n newSourceFile: string | undefined;\n newInBundledContext: boolean;\n newDeclaredTableName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n matchKind: MatchKind;\n upsertExistingEntry: (\n existingKey: string,\n existing: RegisteredClass,\n ) => string;\n}): boolean {\n const inputs = buildDecoratorCollisionInputs(args);\n const decision = decideCollisionPolicy(inputs);\n\n switch (decision.policy) {\n case 'accept':\n case 'replace': {\n // Both map to the same operation for the decorator path:\n // update the existing slot's constructor + metadata. `replace`\n // only differs in verboseLog flavor so a reviewer reading the log\n // can tell which scenario fired.\n const newKey = args.upsertExistingEntry(args.existingKey, args.existing);\n if (\n decision.scenario === 'sti-child-wins' ||\n decision.scenario === 'manifest-stub-replacement'\n ) {\n verboseLog(\n `[registry] ${decision.scenario}: '${args.name}' → key='${newKey}' (${decision.reason})`,\n );\n }\n return true;\n }\n case 'skip':\n verboseLog(\n `[registry] ${decision.scenario}: skipping '${args.name}' (${decision.reason})`,\n );\n return true;\n case 'throw': {\n const matchSuffix =\n args.matchKind === 'case-insensitive'\n ? ` (case-insensitive match with \"${args.existingKey}\")`\n : '';\n throw new Error(\n `SMRT Class Name Collision: \"${args.name}\"${matchSuffix}\\n\\n` +\n `A class with this name is already registered, but with a different constructor.\\n` +\n `This usually happens when:\\n` +\n ` 1. Multiple test files define classes with the same name\\n` +\n ` 2. Different packages export classes with the same name\\n\\n` +\n `The collision will cause the wrong field definitions to be used,\\n` +\n `leading to properties not being initialized correctly.\\n\\n` +\n `To fix:\\n` +\n ` - Use unique class names (e.g., ${args.name}_UniqueId)\\n` +\n ` - Or use @smrt({ name: 'unique_name' }) to override the registration name`,\n );\n }\n case 'coexist-qualified':\n // A different package's class: leave its entry alone and let the new\n // class register under its own qualified key (#3106).\n verboseLog(\n `[registry] ${decision.scenario}: '${args.name}' coexists with '${args.existingKey}' (${decision.reason})`,\n );\n return false;\n case 'merge-manifest':\n // Only reachable from the manifest path; if we somehow get here from\n // `register()`, something is miswired.\n throw new Error(\n `decideCollisionPolicy returned '${decision.policy}' for decorator origin (scenario: ${decision.scenario}). This is a bug.`,\n );\n }\n}\n\n/**\n * Build `CollisionInputs` for the manifest-origin path\n * (`registerFromManifest`). Manifest entries have string-based inheritance\n * (`objectDef.extends`) rather than prototype-based, and no real\n * constructor to compare — `sameConstructor` is always false here.\n */\nfunction buildManifestCollisionInputs(args: {\n name: string;\n objectDef: SmartObjectDefinition;\n packageName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n registrationKey: string;\n matchKind: MatchKind;\n}): CollisionInputs {\n const {\n name,\n objectDef,\n packageName,\n existing,\n existingKey,\n registrationKey,\n matchKind,\n } = args;\n const newClassName = objectDef.className || name;\n const newExtends = objectDef.extends;\n\n // When an incoming manifest's `extends` points at the existing entry,\n // OR the existing entry's `extends` points at the incoming class, we\n // have an STI inheritance relationship. Each side checks:\n // - the simple name of the other\n // - the key under which the other is registered\n // - a case-insensitive fallback\n //\n // The `existingKey` comparison is load-bearing for cross-package STI:\n // `existing.extends` is stored post-`qualifyExtendsName()`, so it may\n // be the fully-qualified parent key like `@pkg:Parent`. Without this\n // comparison, `existingExtendsNew` falsely reads as false and the\n // arriving parent manifest would be registered as a duplicate instead\n // of skipped. See the deep-review report on #1140 for the fix rationale.\n const newExtendsExisting = !!(\n newExtends &&\n (newExtends === existing.name ||\n newExtends === existingKey ||\n newExtends.toLowerCase() === existing.name.toLowerCase())\n );\n const existingExtendsNew = !!(\n existing.extends &&\n (existing.extends === newClassName ||\n existing.extends === name ||\n existing.extends === registrationKey ||\n existing.extends.toLowerCase() === newClassName.toLowerCase())\n );\n\n const newSourceFile = objectDef.filePath;\n const bothSourceFilesKnown = !!(newSourceFile && existing.sourceFilePath);\n const sameSourceFile =\n bothSourceFilesKnown && newSourceFile === existing.sourceFilePath;\n const existingIsPackageQualified = !!existing.packageName?.startsWith('@');\n const samePackage =\n !!packageName &&\n !!existing.packageName &&\n packageName === existing.packageName;\n\n return {\n origin: 'manifest',\n matchKind,\n sameConstructor: false,\n sameSourceFile,\n bothSourceFilesKnown,\n existingIsManifestStub:\n (existing.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true,\n newInBundledContext: false,\n newExtendsExisting,\n existingExtendsNew,\n samePackage,\n existingIsPackageQualified,\n sameName: newClassName === existing.name,\n hasNewQualifiedKey: isQualifiedName(registrationKey),\n existingKeyIsQualified: isQualifiedName(existingKey),\n existingHasAnyPackage: !!existing.packageName,\n hasManifestContent: !!(\n objectDef.fields ||\n objectDef.methods ||\n objectDef.schema ||\n objectDef.decoratorConfig\n ),\n registrationKeyDiffersFromExistingKey: registrationKey !== existingKey,\n existingHasNoPackage: !existing.packageName,\n declaresDifferentTable: false,\n };\n // Note: manifest-origin sets hasNewQualifiedKey from the final\n // registrationKey (not packageName) because registerFromManifest accepts\n // an objectDef.qualifiedName fallback when packageName is omitted —\n // deriving from packageName alone would miss that case and misroute the\n // coexistence rows. See PR #1140 review (Copilot P1 at line 287).\n}\n\n/**\n * Execute the collision policy for `registerFromManifest()`. Returns\n * `'return'` when the policy fully resolves the collision (caller should\n * early-return from `registerFromManifest`) or `'continue'` when the new\n * registration should proceed to the fresh-entry code below the collision\n * block (either a child-wins delete-then-register or a different-package\n * coexist-qualified scenario).\n *\n * Implements the `merge-manifest` contract end-to-end: fold fields via\n * `mergeManifestIntoExistingRegistration`, then conditionally alias the\n * existing entry under `registrationKey` when it differs from the\n * canonical key — both steps preserve `issue-951:144-200`.\n */\nfunction applyManifestCollisionPolicy(args: {\n name: string;\n objectDef: SmartObjectDefinition;\n packageName: string | undefined;\n existing: RegisteredClass;\n existingKey: string;\n registrationKey: string;\n matchKind: MatchKind;\n}): 'return' | 'continue' {\n const inputs = buildManifestCollisionInputs(args);\n const decision = decideCollisionPolicy(inputs);\n\n switch (decision.policy) {\n case 'skip':\n verboseLog(\n `[registry] ${decision.scenario}: skipping manifest '${args.name}' (${decision.reason})`,\n );\n return 'return';\n case 'replace':\n // STI child-wins: delete existing so the new entry can register fresh.\n getClasses().delete(args.existingKey);\n verboseLog(\n `[registry] ${decision.scenario}: '${args.name}' replaces '${args.existingKey}' (${decision.reason})`,\n );\n return 'continue';\n case 'merge-manifest': {\n // The merged manifest config can carry new aliases (#3338): validate\n // the merged result before the merge mutates the live entry.\n assertQualifiedNameAliasesAvailable(\n args.registrationKey,\n {\n ...args.existing,\n config: {\n ...(args.objectDef.decoratorConfig || {}),\n ...args.existing.config,\n },\n },\n args.existing,\n );\n mergeManifestIntoExistingRegistration(\n args.existing,\n args.objectDef,\n args.packageName,\n );\n if (args.registrationKey !== args.existingKey) {\n const classes = getClasses();\n classes.set(args.registrationKey, args.existing);\n getConstructorIndex().set(\n args.existing.constructor,\n args.registrationKey,\n );\n }\n return 'return';\n }\n case 'coexist-qualified':\n // Both registrations live under their qualified keys; caller falls\n // through to register the new one fresh.\n return 'continue';\n case 'accept':\n // Manifest origin never returns 'accept' (that's a decorator-path\n // policy). Treat defensively as return-no-op.\n return 'return';\n case 'throw':\n // Manifest collisions default to skip, never throw — this branch is\n // unreachable from the manifest origin. Guard against future drift.\n throw new Error(\n `decideCollisionPolicy returned 'throw' for manifest origin (scenario: ${decision.scenario}). This is a bug.`,\n );\n }\n}\n\nfunction resolveTableName(\n ctor: typeof SmrtObject,\n name: string,\n config: SmartObjectConfig,\n): string {\n // A known package resolves by qualified identity so a same-named class in\n // another package cannot supply this one's table (#3098).\n const manifestEntry = config._manifest\n ? lookupRegistrationManifest(\n config._manifest,\n name,\n config.packageName,\n config._manifestKey,\n )\n : discoverManifestSync(\n config.packageName\n ? createQualifiedName(config.packageName, name)\n : name,\n );\n\n return (\n manifestEntry?.schema?.tableName ||\n manifestEntry?.decoratorConfig?.tableName ||\n config.tableName ||\n tableNameFromClass(ctor)\n );\n}\n\n/**\n * Whether `packageName` itself declares the class `qualifiedKey` names: it is\n * registered under that key (a manifest stub or an earlier registration), or\n * a manifest owned by that package describes it. A stack-derived package is\n * only trusted as a class's identity on this evidence — a consumer bundle\n * that inlined a dependency reports the consumer's package, whose manifest\n * describes the dependency's classes under the dependency's name (#3098).\n */\nfunction packageDeclaresClass(\n packageName: string,\n qualifiedKey: string,\n): boolean {\n if (getClasses().has(qualifiedKey)) return true;\n const entry = discoverManifestSync(qualifiedKey);\n return (\n !!entry &&\n (entry.packageName === undefined || entry.packageName === packageName)\n );\n}\n\nfunction lookupRegistrationManifest(\n manifest: SmartObjectManifest,\n name: string,\n _packageName: string | undefined,\n manifestKey: string | undefined,\n): SmartObjectDefinition | undefined {\n if (manifestKey) return manifest.objects[manifestKey];\n // `_manifest` predates generated keyed registrations and accepts package-less,\n // unqualified manifests. Preserve that public compatibility path. Generated\n // code supplies `_manifestKey`, which is validated before this lookup and is\n // therefore never resolved through the ambiguous simple-name index.\n return lookupInManifest(manifest, name);\n}\n\nfunction validateIsolatedRegistrationManifest(\n manifest: SmartObjectManifest,\n manifestKey: string,\n name: string,\n packageName: string,\n): SmartObjectDefinition {\n const entries = Object.entries(manifest.objects);\n const targetKey = createQualifiedName(packageName, name);\n const [actualKey, objectDef] = entries[0] ?? [];\n const keyMatchesIdentity =\n actualKey === name ||\n (isQualifiedName(actualKey || '') && actualKey === targetKey);\n const packageMatches =\n (!manifest.packageName || manifest.packageName === packageName) &&\n (!objectDef?.packageName || objectDef.packageName === packageName);\n\n if (\n entries.length !== 1 ||\n actualKey !== manifestKey ||\n !keyMatchesIdentity ||\n objectDef?.className !== name ||\n !packageMatches ||\n (objectDef?.qualifiedName !== undefined &&\n objectDef.qualifiedName !== targetKey)\n ) {\n throw new ConfigurationError(\n `Invalid isolated registration manifest for \"${targetKey}\".`,\n 'CONFIG_INVALID_ISOLATED_MANIFEST',\n { manifestKey, targetKey },\n );\n }\n return objectDef;\n}\n\n/**\n * Publish a `@smrt({ sensitive: true })` declaration to the change feed\n * (issue #2937).\n *\n * Declares **every candidate name**, not just one. The name a class declares\n * and the name its rows are recorded under can diverge: a manifest stub\n * derives the name from `decoratorConfig` but installs\n * `objectDef.schema.tableName`, and the merge path can overwrite\n * `existing.schema.tableName`. A declaration landing on a name nothing writes\n * under is a silent fail-open, and the set is monotonic, so a superset is the\n * safe direction. (The STI case — a child declaring `sensitive` while writing\n * to its base class's table — is closed authoritatively at the write path by\n * `isChangeFeedSensitiveWrite`, which sees the real name.)\n *\n * Only `true` is acted on: the sensitive set is one-way by design, so there is\n * nothing here to undo a previous declaration.\n */\n/**\n * Whether any config source declares the object credential-bearing (#2937).\n *\n * `sensitive` is one-way, so it is combined across sources with OR rather than\n * by spread precedence: only `=== true` carries meaning, and a `false` from any\n * source must never erase a `true` from another.\n */\nfunction anySensitive(...configs: (SmartObjectConfig | undefined)[]): boolean {\n return configs.some((config) => config?.sensitive === true);\n}\n\nfunction declareSensitiveTable(\n config: SmartObjectConfig,\n ...tableNames: (string | undefined)[]\n): void {\n if (config.sensitive !== true) return;\n for (const tableName of tableNames) {\n if (tableName) declareChangeFeedSensitiveTable(tableName);\n }\n}\n\n// The registry's class-level `sensitive` lookup, handed to the change feed so\n// its write path can ask about an instance's class without importing the\n// registry — `class.ts` already imports `change-feed.ts`, so the reverse edge\n// would be a cycle. Installed once at module load (#2937).\nsetChangeFeedSensitiveClassResolver((ctor) => {\n if (typeof ctor !== 'function') return false;\n const key = getConstructorIndex().get(ctor as typeof SmrtObject);\n if (!key) return false;\n return getClasses().get(key)?.config?.sensitive === true;\n});\n\nfunction setSmrtTableName(ctor: typeof SmrtObject, tableName: string): void {\n const existing = Object.getOwnPropertyDescriptor(ctor, 'SMRT_TABLE_NAME');\n if (existing?.value === tableName) {\n return;\n }\n\n Object.defineProperty(ctor, 'SMRT_TABLE_NAME', {\n value: tableName,\n writable: false,\n enumerable: false,\n configurable: true,\n });\n}\n\n/**\n * Attach the registry's qualified name to the constructor as a static\n * property. Mirrors the `SMRT_TABLE_NAME` pattern.\n *\n * Survives:\n * - Minification (the property is set on the constructor itself).\n * - HMR / module duplication / federated-module boundaries where the\n * `constructorIndex` WeakMap holds an older constructor identity than\n * the one a caller has in hand.\n *\n * Acts as a belt-and-suspenders fallback for runtime code that has a\n * constructor reference and wants its registry identity without going\n * through a Map lookup (e.g. `SmrtHierarchical._hierarchyCollection`).\n */\nfunction setSmrtQualifiedName(\n ctor: typeof SmrtObject,\n qualifiedName: string | undefined,\n): void {\n if (!qualifiedName) return;\n const existing = Object.getOwnPropertyDescriptor(ctor, '_smrtQualifiedName');\n if (existing?.value === qualifiedName) {\n return;\n }\n\n Object.defineProperty(ctor, '_smrtQualifiedName', {\n value: qualifiedName,\n writable: false,\n enumerable: false,\n configurable: true,\n });\n}\n\n/**\n * Register (or re-register) a class. Every registration can add, replace or\n * mutate a registered class in place, so it invalidates the generation-keyed\n * registry memos before and after (#3047) — including when it throws partway.\n */\nexport function register(\n ctor: typeof SmrtObject,\n config: SmartObjectConfig = {},\n): void {\n bumpRegistryGeneration();\n try {\n registerUntracked(ctor, config);\n } finally {\n bumpRegistryGeneration();\n }\n}\n\nfunction registerUntracked(\n ctor: typeof SmrtObject,\n config: SmartObjectConfig = {},\n): void {\n const name = config.name || ctor.name;\n const explicitPackageName = config.packageName;\n let promotedCollectionConstructor: RegisteredClass['collectionConstructor'];\n let promotedRuntimeConfig: SmartObjectConfig | undefined;\n let isolatedManifestEntry: SmartObjectDefinition | undefined;\n\n if (config._manifestKey) {\n if (!explicitPackageName || !config._manifest) {\n throw new ConfigurationError(\n 'Generated isolated manifest registration requires packageName and _manifest.',\n 'CONFIG_INVALID_ISOLATED_MANIFEST',\n );\n }\n isolatedManifestEntry = validateIsolatedRegistrationManifest(\n config._manifest,\n config._manifestKey,\n name,\n explicitPackageName,\n );\n // Validate before promotion removes or rewrites an existing exact\n // constructor registration. A generated isolated manifest is authoritative\n // for schema, so it cannot silently erase a live @TenantScoped contract.\n if (\n config.tenantScoped === undefined &&\n normalizeTenantScopedConfig(\n isolatedManifestEntry.decoratorConfig?.tenantScoped,\n ) === undefined &&\n getConstructorTenantScopedDeclarations().get(ctor)\n ) {\n throw new ConfigurationError(\n `Manifest for '${name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`,\n 'CONFIG_TENANT_MANIFEST_CONFLICT',\n );\n }\n }\n\n function upsertExistingEntry(\n existingKey: string,\n existing: RegisteredClass,\n ): string {\n const nextPackageName = explicitPackageName || existing.packageName;\n const nextKey = nextPackageName\n ? createQualifiedName(nextPackageName, name)\n : name;\n // Capture pre-mutation identity so descendants whose `extends` still\n // references the old name/qualifiedName are caught by the post-mutation\n // invalidation sweep (#1139 Gap 2).\n const previousIdentity = {\n name: existing.name,\n qualifiedName: existing.qualifiedName as string | undefined,\n };\n\n // #3338: validate the PROPOSED identity and aliases before mutating the\n // live entry, so a refused re-registration (same key or promoted) leaves\n // it exactly as it was.\n assertQualifiedNameAliasesAvailable(\n nextKey,\n {\n ...existing,\n name,\n packageName: nextPackageName,\n qualifiedName: nextPackageName\n ? (createQualifiedName(nextPackageName, name) as QualifiedClassName)\n : undefined,\n constructor: ctor,\n config: { ...existing.config, ...config },\n },\n existing,\n );\n\n existing.name = name;\n existing.packageName = nextPackageName;\n bumpRegistryGeneration();\n existing.qualifiedName = nextPackageName\n ? (createQualifiedName(nextPackageName, name) as QualifiedClassName)\n : undefined;\n const nextTableName = resolveTableName(ctor, name, {\n ...existing.config,\n ...config,\n ...(nextPackageName ? { packageName: nextPackageName } : {}),\n });\n existing.config = {\n ...existing.config,\n ...config,\n tableName: nextTableName,\n // OR, never last-wins — see `anySensitive` (#2937). A re-registration\n // must not be able to clear a declaration a previous one made.\n ...(anySensitive(existing.config, config)\n ? { sensitive: true as const }\n : {}),\n };\n if (!existing.schema) {\n existing.schema = {\n ddl: '',\n indexes: [],\n triggers: [],\n tableName: nextTableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n };\n }\n existing.schema.tableName = nextTableName;\n // A manifest stub carries the manifest's `filePath` (a build-time source\n // path). Once a real class takes the entry over, later collision checks\n // compare against where that class actually loaded from (#3106).\n if (\n (existing.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true &&\n newSourceFile\n ) {\n existing.sourceFilePath = newSourceFile;\n }\n existing.constructor = ctor;\n setSmrtTableName(ctor, nextTableName);\n declareSensitiveTable(\n existing.config,\n nextTableName,\n existing.schema?.tableName,\n );\n setSmrtQualifiedName(ctor, existing.qualifiedName);\n\n if (existingKey !== nextKey) {\n const classes = getClasses();\n const existingAtNextKey = classes.get(nextKey);\n\n if (existingAtNextKey && existingAtNextKey !== existing) {\n throw new ConfigurationError(\n `Class registry collision while promoting \"${existingKey}\" to \"${nextKey}\". ` +\n 'A different class is already registered under the target key.',\n 'CONFIG_REGISTRY_PROMOTION_COLLISION',\n {\n existingKey,\n nextKey,\n className: name,\n },\n );\n }\n\n classes.delete(existingKey);\n classes.set(nextKey, existing);\n }\n\n getConstructorIndex().set(ctor, nextKey);\n\n // Release C follow-up #1139 Gap 2: we just mutated `existing.name`,\n // `existing.packageName`, `existing.qualifiedName`, `existing.config`,\n // `existing.constructor`, and `existing.schema.tableName`. Any\n // descendant whose cached `inheritedFields` was computed against the\n // prior identity now carries stale data. Invalidate `existing` and\n // every descendant whose `extends` matches the pre- or post-mutation\n // identity so the next field read re-merges from the current state.\n invalidateInheritanceEntries(existing, previousIdentity);\n\n return nextKey;\n }\n\n // Release C (#1134): collision resolution for both exact-match and\n // case-insensitive paths now routes through decideCollisionPolicy, which\n // consolidates the 11-branch if/else tree from pre-C.\n const newSourceFile = getSourceFileFromStack();\n const newInBundledContext = isBundledOutputPath(newSourceFile);\n\n // Generated consumer registration carries both an explicit package and the\n // exact constructor imported from the production bundle. Treat that pair as\n // authoritative identity: discard the earlier decorator registration (whose\n // runtime name/package may have been rewritten by bundling) and rebuild it\n // from the isolated manifest so fields, schema, and decorator config all\n // come from the correct object. This avoids guessing identity from paths,\n // names, or derived table names.\n const constructorKey = getConstructorIndex().get(ctor);\n const constructorEntry = constructorKey\n ? getClasses().get(constructorKey)\n : undefined;\n if (\n constructorKey &&\n constructorEntry &&\n Object.is(constructorEntry.constructor, ctor)\n ) {\n if (explicitPackageName && isolatedManifestEntry) {\n const targetKey = createQualifiedName(explicitPackageName, name);\n const targetEntry = getClasses().get(targetKey);\n const targetCollectionConstructor = targetEntry?.collectionConstructor;\n const targetIsManifestStub =\n targetEntry &&\n targetEntry !== constructorEntry &&\n (targetEntry.constructor as { _isManifestStub?: boolean })\n ._isManifestStub === true;\n\n if (\n targetEntry &&\n targetEntry !== constructorEntry &&\n !targetIsManifestStub\n ) {\n throw new ConfigurationError(\n `Class registry collision while promoting \"${constructorKey}\" to \"${targetKey}\". ` +\n 'A different class is already registered under the target key.',\n 'CONFIG_REGISTRY_PROMOTION_COLLISION',\n { existingKey: constructorKey, nextKey: targetKey, className: name },\n );\n }\n\n promotedCollectionConstructor =\n constructorEntry.collectionConstructor || targetCollectionConstructor;\n // Generated manifests are JSON data and cannot carry runtime-only\n // values such as function-valued lifecycle hooks. Preserve the exact\n // constructor's decorator-time config as the lowest-priority layer;\n // the authoritative manifest and explicit generated config still win\n // for serializable identity, schema, and policy fields.\n promotedRuntimeConfig = constructorEntry.config;\n getClasses().delete(constructorKey);\n getConstructorIndex().delete(ctor);\n if (targetIsManifestStub && targetEntry) {\n getClasses().delete(targetKey);\n getConstructorIndex().delete(targetEntry.constructor);\n }\n } else {\n upsertExistingEntry(constructorKey, constructorEntry);\n return;\n }\n }\n\n // The class's package identity: an explicit `packageName`; else the\n // package owning the declaring file (stack-derived) when that package\n // declares the class; else the package whose loaded manifest describes the\n // declaring file (a workspace package's source scanned into an app's\n // manifest, #3110); else the stack-derived package, unconfirmed.\n const stackPackageName = explicitPackageName\n ? undefined\n : getPackageName(ctor, true) || undefined;\n const stackPackageDeclaresClass =\n !!stackPackageName &&\n packageDeclaresClass(\n stackPackageName,\n createQualifiedName(stackPackageName, name),\n );\n const sourceManifestPackage =\n explicitPackageName || stackPackageDeclaresClass\n ? undefined\n : findManifestPackageForSource(name, newSourceFile, stackPackageName);\n const newPackageName =\n explicitPackageName ||\n sourceManifestPackage?.packageName ||\n stackPackageName;\n\n // #3098: when this constructor's own package is known and that package\n // declares this class (its manifest stub or an earlier registration sits\n // under the qualified key, or its manifest describes it), never adopt\n // another package's same-named registration below — `Account` exists in\n // both smrt-ledgers and smrt-messages, and a simple-name match would hand\n // one package's constructor the other's fields and table.\n const ownQualifiedKey = newPackageName\n ? createQualifiedName(newPackageName, name)\n : undefined;\n const ownPackageDeclaresClass =\n !!ownQualifiedKey &&\n (!!explicitPackageName ||\n stackPackageDeclaresClass ||\n !!sourceManifestPackage);\n const belongsToAnotherPackage = (existing: RegisteredClass): boolean =>\n ownPackageDeclaresClass &&\n !!existing.packageName &&\n existing.packageName !== newPackageName;\n\n // 1. Exact-match check (existingKey === name)\n const exactExisting = getClasses().get(name);\n if (exactExisting && !belongsToAnotherPackage(exactExisting)) {\n const existing = exactExisting;\n const handled = applyRegisterCollisionPolicy({\n ctor,\n name,\n newPackageName,\n newSourceFile,\n newInBundledContext,\n newDeclaredTableName: config.tableName,\n existing,\n existingKey: name,\n matchKind: 'exact-key',\n upsertExistingEntry,\n });\n if (handled) return;\n }\n\n // 2. Case-insensitive check for manifest stubs (Issue #531, #847) and\n // other same-name-different-case collisions.\n const lowerName = name.toLowerCase();\n for (const [existingKey, existing] of getClasses().entries()) {\n const keyMatches = existingKey.toLowerCase() === lowerName;\n const nameMatches = existing.name?.toLowerCase() === lowerName;\n if (!(keyMatches || nameMatches) || existingKey === name) continue;\n\n // Distinct explicitly named packages are intentionally allowed to export\n // the same simple class name. Their qualified keys are unambiguous; do not\n // route them through the bundled-duplicate collision policy.\n if (\n explicitPackageName &&\n existing.packageName &&\n explicitPackageName !== existing.packageName &&\n isQualifiedName(existingKey)\n ) {\n continue;\n }\n // The same holds for a package identity the registry already knows this\n // class under (see ownPackageDeclaresClass above, #3098).\n if (belongsToAnotherPackage(existing)) {\n continue;\n }\n\n const handled = applyRegisterCollisionPolicy({\n ctor,\n name,\n newPackageName,\n newSourceFile,\n newInBundledContext,\n newDeclaredTableName: config.tableName,\n existing,\n existingKey,\n matchKind: 'case-insensitive',\n upsertExistingEntry,\n });\n if (handled) return;\n }\n\n // CRITICAL: Capture package name NOW, while stack trace still shows external package\n // This is called from the @smrt() decorator during import, so the stack trace\n // includes the external package file path. Later calls won't have this context.\n // Skip registry check to avoid circular dependency - class isn't registered yet!\n // This solves issue #159 where external package manifests couldn't be loaded.\n const packageNameFromStack = newPackageName;\n\n // Capture source file path for collision detection during module re-evaluation\n // (Issue #555: Test isolation - class name collision during vitest collection)\n const sourceFilePath = getSourceFileFromStack();\n\n // Get field definitions from manifest\n // Priority order (Issue #270 Phase 1 - synchronous manifest loading):\n // 1. Explicitly provided manifest (_manifest parameter)\n // 2. Test manifests (for test classes)\n // 3. Static manifests (for core framework classes)\n // 4. Cached external manifests (if already loaded)\n // For external packages not yet loaded, manifest discovery happens lazily during schema generation\n // Issue #713: Use lookupInManifest for qualified name support\n // The simple-name entry is a last resort for a class with a known package\n // identity. It never applies while another package registers a class of\n // this name, and a stack-derived identity nothing confirmed (outside\n // bundled output, where the stack package is the declaring file's own) also\n // refuses an entry another package owns: an app manifest that declares a\n // dependency loads that dependency's manifest before any of its classes\n // register, and its same-named entry would otherwise hand a consumer class\n // the dependency's identity, fields and table (#3106). In bundled output\n // (where the stack package is the bundle's) the entry is refused only when\n // the table the decorator resolved for the class differs from the entry's.\n // A class whose package is unknown still refuses a packaged entry that\n // describes another file (#3112): bundled output keeps it, where the stack\n // cannot name the declaring package, as for a stack-derived identity.\n const unknownPackageManifestEntry = () => {\n const entry = discoverManifestSync(name);\n if (\n !entry?.packageName ||\n newInBundledContext ||\n isSameSourcePath(newSourceFile, entry.filePath)\n ) {\n return entry;\n }\n return undefined;\n };\n const simpleNameManifestFallback = () => {\n if (\n findClassesByName(name).some(\n (candidate) =>\n !!candidate.packageName && candidate.packageName !== newPackageName,\n )\n ) {\n return undefined;\n }\n const entry = discoverManifestSync(name);\n const foreignEntry =\n !!entry?.packageName && entry.packageName !== newPackageName;\n if (!foreignEntry) return entry;\n // Another package's entry describes this class only when it describes\n // this class's own file: a class scanned into another package's\n // manifest under that package's key (core's own fixtures with an\n // explicit `packageName`, #3098).\n if (isSameSourcePath(newSourceFile, entry?.filePath)) return entry;\n if (ownPackageDeclaresClass) return undefined;\n const entryTable =\n entry?.schema?.tableName || entry?.decoratorConfig?.tableName;\n const declaresOtherTable =\n !!config.tableName && !!entryTable && config.tableName !== entryTable;\n return !newInBundledContext || declaresOtherTable ? undefined : entry;\n };\n let manifestEntry: ReturnType<typeof lookupInManifest> | undefined;\n if (config._manifest) {\n manifestEntry = lookupRegistrationManifest(\n config._manifest,\n name,\n explicitPackageName,\n config._manifestKey,\n );\n }\n if (!manifestEntry) {\n // A class whose own package is known resolves its manifest by qualified\n // identity only; a simple-name lookup could return another package's\n // same-named class (#3098).\n // When that identity has no manifest entry (e.g. an explicit\n // `packageName` on a class scanned into another package's manifest), the\n // simple-name entry still applies unless another package registers a\n // class of this name.\n // The same guard applies to an unconfirmed package identity: another\n // package's same-named entry must not become this class's manifest\n // (#3106).\n manifestEntry = ownQualifiedKey\n ? (discoverManifestSync(ownQualifiedKey) ??\n sourceManifestPackage?.entry ??\n simpleNameManifestFallback())\n : unknownPackageManifestEntry();\n }\n const runtimeTenantScopedDeclaration =\n getConstructorTenantScopedDeclarations().get(ctor);\n if (\n manifestEntry &&\n config.tenantScoped === undefined &&\n normalizeTenantScopedConfig(manifestEntry.decoratorConfig?.tenantScoped) ===\n undefined &&\n runtimeTenantScopedDeclaration\n ) {\n throw new ConfigurationError(\n `Manifest for '${name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`,\n 'CONFIG_TENANT_MANIFEST_CONFLICT',\n );\n }\n const fields = new Map<string, RegisteredField>();\n const methods = new Map<string, MethodDefinition>();\n let packageName: string | undefined;\n\n verboseLog(\n `[registry] Registering ${name}: manifestEntry =`,\n manifestEntry ? 'found' : 'not found',\n );\n if (manifestEntry?.fields) {\n verboseLog(\n `[registry] Manifest has ${Object.keys(manifestEntry.fields).length} fields:`,\n Object.keys(manifestEntry.fields),\n );\n }\n\n if (manifestEntry?.fields) {\n // Use manifest fields (from build-time AST scanning)\n // Store field definitions as plain objects with nested options\n for (const [fieldName, fieldDef] of Object.entries(\n manifestEntry.fields,\n ) as [string, FieldDefinition][]) {\n // Build options object, only including defined values\n const options: Record<string, unknown> = { ...fieldDef._meta };\n if (fieldDef.required !== undefined) options.required = fieldDef.required;\n if (fieldDef.default !== undefined) options.default = fieldDef.default;\n if (fieldDef.description !== undefined)\n options.description = fieldDef.description;\n if (fieldDef.transient !== undefined)\n options.transient = fieldDef.transient;\n\n // Store field definition as plain object maintaining Field-like structure\n const field: RegisteredField = {\n type: fieldDef.type,\n };\n\n // Only include options if not empty\n if (Object.keys(options).length > 0) {\n field._meta = options;\n }\n\n // Preserve top-level flags from manifest\n if (fieldDef.transient !== undefined) {\n field.transient = fieldDef.transient;\n }\n if (fieldDef.required !== undefined) {\n field.required = fieldDef.required;\n }\n if (fieldDef.sensitive !== undefined) {\n field.sensitive = fieldDef.sensitive;\n }\n if (fieldDef.readonly !== undefined) {\n field.readonly = fieldDef.readonly;\n }\n if (fieldDef.readPermission !== undefined) {\n field.readPermission = fieldDef.readPermission;\n }\n\n // Hoist related to top level for relationship fields\n // Check both fieldDef.related (new manifests) and _meta.related (old manifests)\n if (fieldDef.related !== undefined) {\n field.related = fieldDef.related;\n } else if (options.related !== undefined) {\n // `related` carries the related class name (always a string at runtime).\n field.related = options.related as string;\n delete field._meta?.related;\n }\n\n fields.set(fieldName, field);\n }\n\n verboseLog(\n `[registry] ✅ Loaded ${fields.size} fields for ${name} from manifest`,\n );\n\n // Use packageName from manifest if available, otherwise from stack trace\n // Priority: explicit manifest > manifestEntry > stack trace\n packageName =\n explicitPackageName ||\n config._manifest?.packageName ||\n manifestEntry.packageName ||\n packageNameFromStack;\n } else {\n // No manifest found yet - use package name from stack trace\n // This will be used later by ensureManifestLoaded() to load the external manifest\n verboseLog(\n `[registry] ⚠️ No manifest entry for ${name} - fields will be loaded later`,\n );\n packageName = packageNameFromStack;\n }\n\n // Apply decorator metadata to override/extend manifest fields\n // Decorators take priority over AST-scanned types (Issue #316)\n const decoratorKey = isolatedManifestEntry ? ctor.name : name;\n // Only explicit string-only registrations are ownerless legacy metadata.\n // Public decorators also expose a simple-name inspection mirror, but that\n // mirror must never become another constructor's schema.\n const simpleDecorators = getLegacyFieldDecorators().get(decoratorKey);\n const constructorDecorators = getConstructorFieldDecorators().get(ctor);\n const decorators = new Map(simpleDecorators);\n for (const [fieldName, options] of constructorDecorators ?? []) {\n decorators.set(fieldName, { ...decorators.get(fieldName), ...options });\n }\n if (decorators && decorators.size > 0) {\n verboseLog(\n `[registry] Applying ${decorators.size} field decorators for ${name}`,\n );\n\n for (const [fieldName, decoratorOptions] of decorators) {\n // Typed read-view of the raw `Record<string, unknown>` decorator bag so\n // the member reads below narrow to the `RegisteredField` member types\n // they feed (instead of `unknown`). Same runtime object, type-only view.\n const opts: DecoratorFieldOptions = decoratorOptions;\n const existingField = fields.get(fieldName);\n\n if (existingField) {\n // Merge decorator options with manifest field\n // Decorator type takes priority over AST-scanned type\n const mergedMeta: FieldMeta = {\n ...existingField._meta,\n ...decoratorOptions,\n };\n const mergedField: RegisteredField = {\n type: opts.type || existingField.type,\n _meta: mergedMeta,\n };\n\n // Remove 'type' from _meta if it was moved to top level\n if (mergedMeta.type) {\n delete mergedMeta.type;\n }\n\n // Preserve top-level flags (transient, required, etc.)\n if (opts.transient !== undefined) {\n mergedField.transient = opts.transient;\n } else if (existingField.transient !== undefined) {\n mergedField.transient = existingField.transient;\n }\n if (opts.sensitive !== undefined) {\n mergedField.sensitive = opts.sensitive;\n } else if (existingField.sensitive !== undefined) {\n mergedField.sensitive = existingField.sensitive;\n }\n if (opts.readonly !== undefined) {\n mergedField.readonly = opts.readonly;\n } else if (existingField.readonly !== undefined) {\n mergedField.readonly = existingField.readonly;\n }\n if (typeof opts.readPermission === 'string') {\n mergedField.readPermission = opts.readPermission;\n } else if (typeof existingField.readPermission === 'string') {\n mergedField.readPermission = existingField.readPermission;\n }\n\n // Handle required flag: nullable fields should not be required\n if (opts.nullable === true) {\n // Nullable explicitly set to true means field is NOT required\n mergedField.required = false;\n mergedMeta.required = false;\n } else if (opts.required !== undefined) {\n mergedField.required = opts.required;\n } else if (existingField.required !== undefined) {\n mergedField.required = existingField.required;\n }\n\n // Hoist related to top level for relationship fields\n if (opts.related !== undefined) {\n mergedField.related = opts.related;\n delete mergedField._meta?.related;\n } else if (existingField.related !== undefined) {\n mergedField.related = existingField.related;\n }\n\n fields.set(fieldName, mergedField);\n verboseLog(\n `[registry] ✅ Merged decorator for ${fieldName}: type=${mergedField.type}`,\n );\n } else {\n // Decorator for field not in manifest - add it\n const newMeta: FieldMeta = decoratorOptions;\n const newField: RegisteredField = {\n type: opts.type || 'text',\n _meta: newMeta,\n };\n\n // Set top-level flags from decorator options\n if (opts.transient !== undefined) {\n newField.transient = opts.transient;\n }\n if (opts.sensitive !== undefined) {\n newField.sensitive = opts.sensitive;\n }\n if (opts.readonly !== undefined) {\n newField.readonly = opts.readonly;\n }\n if (typeof opts.readPermission === 'string') {\n newField.readPermission = opts.readPermission;\n }\n // Handle required flag: nullable fields should not be required\n if (opts.nullable === true) {\n newField.required = false;\n newMeta.required = false;\n } else if (opts.required !== undefined) {\n newField.required = opts.required;\n }\n\n // Hoist related to top level for relationship fields (Issue #746)\n // This is critical for getRelationshipMap() to detect relationships\n if (opts.related !== undefined) {\n newField.related = opts.related;\n delete newField._meta?.related;\n }\n\n fields.set(fieldName, newField);\n verboseLog(\n `[registry] ✅ Added field ${fieldName} from decorator: type=${opts.type || 'text'}`,\n );\n }\n }\n }\n\n // Handle tenantScoped configuration (Issue #688)\n // External manifests can carry tenantScoped only in decoratorConfig, so\n // registration must honor the merged view rather than only explicit config.\n // `@TenantScoped()` is intentionally implemented by smrt-tenancy, not core;\n // when a standalone runtime imports an external model before its manifest is\n // cached, the tenant field decorator is the core-visible declaration of that\n // contract. Preserve it here so runtime registration and the manifest path\n // agree on the conflict target (#2763).\n let tenantScopedConfig: RegisteredClass['tenantScopedConfig'] | undefined;\n const constructorTenantScopedDeclaration = manifestEntry\n ? undefined\n : (runtimeTenantScopedDeclaration as\n | RegisteredClass['tenantScopedConfig']\n | undefined);\n const fieldTenantScopedConfig = tenantScopedConfigFromFieldMetadata(fields);\n const tenantScopedConfigSource: RegisteredClass['tenantScopedConfigSource'] =\n config.tenantScoped !== undefined\n ? 'explicit'\n : manifestEntry?.decoratorConfig?.tenantScoped !== undefined\n ? 'manifest'\n : manifestEntry\n ? 'manifest'\n : constructorTenantScopedDeclaration\n ? 'tenant-decorator'\n : fieldTenantScopedConfig\n ? 'field-fallback'\n : undefined;\n const effectiveTenantScoped =\n config.tenantScoped ??\n manifestEntry?.decoratorConfig?.tenantScoped ??\n (manifestEntry\n ? undefined\n : (constructorTenantScopedDeclaration ?? fieldTenantScopedConfig));\n if (effectiveTenantScoped) {\n tenantScopedConfig = normalizeTenantScopedConfig(effectiveTenantScoped);\n if (!tenantScopedConfig) return;\n\n // Inject or enrich tenantId field\n const fieldName = tenantScopedConfig.field;\n const hadTenantField = fields.has(fieldName);\n ensureTenantScopedField(fields, tenantScopedConfig);\n if (!hadTenantField) {\n verboseLog(\n `[registry] ✅ Injected ${fieldName} field for tenant-scoped class ${name}`,\n );\n }\n }\n\n if (manifestEntry?.methods) {\n // Load method definitions from manifest (for custom CLI/API/MCP generation)\n for (const [methodName, methodDef] of Object.entries(\n manifestEntry.methods,\n )) {\n methods.set(methodName, methodDef);\n }\n }\n\n // Also load methods from _manifestMethods in config (from consumer plugin register.js)\n // This is how external package methods are passed to the registry.\n // `_manifestMethods` is an undeclared escape-hatch carried on the config bag\n // by generated consumer `register.js`, so read it through a narrowed view.\n const manifestMethods = (\n config as unknown as {\n _manifestMethods?: Record<string, MethodDefinition>;\n }\n )._manifestMethods;\n if (manifestMethods) {\n for (const [methodName, methodDef] of Object.entries(manifestMethods)) {\n methods.set(methodName, methodDef);\n }\n verboseLog(\n `[registry] Loaded ${methods.size} methods for ${name} from _manifestMethods`,\n );\n }\n\n // Note: If manifest not found here, it will be loaded asynchronously when needed\n // via ensureManifestLoaded(). This allows decorators to remain synchronous while\n // supporting dynamic external package manifest loading.\n\n // Build inheritance chain from constructor (needed for STI table name resolution)\n const inheritanceChain = buildInheritanceChain(ctor);\n\n // Validate table strategy compatibility with parent (STI requirement)\n if (inheritanceChain.length > 1) {\n // This class has a parent - validate strategy compatibility\n const parentName = inheritanceChain[inheritanceChain.length - 2]; // Second-to-last is parent\n const parentEntry = findClass(parentName);\n\n // A framework base class (SmrtObject, SmrtHierarchical, SmrtJunction, …)\n // has no independent existence as a resource and carries no `@smrt()`\n // decorator of its own (see framework-base-classes.ts) — any table\n // strategy it appears to have once registered is just the registry's\n // undecorated-entry default, not an authored constraint later\n // subclasses must match. Every other one of this identity check's nine\n // existing call sites already exempts these classes; this STI-strategy\n // consistency check must too, or a framework base class that reaches\n // `ObjectRegistry` before its first concrete decorated descendant (e.g.\n // via #2750's worker-side manifest bulk-registration bulk-loading\n // `@happyvertical/smrt-core`'s manifest, which lists every class\n // extending `SmrtObject` including undecorated abstract bases) makes\n // that descendant's OWN, correctly-declared `tableStrategy` look like a\n // mismatch against its abstract parent's meaningless placeholder one.\n const parentIsFrameworkBase =\n parentEntry !== undefined &&\n isFrameworkBaseClass(parentEntry.name, parentEntry.packageName);\n\n if (parentEntry && !parentIsFrameworkBase) {\n const parentStrategy = parentEntry.config?.tableStrategy || 'default';\n const childStrategy = config.tableStrategy; // Don't default - undefined means inherit\n\n // Only validate if child has an EXPLICIT strategy that differs from parent\n // undefined childStrategy means it will inherit from parent\n if (childStrategy !== undefined && parentStrategy !== childStrategy) {\n throw ConfigurationError.incompatibleStrategy(\n name,\n childStrategy,\n parentName,\n parentStrategy,\n );\n }\n }\n }\n\n // Defer schema generation until needed (generateSchema now uses dynamic import)\n // Store table name for lazy schema generation\n // Priority for STI: manifest's tableName > decorator config > derived from class name\n // The manifest's tableName is computed at build-time when full class hierarchy is known,\n // which correctly handles STI inheritance. The decorator may derive wrong tableName\n // if parent class isn't registered yet at decorator execution time.\n // The table comes from the manifest entry selected above, which already\n // refuses another package's same-named entry: a fresh simple-name lookup\n // here bound a consumer's `LicenseSale` (`license_sales`) to smrt-commerce's\n // `contracts` table (#3106).\n const tableName =\n manifestEntry?.schema?.tableName ||\n manifestEntry?.decoratorConfig?.tableName ||\n config.tableName ||\n tableNameFromClass(ctor);\n setSmrtTableName(ctor, tableName);\n\n // Load pre-generated schema from manifest if available, otherwise placeholder\n let schema: SchemaDefinition;\n if (manifestEntry?.schema) {\n // Pre-generated schema from manifest (build-time)\n // Keep indexes as IndexDefinition objects for DDL strategies\n schema = {\n ddl: manifestEntry.schema.ddl,\n indexes:\n manifestEntry.schema.indexes?.map((idx: IndexDefinition) => ({\n name: idx.name,\n columns: idx.columns || [],\n unique: idx.unique || false,\n ...(idx.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: idx.where,\n description: idx.description,\n jsonPath: idx.jsonPath,\n })) || [],\n triggers: [],\n tableName: manifestEntry.schema.tableName || tableName,\n // Cast manifest columns to ColumnDefinition (same shape, TypeScript just needs help)\n columns: cloneManifestSchemaColumns(manifestEntry.schema.columns),\n foreignKeys: [],\n dependencies: [],\n version: manifestEntry.schema.version || '',\n packageName: manifestEntry.packageName,\n };\n verboseLog(\n `[registry] Loaded pre-generated schema for ${name} (${Object.keys(manifestEntry.schema.columns || {}).length} columns)`,\n );\n } else {\n // Placeholder schema - will be generated lazily when first needed\n schema = {\n ddl: '', // Generated lazily\n indexes: [], // Parsed from DDL lazily\n triggers: [], // No longer using database triggers - timestamps managed by application\n tableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n packageName: undefined,\n };\n }\n\n if (schema.columns) {\n applySqlTypeOverrides(schema.columns, fields.entries());\n if (decorators && decorators.size > 0) {\n applySqlTypeOverrides(schema.columns, decorators.entries());\n }\n }\n\n // Use pre-computed validation rules from manifest if available (Issue #782)\n // For decorator-based registration, manifest may have pre-computed rules\n const validationRules = manifestEntry?.validationRules;\n let validators: ValidatorFunction[] | undefined;\n\n // Only compile validators if no pre-computed rules exist\n if (validationRules === undefined) {\n validators = compileValidators(name, fields);\n } else {\n verboseLog(\n `[registry] Using ${validationRules.length} pre-computed validation rules for ${name}`,\n );\n }\n\n // Derive extends from prototype chain if not available from manifest\n // This is critical for inline test classes that use decorators\n let extendsClass: string | undefined = manifestEntry?.extends;\n if (!extendsClass) {\n const proto = Object.getPrototypeOf(ctor);\n if (proto?.name && proto.name !== 'SmrtObject' && proto.name !== 'Object') {\n extendsClass = proto.name;\n }\n }\n\n // Merge manifest's decoratorConfig into config\n // Use the computed tableName which prioritizes manifest's value for STI correctness\n const mergedConfig = {\n ...promotedRuntimeConfig,\n ...manifestEntry?.decoratorConfig,\n ...config,\n tableName, // Override with correctly computed tableName\n // `sensitive` is an OR across every source, not last-wins (#2937). Ordinary\n // spread precedence would let an explicit `sensitive: false` from a\n // lower-priority-but-later source erase a `true` — for instance a stale\n // manifest disagreeing with the class — which is a silent fail-OPEN in a\n // control documented as one-way (\"`sensitive: false` is not an opt-out\").\n // Only `=== true` is meaningful anywhere, so OR is the whole rule.\n ...(anySensitive(\n promotedRuntimeConfig,\n manifestEntry?.decoratorConfig,\n config,\n )\n ? { sensitive: true as const }\n : {}),\n };\n\n // Declare from the MERGED config, not the raw one: generated consumer\n // registration passes the declaration through `manifestEntry.decoratorConfig`\n // rather than the call's own `config` (#2937). Both the resolved name and the\n // schema's own, which can differ.\n declareSensitiveTable(\n mergedConfig,\n tableName,\n schema?.tableName,\n manifestEntry?.schema?.tableName,\n );\n\n // Generate qualified name if we have a package name\n // Format: \"@package/name:ClassName\"\n const qualifiedName = packageName\n ? createQualifiedName(packageName, name)\n : undefined;\n\n // Determine visibility from config, manifest, or default to 'public'\n // Priority: explicit config > manifest > default\n const visibility: SmrtVisibility =\n config.visibility || manifestEntry?.visibility || 'public';\n\n // Issue #951: Use qualified name as primary key when available\n const registrationKey = qualifiedName || name;\n\n const registration: RegisteredClass = {\n name,\n qualifiedName, // Qualified name for cross-package identification\n constructor: ctor,\n config: mergedConfig,\n fields,\n methods,\n schema,\n validators,\n validationRules, // Pre-computed rules from manifest (Issue #782)\n tools: manifestEntry?.tools, // AI-callable tool schemas (CLI param schemas)\n // Pluralized endpoint name. Prefer the manifest's computed value (handles\n // STI inheritance + any future inflection changes); fall back to the same\n // simple pluralization the scanner uses for inline/test classes that have\n // no manifest entry. (smrt#1311.) An STI subtype with no manifest entry\n // takes its registered STI base's, as the manifest would (#3125).\n collection:\n manifestEntry?.collection ??\n inheritedStiCollection(ctor) ??\n pluralizeCollection(name),\n collectionConstructor: promotedCollectionConstructor,\n packageName, // Store package name from manifest for getPackageName() lookup\n sourceFilePath, // Store source file for collision detection (Issue #555)\n extends: extendsClass, // Capture parent class name from manifest OR prototype chain\n extendsTypeArg: manifestEntry?.extendsTypeArg, // SmrtCollection<T> generic arg\n tenantScopedConfig, // Multi-tenancy config (Issue #688)\n tenantScopedConfigSource,\n visibility, // Visibility control for manifest filtering\n // NOTE: Don't pre-compute inheritanceChain here - let getInheritanceChain() compute\n // it lazily using the `extends` field. This ensures correct chain for both\n // decorator-registered and manifest-loaded classes.\n };\n // #3338: a deprecated alias must never name a second live class.\n assertQualifiedNameAliasesAvailable(registrationKey, registration);\n getClasses().set(registrationKey, registration);\n\n // Release B (#1133): case-insensitive lookups iterate the classes Map\n // directly instead of maintaining a parallel classNameMap index.\n\n // Index constructor for O(1) reverse lookups (Issue #713: constructor-based lookup)\n getConstructorIndex().set(ctor, registrationKey);\n // Stamp the qualified name on the constructor itself as a fallback for\n // runtime code that has a constructor reference but might hit a\n // WeakMap miss (HMR / federated modules / multiple-copy edge cases).\n setSmrtQualifiedName(ctor, qualifiedName);\n\n verboseLog(\n `🎯 Registered smrt object: ${name} (key: ${registrationKey}) with schema for ${schema.tableName} and ${(validators?.length || 0) + (validationRules?.length || 0)} validators/rules`,\n );\n\n // STI sibling auto-loading (Issue #430)\n // When a class is registered that shares a table with other classes (STI),\n // we need to discover and register ALL siblings so that getAllSchemas()\n // can merge columns from all subtypes for the database adapter.\n //\n // IMPORTANT: Only auto-load siblings from EXTERNAL packages.\n // For test classes or classes in the same package, they will be registered\n // by their own @smrt() decorators. Auto-loading them as stubs would cause collisions.\n const collection = manifestEntry?.collection;\n if (collection && !getStiSiblingsLoaded().has(collection)) {\n // Mark this collection as processed to prevent infinite recursion\n getStiSiblingsLoaded().add(collection);\n\n verboseLog(\n `[registry] Checking for STI siblings for collection: ${collection}`,\n );\n\n // Discover all classes that share this collection (table)\n const siblings = discoverSTISiblingsSync(collection);\n\n // Register any siblings that aren't already registered\n // Only load siblings from DIFFERENT packages to avoid collisions with local classes\n for (const sibling of siblings) {\n // Use case-insensitive check to prevent registering 'Praeco' when 'praeco' exists\n if (!hasClassCaseInsensitive(sibling.className)) {\n // Skip siblings from the same package - they will be registered by their own decorators\n if (\n sibling.packageName &&\n packageName &&\n sibling.packageName === packageName\n ) {\n verboseLog(\n `[registry] Skipping STI sibling ${sibling.className} from same package: ${packageName}`,\n );\n continue;\n }\n\n verboseLog(\n `[registry] Auto-loading STI sibling: ${sibling.className} for collection: ${collection}`,\n );\n registerFromManifest(\n sibling.className,\n sibling.entry,\n sibling.packageName,\n );\n }\n }\n }\n}\n\n/**\n * Resolve the core-visible tenancy contract from a `@tenantId()` field when a\n * runtime registration has no manifest entry. `@TenantScoped()` lives in the\n * tenancy package, so core cannot import its registry without a cycle; the\n * field decorator runs before `@smrt()`. A nullable tenant identifier is the\n * runtime representation of optional tenancy used by that decorator.\n */\nfunction tenantScopedConfigFromFieldMetadata(\n fields: Map<string, RegisteredField>,\n): SmartObjectConfig['tenantScoped'] | undefined {\n for (const [fieldName, field] of fields) {\n const tenancy = field._meta?.__tenancy as\n | {\n isTenantIdField?: unknown;\n mode?: unknown;\n field?: unknown;\n autoFilter?: unknown;\n autoPopulate?: unknown;\n allowSuperAdminBypass?: unknown;\n }\n | undefined;\n if (tenancy?.isTenantIdField !== true) continue;\n\n return {\n mode:\n tenancy.mode === 'required'\n ? 'required'\n : tenancy.mode === 'optional' || field._meta?.nullable === true\n ? 'optional'\n : 'required',\n field: typeof tenancy.field === 'string' ? tenancy.field : fieldName,\n autoFilter: tenancy.autoFilter !== false,\n autoPopulate: tenancy.autoPopulate !== false,\n allowSuperAdminBypass: tenancy.allowSuperAdminBypass === true,\n };\n }\n return undefined;\n}\n\nexport function registerCollection(\n objectName: string,\n // `new (options: any) => SmrtCollection<any>` is the irreducible\n // collection-constructor shape (S4 #1579): the public\n // `ObjectRegistry.registerCollection` wrapper hands a non-generic constructor\n // of exactly this form, which is not assignable to the generic\n // `typeof SmrtCollection`. Mirrors `RegisteredClass.collectionConstructor`.\n collectionConstructor: NonNullable<RegisteredClass['collectionConstructor']>,\n): void {\n const registered = findClass(objectName);\n if (registered) {\n registered.collectionConstructor = collectionConstructor;\n }\n\n // The collections map stores `typeof SmrtCollection`; the runtime value is a\n // SmrtCollection subclass constructor. Bridge the loose constructor shape to\n // the map's element type without `any`.\n getCollections().set(\n objectName,\n collectionConstructor as unknown as Parameters<\n ReturnType<typeof getCollections>['set']\n >[1],\n );\n}\n\n// resolveManifestCollision was removed in Release C (#1134). Its three-branch\n// decision is now represented as explicit rows in the collision-policy\n// decision table — see `manifest-same-source-file`, `manifest-sti-child-wins`,\n// `manifest-sti-parent-skip`, `manifest-default-skip` scenarios in\n// packages/core/src/registry/collision-policy.ts.\n\ntype TenantScopedOptions = Exclude<\n SmartObjectConfig['tenantScoped'],\n boolean | undefined\n>;\n\nfunction normalizeTenantScopedConfig(\n tenantScoped: SmartObjectConfig['tenantScoped'],\n): RegisteredClass['tenantScopedConfig'] | undefined {\n if (!tenantScoped) {\n return undefined;\n }\n\n const tenantOpts: TenantScopedOptions =\n typeof tenantScoped === 'boolean' ? {} : tenantScoped;\n return {\n mode: tenantOpts.mode ?? 'required',\n field: tenantOpts.field ?? 'tenantId',\n autoFilter: tenantOpts.autoFilter ?? true,\n autoPopulate: tenantOpts.autoPopulate ?? true,\n allowSuperAdminBypass: tenantOpts.allowSuperAdminBypass ?? false,\n };\n}\n\nexport function ensureTenantScopedField(\n fields: Map<string, RegisteredField>,\n tenantScopedConfig: RegisteredClass['tenantScopedConfig'] | undefined,\n): void {\n if (!tenantScopedConfig) {\n return;\n }\n // Mutates a registered class's field map in place (#3047).\n bumpRegistryGeneration();\n\n const fieldName = tenantScopedConfig.field;\n const existingField = fields.get(fieldName);\n if (existingField) {\n fields.set(fieldName, {\n ...existingField,\n required:\n existingField.required ?? tenantScopedConfig.mode === 'required',\n _meta: {\n ...existingField._meta,\n reference: existingField._meta?.reference ?? 'Tenant',\n sqlType: 'UUID',\n __tenancy: {\n ...existingField._meta?.__tenancy,\n isTenantIdField: true,\n ...tenantScopedConfig,\n },\n },\n });\n return;\n }\n\n fields.set(fieldName, {\n type: 'foreignKey',\n related: 'Tenant',\n required: tenantScopedConfig.mode === 'required',\n _meta: {\n reference: 'Tenant',\n sqlType: 'UUID',\n __tenancy: {\n isTenantIdField: true,\n ...tenantScopedConfig,\n },\n },\n });\n}\n\nfunction mergeIndexDefinitions(\n existingIndexes: IndexDefinition[] | undefined,\n manifestIndexes: IndexDefinition[] | undefined,\n): IndexDefinition[] {\n const merged = [...(existingIndexes || [])];\n const seen = new Set(merged.map((index) => index?.name).filter(Boolean));\n\n for (const index of manifestIndexes || []) {\n if (!index?.name || seen.has(index.name)) {\n continue;\n }\n merged.push(index);\n seen.add(index.name);\n }\n\n return merged;\n}\n\n// cloneManifestSchemaColumns lives in ../manifest/store.ts — imported above.\n// (Hoisted out of the duplicate definition here and in registry.ts.)\n\n/**\n * Typed read-view of a raw decorator option bag.\n *\n * `getFieldDecorators()` stores decorator options as\n * `Map<string, Record<string, unknown>>`, so the individual reads come back as\n * `unknown` and won't narrow to the typed `RegisteredField` members they feed.\n * This interface re-types only the members the decorator-merge loop reads, with\n * exactly the target member types, and keeps the open index signature so a raw\n * `Record<string, unknown>` bag is assignable to it without `any`. (The bag's\n * runtime values are field-helper options; this view mirrors that contract.)\n */\ninterface DecoratorFieldOptions {\n type?: FieldDefinition['type'];\n required?: boolean;\n nullable?: boolean;\n transient?: boolean;\n sensitive?: boolean;\n readonly?: boolean;\n readPermission?: unknown;\n related?: string;\n [key: string]: unknown;\n}\n\n/**\n * Read-only field shape consumed by the SQL-type override helpers.\n *\n * `applySqlTypeOverrides` runs over two sources: the canonical\n * `Map<string, RegisteredField>` AND the raw decorator bag\n * (`Map<string, Record<string, unknown>>` from `getFieldDecorators()`). Both\n * satisfy this shape — every member is optional and the open index signature\n * matches both `RegisteredField`'s index signature and `Record<string, unknown>`\n * — so the helpers read the same overrides off either source without `any`.\n */\ninterface SqlTypeOverrideField {\n type?: unknown;\n sqlType?: unknown;\n __tenancy?: FieldMeta['__tenancy'];\n _meta?: FieldMeta;\n [key: string]: unknown;\n}\n\nfunction getReferenceKindFromFieldOptions(\n fieldOptions: SqlTypeOverrideField,\n): ColumnDefinition['referenceKind'] | undefined {\n if (\n fieldOptions?.__tenancy?.isTenantIdField ||\n fieldOptions?._meta?.__tenancy?.isTenantIdField\n ) {\n return 'tenantId';\n }\n\n if (fieldOptions?.type === 'foreignKey') {\n return 'foreignKey';\n }\n\n if (fieldOptions?.type === 'crossPackageRef') {\n return 'crossPackageRef';\n }\n\n return undefined;\n}\n\nfunction applySqlTypeOverrides(\n columns: Record<string, ColumnDefinition>,\n fieldEntries: Iterable<[string, SqlTypeOverrideField]> | undefined,\n): void {\n if (!fieldEntries) {\n return;\n }\n\n for (const [fieldName, fieldOptions] of fieldEntries) {\n const sqlType = fieldOptions?.sqlType ?? fieldOptions?._meta?.sqlType;\n const referenceKind = getReferenceKindFromFieldOptions(fieldOptions);\n if (!sqlType && !referenceKind) {\n continue;\n }\n\n const columnName = toSnakeCase(fieldName);\n const existingColumn = columns[columnName];\n if (!existingColumn) {\n continue;\n }\n\n columns[columnName] = {\n ...existingColumn,\n ...(sqlType\n ? { type: String(sqlType).toUpperCase() as ColumnDefinition['type'] }\n : {}),\n ...(referenceKind ? { referenceKind } : {}),\n };\n }\n}\n\n/**\n * Invalidate cached inheritance state (chain + inheritedFields +\n * inheritedMethods) on `existing` AND every descendant whose `extends` or\n * `inheritanceChain` references it.\n *\n * This covers both simple-name and qualified-name `extends` matches, which\n * is why `ObjectRegistry.invalidateInheritanceCache` delegates here (Release\n * C follow-up #1139 Gap 1 — the old recursive public helper only matched\n * `extends === className` by exact string, silently missing qualified\n * descendants like `@pkg:Parent`).\n *\n * `previousIdentity` is used by `upsertExistingEntry` (Gap 2): when a class\n * is promoted (its name/packageName/qualifiedName are mutated in place),\n * descendants registered against the pre-mutation identity need to be\n * invalidated too. Pass the pre-mutation `{ name, qualifiedName }` so this\n * sweep matches against both the old and new identity.\n *\n * Exported for the public `ObjectRegistry.invalidateInheritanceCache`\n * shim in registry.ts.\n */\nexport function invalidateInheritanceEntries(\n existing: RegisteredClass,\n previousIdentity?: {\n name?: string;\n qualifiedName?: string;\n },\n): void {\n bumpRegistryGeneration();\n const cache = getInheritanceCache();\n const affectedNames = new Set<string>();\n\n const remember = (name: string | undefined): void => {\n if (name) {\n affectedNames.add(name);\n }\n };\n\n const matchNames = new Set<string>();\n const rememberMatch = (name: string | undefined): void => {\n if (name) matchNames.add(name);\n };\n rememberMatch(existing.name);\n rememberMatch(existing.qualifiedName);\n rememberMatch(previousIdentity?.name);\n rememberMatch(previousIdentity?.qualifiedName);\n\n for (const name of matchNames) {\n remember(name);\n }\n\n for (const [key, candidate] of getClasses()) {\n const extendsMatches =\n !!candidate.extends && matchNames.has(candidate.extends);\n const chainMatches =\n !!candidate.inheritanceChain &&\n candidate.inheritanceChain.some((n) => matchNames.has(n));\n\n if (candidate === existing || extendsMatches || chainMatches) {\n candidate.inheritanceChain = undefined;\n candidate.inheritedFields = undefined;\n candidate.inheritedMethods = undefined;\n remember(key);\n remember(candidate.name);\n remember(candidate.qualifiedName);\n }\n }\n\n for (const name of affectedNames) {\n cache.delete(name);\n }\n}\n\nfunction mergeManifestIntoExistingRegistration(\n existing: RegisteredClass,\n objectDef: SmartObjectDefinition,\n packageName?: string,\n): void {\n const manifestConfig = objectDef.decoratorConfig || {};\n const runtimeTenantScopedDeclaration =\n getConstructorTenantScopedDeclarations().get(existing.constructor);\n if (\n existing.tenantScopedConfigSource !== 'explicit' &&\n normalizeTenantScopedConfig(manifestConfig.tenantScoped) === undefined &&\n runtimeTenantScopedDeclaration\n ) {\n throw new ConfigurationError(\n `Manifest for '${existing.qualifiedName || existing.name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`,\n 'CONFIG_TENANT_MANIFEST_CONFLICT',\n );\n }\n const manifestTableName =\n objectDef.schema?.tableName ||\n manifestConfig.tableName ||\n existing.schema?.tableName ||\n existing.config.tableName ||\n tableNameFromClass(existing.constructor);\n\n existing.config = {\n ...manifestConfig,\n ...existing.config,\n tableName: manifestTableName,\n // OR, never last-wins — see `anySensitive` (#2937).\n ...(anySensitive(manifestConfig, existing.config)\n ? { sensitive: true as const }\n : {}),\n };\n\n // The merge can move the recorded name onto the manifest's (#2937). Nothing\n // else on this path re-declares, so a sensitive class merged here would\n // otherwise keep its declaration on the pre-merge name only.\n declareSensitiveTable(\n existing.config,\n manifestTableName,\n objectDef.schema?.tableName,\n existing.schema?.tableName,\n );\n\n if (objectDef.fields) {\n for (const [fieldName, fd] of Object.entries(objectDef.fields)) {\n if (!existing.fields.has(fieldName)) {\n existing.fields.set(fieldName, createFieldFromManifest(fd));\n continue;\n }\n\n const existingField = existing.fields.get(fieldName);\n if (!existingField) {\n continue;\n }\n\n existing.fields.set(fieldName, mergeManifestField(existingField, fd));\n }\n }\n\n // An explicit core declaration remains authoritative. Otherwise a manifest\n // is authoritative even when it is silent: discard provisional decorator or\n // field-fallback tenancy so lazy manifest loading matches preloaded runtime.\n if (existing.tenantScopedConfigSource !== 'explicit') {\n const tenantScopedConfig = normalizeTenantScopedConfig(\n manifestConfig.tenantScoped,\n );\n existing.tenantScopedConfig = tenantScopedConfig;\n existing.tenantScopedConfigSource = 'manifest';\n if (tenantScopedConfig) {\n ensureTenantScopedField(existing.fields, tenantScopedConfig);\n }\n }\n\n if (objectDef.methods) {\n for (const [methodName, methodDef] of Object.entries(objectDef.methods)) {\n existing.methods.set(methodName, methodDef);\n }\n }\n\n if (objectDef.schema) {\n const manifestSchema: SchemaDefinition = {\n ddl: objectDef.schema.ddl || '',\n indexes:\n objectDef.schema.indexes?.map((idx: IndexDefinition) => ({\n name: idx.name,\n columns: idx.columns || [],\n unique: idx.unique || false,\n ...(idx.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: idx.where,\n description: idx.description,\n jsonPath: idx.jsonPath,\n })) || [],\n triggers: [],\n tableName: objectDef.schema.tableName || manifestTableName,\n columns: cloneManifestSchemaColumns(objectDef.schema.columns),\n foreignKeys: [],\n dependencies: [],\n version: objectDef.schema.version || '',\n packageName: packageName,\n };\n\n applySqlTypeOverrides(manifestSchema.columns, existing.fields.entries());\n\n existing.schema = {\n ...(existing.schema || {}),\n ...manifestSchema,\n tableName: manifestSchema.tableName,\n ddl: manifestSchema.ddl || existing.schema?.ddl || '',\n columns: {\n ...(existing.schema?.columns || {}),\n ...(manifestSchema.columns || {}),\n },\n indexes: mergeIndexDefinitions(\n existing.schema?.indexes,\n manifestSchema.indexes,\n ),\n packageName: packageName || existing.schema?.packageName,\n };\n } else if (!existing.schema) {\n existing.schema = {\n ddl: '',\n indexes: [],\n triggers: [],\n tableName: manifestTableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n packageName: packageName,\n };\n } else {\n existing.schema.tableName = manifestTableName;\n existing.schema.packageName = packageName || existing.schema.packageName;\n }\n\n if (objectDef.validationRules !== undefined) {\n existing.validationRules = objectDef.validationRules;\n existing.validators = undefined;\n } else if (!existing.validationRules && !existing.validators) {\n existing.validators = compileValidators(existing.name, existing.fields);\n }\n\n if (packageName) {\n existing.packageName = packageName;\n existing.qualifiedName = createQualifiedName(\n packageName,\n existing.name,\n ) as QualifiedClassName;\n } else if (!existing.packageName && objectDef.packageName) {\n existing.packageName = objectDef.packageName;\n }\n\n if (objectDef.extends) {\n existing.extends = packageName\n ? qualifyExtendsName(objectDef.extends, packageName)\n : objectDef.extends;\n }\n\n if (!existing.sourceFilePath && objectDef.filePath) {\n existing.sourceFilePath = objectDef.filePath;\n }\n\n // The manifest's collection is authoritative (it carries STI inheritance):\n // a class decorated before its manifest loaded registered a derived one,\n // which permission slugs and route segments would otherwise keep (#3125).\n if (objectDef.collection) {\n existing.collection = objectDef.collection;\n }\n\n existing.visibility =\n objectDef.visibility || manifestConfig.visibility || existing.visibility;\n invalidateInheritanceEntries(existing);\n}\n\nexport function registerFromManifest(\n name: string,\n objectDef: SmartObjectDefinition,\n manifestPackageName?: string,\n): void {\n // Same invalidation contract as register() (#3047).\n bumpRegistryGeneration();\n try {\n registerFromManifestUntracked(name, objectDef, manifestPackageName);\n } finally {\n bumpRegistryGeneration();\n }\n}\n\nfunction registerFromManifestUntracked(\n name: string,\n objectDef: SmartObjectDefinition,\n manifestPackageName?: string,\n): void {\n // Issue #2970: `manifestPackageName` identifies the package that owns the\n // manifest FILE this entry was read from, which is not always the package\n // that declares the class. A consumer app's generated `.smrt/manifest.json`\n // is an aggregate: it carries every consumed package's objects verbatim,\n // each keyed by its qualified name and each stating its own `packageName`.\n // Deriving identity from the file's owner re-attributed all of them to the\n // consumer, so a class reached through both that aggregate and its own\n // package's manifest became two registry entries under two packages and its\n // simple name went ambiguous in `findClassStrict()` — reported for\n // `SmrtHierarchical`, but true of any aggregated object.\n //\n // The entry's own declaration therefore wins; the caller's value stays as\n // the fallback for a local manifest whose entries name no package. This is\n // identity-based, so two packages genuinely declaring the same class name\n // still produce two entries and are still reported as ambiguous.\n const packageName = objectDef.packageName || manifestPackageName;\n\n // Issue #951: Compute simple class name and registration key early\n // `name` may be a qualified key from manifest (e.g., '@happyvertical/smrt-events:Event')\n // `simpleClassName` is always the plain class name (e.g., 'Event')\n const simpleClassName = objectDef.className || name;\n const qualifiedNameEarly = packageName\n ? createQualifiedName(packageName, simpleClassName)\n : objectDef.qualifiedName;\n const registrationKey = (qualifiedNameEarly || name) as string;\n\n // Release C (#1134): collision resolution routes through\n // decideCollisionPolicy. See collision-policy.ts for the 16-row decision\n // table; applyManifestCollisionPolicy below turns a policy into registry\n // mutations.\n //\n // Two collision checks, matching pre-C behavior:\n // 1. Canonical-name lookup (case-insensitive simple-name match; covers\n // issue #950's STI child-wins and issue #951's qualified coexistence).\n // 2. Exact-key match (handles re-registration with same qualified key).\n //\n // The ambiguous case (multiple existing entries share the simple name —\n // `getCanonicalClassName` returns undefined) is NOT fed through the table.\n // It falls through both checks into the new-registration code below,\n // preserving issue #951's coexistence semantics.\n const existingCanonical = getCanonicalClassName(simpleClassName);\n if (existingCanonical) {\n const existing = getClasses().get(existingCanonical);\n if (existing) {\n const outcome = applyManifestCollisionPolicy({\n name,\n objectDef,\n packageName,\n existing,\n existingKey: existingCanonical,\n registrationKey,\n matchKind: 'canonical-name',\n });\n if (outcome === 'return') return;\n // outcome === 'continue' means policy was replace (child-wins) or\n // coexist — fall through into the new-registration code below.\n }\n // else: stale map entry (key exists but class was removed) — allow registration\n }\n\n if (getClasses().has(registrationKey)) {\n const existing = getClasses().get(registrationKey);\n if (!existing) return;\n const outcome = applyManifestCollisionPolicy({\n name,\n objectDef,\n packageName,\n existing,\n existingKey: registrationKey,\n registrationKey,\n matchKind: 'exact-key',\n });\n if (outcome === 'return') return;\n }\n\n // Issue #1004: Qualify the `extends` value BEFORE inserting this class\n // into the classes Map. Otherwise qualifyExtendsName would iterate and\n // find the child's own entry, creating a circular extends chain\n // (e.g., @test/sports:TestEvent extends itself). Release B (#1133) swapped\n // the underlying classNameMap lookup for an iteration over `classes`, but\n // the ordering invariant still holds.\n const qualifiedExtends =\n objectDef.extends && packageName\n ? qualifyExtendsName(objectDef.extends, packageName)\n : objectDef.extends;\n\n // Release B (#1133): case-insensitive lookups iterate the classes Map\n // directly; no parallel classNameMap index to maintain.\n\n // Create stub constructor - not needed for CLI command generation\n // The CLI only needs metadata (fields, methods, config)\n // Mark as manifest stub so real class can replace it during decorator registration\n const stubConstructor = class extends SmrtObject {\n static readonly _isManifestStub = true;\n } as typeof SmrtObject;\n Object.defineProperty(stubConstructor, 'name', { value: simpleClassName });\n\n // Convert manifest field definitions to Field objects\n const fields = new Map<string, RegisteredField>();\n const decorators = getLegacyFieldDecorators().get(simpleClassName);\n if (objectDef.fields) {\n for (const [fieldName, fd] of Object.entries(objectDef.fields)) {\n fields.set(fieldName, createFieldFromManifest(fd));\n }\n }\n\n // Load method definitions\n const methods = new Map<string, MethodDefinition>();\n if (objectDef.methods) {\n for (const [methodName, methodDef] of Object.entries(objectDef.methods)) {\n methods.set(methodName, methodDef);\n }\n }\n\n // Get config from manifest\n const config = objectDef.decoratorConfig || {};\n const tableName = config.tableName || tableNameFromClass(stubConstructor);\n // A manifest-only registration (a consumed package's stub) still carries the\n // credential declaration, and is often the ONLY registration a consumer app\n // performs for that class (#2937). `tableName` here is derived from\n // `decoratorConfig`, while the schema installed below uses\n // `objectDef.schema.tableName` — declare both.\n declareSensitiveTable(config, tableName, objectDef.schema?.tableName);\n\n // Load pre-generated schema from manifest if available\n // This enables efficient external package consumption without runtime schema generation\n let schema: SchemaDefinition;\n if (objectDef.schema) {\n // Pre-generated schema from manifest (build-time)\n // Keep indexes as IndexDefinition objects for DDL strategies\n schema = {\n ddl: objectDef.schema.ddl,\n indexes:\n objectDef.schema.indexes?.map((idx: IndexDefinition) => ({\n name: idx.name,\n columns: idx.columns || [],\n unique: idx.unique || false,\n ...(idx.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: idx.where,\n description: idx.description,\n jsonPath: idx.jsonPath,\n })) || [],\n triggers: [],\n tableName: objectDef.schema.tableName,\n columns: cloneManifestSchemaColumns(objectDef.schema.columns),\n foreignKeys: [],\n dependencies: [],\n version: objectDef.schema.version || '',\n packageName: packageName,\n };\n applySqlTypeOverrides(schema.columns, fields.entries());\n applySqlTypeOverrides(schema.columns, decorators?.entries());\n verboseLog(\n `[registry] Loaded pre-generated schema for ${name} (${Object.keys(objectDef.schema.columns || {}).length} columns)`,\n );\n } else {\n // Placeholder schema - will be generated at runtime if needed\n schema = {\n ddl: '',\n indexes: [],\n triggers: [],\n tableName,\n columns: {},\n foreignKeys: [],\n dependencies: [],\n version: '',\n packageName: packageName,\n };\n }\n\n // Use pre-computed validation rules from manifest if available (Issue #782)\n // This avoids compiling validator closures at runtime, reducing startup time\n const validationRules = objectDef.validationRules;\n let validators: ValidatorFunction[] | undefined;\n\n // Only compile validators if no pre-computed rules exist\n // (backward compatibility for older manifests)\n if (validationRules === undefined) {\n validators = compileValidators(name, fields);\n verboseLog(\n `[registry] No pre-computed rules for ${name}, compiled ${validators.length} validators`,\n );\n } else {\n verboseLog(\n `[registry] Using ${validationRules.length} pre-computed validation rules for ${name}`,\n );\n }\n\n // Issue #951: Use qualifiedNameEarly computed at the top of this function\n // (uses simpleClassName, not the manifest key which may already be qualified)\n const qualifiedName = qualifiedNameEarly;\n\n // Get visibility from manifest (defaults to 'public')\n const visibility: SmrtVisibility =\n objectDef.visibility || config.visibility || 'public';\n\n // Register in ObjectRegistry (metadata only, no collection constructor)\n // Manifest registration is for command discovery and help text.\n // Runtime execution requires real classes loaded from entry point.\n //\n // Issue #847: Use className from objectDef (simple name like 'Council') for the name\n // property, not the qualified name key. This enables getFields() lookups by simple\n // class name to work correctly. simpleClassName is defined earlier in this function.\n //\n // A manifest-loaded class carries `tenantScoped` only in its decorator\n // config; normalize it the way registerClass() does so the schema owner's\n // tenant column resolves for `getConflictColumns()` / `getTenantColumn()`\n // on this registration too (#2360). The manifest pipeline already\n // materialized the tenant field (`injectTenantScopedFields`), so the field\n // map is left as the manifest describes it.\n const tenantScopedConfig = normalizeTenantScopedConfig(config.tenantScoped);\n\n // Issue #951: Use registrationKey (qualified when available) as the primary key\n const registration: RegisteredClass = {\n name: simpleClassName,\n qualifiedName, // Qualified name for cross-package identification\n constructor: stubConstructor,\n config,\n fields,\n methods,\n schema,\n tenantScopedConfig,\n validators,\n validationRules, // Pre-computed rules from manifest (Issue #782)\n tools: objectDef.tools, // AI-callable tool schemas (used for CLI param schemas)\n // Pluralized endpoint name; fall back to simple pluralization if a\n // (legacy) manifest lacks it. (smrt#1311.)\n collection: objectDef.collection ?? pluralizeCollection(simpleClassName),\n packageName,\n sourceFilePath: objectDef.filePath, // Store source file for collision detection (Issue #555)\n extends: qualifiedExtends, // Issue #1004: Pre-computed qualified parent\n extendsTypeArg: objectDef.extendsTypeArg, // SmrtCollection<T> generic arg\n visibility, // New: Visibility control for manifest filtering\n };\n // #3338: a deprecated alias must never name a second live class.\n assertQualifiedNameAliasesAvailable(registrationKey, registration);\n getClasses().set(registrationKey, registration);\n // Tag the synthetic stub constructor with the qualified name so the\n // same constructor-side identity convention holds for manifest-loaded\n // classes as well as decorator-registered ones.\n setSmrtQualifiedName(stubConstructor, qualifiedName);\n\n verboseLog(\n `📦 Registered ${simpleClassName} from manifest (key: ${registrationKey}, ${fields.size} fields, ${methods.size} methods)`,\n );\n\n // STI sibling auto-loading (Issue #430)\n // When a class is registered that shares a table with other classes (STI),\n // we need to discover and register ALL siblings so that getAllSchemas()\n // can merge columns from all subtypes for the database adapter.\n //\n // IMPORTANT: Only auto-load siblings from EXTERNAL packages.\n // For test classes or classes in the same package, they will be registered\n // by their own @smrt() decorators. Auto-loading them as stubs would cause collisions.\n const collection = objectDef.collection;\n if (collection && !getStiSiblingsLoaded().has(collection)) {\n // Mark this collection as processed to prevent infinite recursion\n getStiSiblingsLoaded().add(collection);\n\n verboseLog(\n `[registry] Checking for STI siblings for collection: ${collection}`,\n );\n\n // Discover all classes that share this collection (table)\n const siblings = discoverSTISiblingsSync(collection);\n\n // Register any siblings that aren't already registered\n // Only load siblings from DIFFERENT packages to avoid collisions with local classes\n for (const sibling of siblings) {\n // Use case-insensitive check to prevent registering 'Praeco' when 'praeco' exists\n if (!hasClassCaseInsensitive(sibling.className)) {\n // Skip siblings from the same package - they will be registered by their own decorators\n if (\n sibling.packageName &&\n packageName &&\n sibling.packageName === packageName\n ) {\n verboseLog(\n `[registry] Skipping STI sibling ${sibling.className} from same package: ${packageName}`,\n );\n continue;\n }\n\n verboseLog(\n `[registry] Auto-loading STI sibling: ${sibling.className} for collection: ${collection}`,\n );\n registerFromManifest(\n sibling.className,\n sibling.entry,\n sibling.packageName,\n );\n }\n }\n }\n}\n"],"mappings":"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"}