@happyvertical/smrt-core 0.52.0 → 0.53.0

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":"polymorphic-association.js","names":[],"sources":["../src/polymorphic-association.ts"],"sourcesContent":["/**\n * SmrtPolymorphicAssociation — base class for polymorphic association rows.\n *\n * A polymorphic association links an owner row to an arbitrary target\n * SmrtObject identified by a `(metaType, metaId)` pair — `metaType` being the\n * target's qualified class name (e.g. `@happyvertical/smrt-content:Article`)\n * and `metaId` its row id. Pair that with a `role` discriminator and a\n * `sortOrder`, and one join table can reference many different target types\n * without a typed foreign key per type.\n *\n * Subclasses add their own \"owner\" side and decorate with `@smrt()`:\n *\n * ```typescript\n * @smrt({ conflictColumns: ['asset_id', 'meta_type', 'meta_id', 'role'] })\n * export class AssetAssociation extends SmrtPolymorphicAssociation {\n * @foreignKey('Asset', { required: true })\n * assetId = '';\n * }\n *\n * const target = await association.hydrate(); // resolves metaType + loads metaId\n * ```\n *\n * Convention: `metaId` is intentionally a bare string, NOT a typed\n * `@foreignKey` / `@crossPackageRef` — it is polymorphic, so there is no\n * single target table to point at. `metaType` carries the type information\n * instead, resolved at runtime via `ObjectRegistry`.\n *\n * This is an abstract framework base in the same family as\n * `SmrtHierarchical` and `SmrtJunction`: it has no `@smrt()` decorator and no\n * table of its own. Its columns are merged into each concrete subclass's\n * manifest by the scanner's `FRAMEWORK_BASE_CLASSES` /\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` wiring. Keep those two lists in sync when\n * touching this class.\n *\n * @example\n * ```typescript\n * @smrt({ conflictColumns: ['owner_id', 'meta_type', 'meta_id', 'role'] })\n * export class CommentAssociation extends SmrtPolymorphicAssociation {\n * @foreignKey('Comment', { required: true })\n * ownerId = '';\n * }\n * ```\n */\n\nimport { field } from './decorators/index';\nimport { SmrtObject, type SmrtObjectOptions } from './object';\nimport { ObjectRegistry } from './registry';\n\n/**\n * Options accepted by `SmrtPolymorphicAssociation` (and its subclasses)\n * covering the polymorphic right side of the join.\n */\nexport interface SmrtPolymorphicAssociationOptions extends SmrtObjectOptions {\n /** Target class name or qualified name (e.g. `'Article'` or `'@pkg:Article'`). */\n metaType?: string;\n /** Target object id. */\n metaId?: string;\n /** Association role (e.g. `'hero'`, `'thumbnail'`, `'attachment'`). */\n role?: string;\n /** Sort order within a role. */\n sortOrder?: number;\n}\n\nexport class SmrtPolymorphicAssociation extends SmrtObject {\n /**\n * Internal marker so the scanner can recognize this framework abstract base\n * even when consumers haven't built its package. Mirrors\n * `SmrtHierarchical._isHierarchicalBase` and `SmrtJunction._isJunctionBase`.\n * Don't rename without also updating the scanner's `FRAMEWORK_BASE_CLASSES`\n * set in `packages/scanner/src/inheritance-resolver.ts` and\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` in\n * `packages/core/src/scanner/manifest-generator.ts`.\n */\n static readonly _isPolymorphicAssociationBase = true as const;\n\n /** Target class name or qualified name (e.g. `'Article'` or `'@pkg:Article'`). */\n @field({ required: true })\n metaType = '';\n\n /**\n * Target object id. Bare string by design — polymorphic, not a typed\n * `@foreignKey` / `@crossPackageRef`, because there is no single target\n * table to point at.\n */\n @field({ required: true })\n metaId = '';\n\n /** Role of this association (e.g. `'hero'`, `'thumbnail'`, `'attachment'`). */\n @field({ required: true })\n role = 'default';\n\n /** Sort order for ordering targets within a role. */\n @field()\n sortOrder: number = 0;\n\n constructor(options: SmrtPolymorphicAssociationOptions = {}) {\n super(options);\n if (options.metaType) this.metaType = options.metaType;\n if (options.metaId) this.metaId = options.metaId;\n if (options.role) this.role = options.role;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n }\n\n /**\n * Resolve and load the target object this association points at.\n *\n * Resolves `metaType` to its registered class via\n * `ObjectRegistry.getClassByQualifiedName` (falling back to a simple-name\n * lookup for legacy/unqualified values), then loads the `metaId` row through\n * the target's collection. Going through the collection means STI targets\n * are rehydrated as their concrete subclass and a missing row yields `null`.\n *\n * When the type isn't registered yet, a lazy external-package load is\n * attempted so a qualified `metaType` still hydrates even if nothing has\n * imported the target class. Once resolved, the load goes through the\n * target's collection by its qualified name — genuine failures (DB/init\n * errors) surface rather than being masked as \"no target\".\n *\n * Returns `null` when `metaType`/`metaId` are unset, the type can't be\n * resolved to a registered/loadable class, or the target row no longer\n * exists. The target shares this association's database connection via\n * `this.options`.\n *\n * Prefer qualified `metaType` values (`@pkg:Class`): a bare simple name\n * resolves to the first registered match, and an ambiguous unqualified name\n * that has to be lazily loaded surfaces a `ConfigurationError` rather than\n * guessing.\n *\n * @typeParam T - Expected target type for the caller's convenience cast.\n */\n async hydrate<T extends SmrtObject = SmrtObject>(): Promise<T | null> {\n if (!this.metaType || !this.metaId) return null;\n\n // Prefer the qualified-name lookup; fall back to a simple-name lookup for\n // legacy/unqualified values.\n let registered =\n ObjectRegistry.getClassByQualifiedName(this.metaType) ??\n ObjectRegistry.getClass(this.metaType);\n\n // Not registered yet — try a lazy external-package load, then re-resolve.\n // Branch on the boolean: a `false` result means the type genuinely isn't\n // installed (→ null), while real loader failures (e.g. an ambiguous\n // unqualified name throwing ConfigurationError) propagate instead of being\n // masked as \"no target\".\n if (!registered) {\n const loaded = await ObjectRegistry.tryLoadFromExternalPackage(\n this.metaType,\n );\n if (!loaded) return null;\n registered =\n ObjectRegistry.getClassByQualifiedName(this.metaType) ??\n ObjectRegistry.getClass(this.metaType);\n }\n\n if (!registered) return null;\n\n // Resolve via the canonical (qualified) name so the lookup is\n // unambiguous. getCollection is deliberately NOT wrapped in a catch:\n // real DB/init failures must surface, not be reported as a missing row.\n const collection = await ObjectRegistry.getCollection<SmrtObject>(\n registered.qualifiedName ?? registered.name,\n this.options,\n );\n\n const target = await collection.get({ id: this.metaId });\n return target as T | null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,IAAa,6BAAb,cAAgD,WAAW;;;;;;;;;;CAUzD,OAAgB,gCAAgC;;CAGhD,WACW;;;;;;CAOX,SACS;;CAGT,OACO;;CAGP,YACoB;CAEpB,YAAY,UAA6C,CAAC,GAAG;EAC3D,MAAM,OAAO;EACb,IAAI,QAAQ,UAAU,KAAK,WAAW,QAAQ;EAC9C,IAAI,QAAQ,QAAQ,KAAK,SAAS,QAAQ;EAC1C,IAAI,QAAQ,MAAM,KAAK,OAAO,QAAQ;EACtC,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;CAChE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BA,MAAM,UAAgE;EACpE,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,QAAQ,OAAO;EAI3C,IAAI,aACF,eAAe,wBAAwB,KAAK,QAAQ,KACpD,eAAe,SAAS,KAAK,QAAQ;EAOvC,IAAI,CAAC,YAAY;GAIf,IAAI,CAAC,MAHgB,eAAe,2BAClC,KAAK,QACP,GACa,OAAO;GACpB,aACE,eAAe,wBAAwB,KAAK,QAAQ,KACpD,eAAe,SAAS,KAAK,QAAQ;EACzC;EAEA,IAAI,CAAC,YAAY,OAAO;EAWxB,OAAO,OADc,MALI,eAAe,cACtC,WAAW,iBAAiB,WAAW,MACvC,KAAK,OACP,EAAA,CAEgC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CAEzD;AACF;WA3FG,MAAM,EAAE,UAAU,KAAK,CAAC,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,YAAA,KAAA,CAAA;WAQxB,MAAM,EAAE,UAAU,KAAK,CAAC,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,UAAA,KAAA,CAAA;WAIxB,MAAM,EAAE,UAAU,KAAK,CAAC,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,QAAA,KAAA,CAAA;WAIxB,MAAM,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,aAAA,KAAA,CAAA"}
1
+ {"version":3,"file":"polymorphic-association.js","names":[],"sources":["../src/polymorphic-association.ts"],"sourcesContent":["/**\n * SmrtPolymorphicAssociation — base class for polymorphic association rows.\n *\n * A polymorphic association links an owner row to an arbitrary target\n * SmrtObject identified by a `(metaType, metaId)` pair — `metaType` being the\n * target's qualified class name (e.g. `@happyvertical/smrt-content:Article`)\n * and `metaId` its row id. Pair that with a `role` discriminator and a\n * `sortOrder`, and one join table can reference many different target types\n * without a typed foreign key per type.\n *\n * Subclasses add their own \"owner\" side and decorate with `@smrt()`:\n *\n * ```typescript\n * @smrt({ conflictColumns: ['asset_id', 'meta_type', 'meta_id', 'role'] })\n * export class AssetAssociation extends SmrtPolymorphicAssociation {\n * @foreignKey('Asset', { required: true })\n * assetId = '';\n * }\n *\n * const target = await association.hydrate(); // resolves metaType + loads metaId\n * ```\n *\n * Convention: `metaId` is intentionally a bare string, NOT a typed\n * `@foreignKey` / `@crossPackageRef` — it is polymorphic, so there is no\n * single target table to point at. `metaType` carries the type information\n * instead, resolved at runtime via `ObjectRegistry`.\n *\n * This is an abstract framework base in the same family as\n * `SmrtHierarchical` and `SmrtJunction`: it has no `@smrt()` decorator and no\n * table of its own. Its columns are merged into each concrete subclass's\n * manifest by the scanner's `FRAMEWORK_BASE_CLASSES` /\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` wiring. Keep those two lists in sync when\n * touching this class.\n *\n * @example\n * ```typescript\n * @smrt({ conflictColumns: ['owner_id', 'meta_type', 'meta_id', 'role'] })\n * export class CommentAssociation extends SmrtPolymorphicAssociation {\n * @foreignKey('Comment', { required: true })\n * ownerId = '';\n * }\n * ```\n */\n\nimport { field } from './decorators/index';\nimport { SmrtObject, type SmrtObjectOptions } from './object';\nimport { ObjectRegistry } from './registry';\n\n/**\n * Options accepted by `SmrtPolymorphicAssociation` (and its subclasses)\n * covering the polymorphic right side of the join.\n */\nexport interface SmrtPolymorphicAssociationOptions extends SmrtObjectOptions {\n /** Target class name or qualified name (e.g. `'Article'` or `'@pkg:Article'`). */\n metaType?: string;\n /** Target object id. */\n metaId?: string;\n /** Association role (e.g. `'hero'`, `'thumbnail'`, `'attachment'`). */\n role?: string;\n /** Sort order within a role. */\n sortOrder?: number;\n}\n\nexport class SmrtPolymorphicAssociation extends SmrtObject {\n /**\n * Internal marker so the scanner can recognize this framework abstract base\n * even when consumers haven't built its package. Mirrors\n * `SmrtHierarchical._isHierarchicalBase` and `SmrtJunction._isJunctionBase`.\n * Don't rename without also updating the scanner's `FRAMEWORK_BASE_CLASSES`\n * set in `packages/scanner/src/inheritance-resolver.ts` and\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` in\n * `packages/core/src/scanner/manifest-generator.ts`.\n */\n static readonly _isPolymorphicAssociationBase = true as const;\n\n /** Target class name or qualified name (e.g. `'Article'` or `'@pkg:Article'`). */\n @field({ required: true })\n metaType = '';\n\n /**\n * Target object id. Bare string by design — polymorphic, not a typed\n * `@foreignKey` / `@crossPackageRef`, because there is no single target\n * table to point at.\n */\n @field({ required: true })\n metaId = '';\n\n /** Role of this association (e.g. `'hero'`, `'thumbnail'`, `'attachment'`). */\n @field({ required: true })\n role = 'default';\n\n /** Sort order for ordering targets within a role. */\n @field()\n sortOrder: number = 0;\n\n constructor(options: SmrtPolymorphicAssociationOptions = {}) {\n super(options);\n if (options.metaType) this.metaType = options.metaType;\n if (options.metaId) this.metaId = options.metaId;\n if (options.role) this.role = options.role;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n }\n\n /**\n * Store `metaType` under its target's CURRENT qualified name before every\n * save (#3338). A deprecated name declared in the target's\n * `previousQualifiedNames` is rewritten first, so new rows — and any legacy\n * row that is loaded and saved again — never perpetuate it. A target known\n * only from an installed manifest is lazily loaded first; names that\n * resolve to no class at all are stored as given.\n *\n * This runs in the first save-preparation hook rather than a `save()`\n * override: a public override would be scanned into every subclass's\n * manifest as a `save` method.\n */\n protected override async validateBeforeSave(): Promise<void> {\n if (this.metaType) {\n // Async: a target known only from its (new owner's) manifest is\n // lazily loaded first, so an old name never slips through unresolved.\n const current = await ObjectRegistry.resolveQualifiedNameAsync(\n this.metaType,\n { source: 'SmrtPolymorphicAssociation.save' },\n );\n if (current && current !== this.metaType) this.metaType = current;\n }\n await super.validateBeforeSave();\n }\n\n /**\n * Resolve and load the target object this association points at.\n *\n * Resolves `metaType` to its registered class via\n * `ObjectRegistry.getClassByQualifiedName` (falling back to a simple-name\n * lookup for legacy/unqualified values), then loads the `metaId` row through\n * the target's collection. Going through the collection means STI targets\n * are rehydrated as their concrete subclass and a missing row yields `null`.\n *\n * When the type isn't registered yet, a lazy external-package load is\n * attempted so a qualified `metaType` still hydrates even if nothing has\n * imported the target class. Once resolved, the load goes through the\n * target's collection by its qualified name — genuine failures (DB/init\n * errors) surface rather than being masked as \"no target\".\n *\n * Returns `null` when `metaType`/`metaId` are unset, the type can't be\n * resolved to a registered/loadable class, or the target row no longer\n * exists. The target shares this association's database connection via\n * `this.options`.\n *\n * A `metaType` written under a class's former qualified name (declared in\n * its `previousQualifiedNames`, e.g. after the class moved package)\n * resolves to the class, eagerly or through the lazy manifest alias index,\n * with a one-time deprecation warning (#3338).\n *\n * Prefer qualified `metaType` values (`@pkg:Class`): a bare simple name\n * resolves to the first registered match, and an ambiguous unqualified name\n * that has to be lazily loaded surfaces a `ConfigurationError` rather than\n * guessing.\n *\n * @typeParam T - Expected target type for the caller's convenience cast.\n */\n async hydrate<T extends SmrtObject = SmrtObject>(): Promise<T | null> {\n if (!this.metaType || !this.metaId) return null;\n\n // Prefer the qualified-name lookup; fall back to a simple-name lookup for\n // legacy/unqualified values.\n const lookup = { source: 'SmrtPolymorphicAssociation.hydrate' };\n let registered =\n ObjectRegistry.getClassByQualifiedName(this.metaType, lookup) ??\n ObjectRegistry.getClass(this.metaType);\n\n // Not registered yet — try a lazy external-package load, then re-resolve.\n // Branch on the boolean: a `false` result means the type genuinely isn't\n // installed (→ null), while real loader failures (e.g. an ambiguous\n // unqualified name throwing ConfigurationError) propagate instead of being\n // masked as \"no target\".\n if (!registered) {\n const loaded = await ObjectRegistry.tryLoadFromExternalPackage(\n this.metaType,\n );\n if (!loaded) return null;\n registered =\n ObjectRegistry.getClassByQualifiedName(this.metaType, lookup) ??\n ObjectRegistry.getClass(this.metaType);\n }\n\n if (!registered) return null;\n\n // Resolve via the canonical (qualified) name so the lookup is\n // unambiguous. getCollection is deliberately NOT wrapped in a catch:\n // real DB/init failures must surface, not be reported as a missing row.\n const collection = await ObjectRegistry.getCollection<SmrtObject>(\n registered.qualifiedName ?? registered.name,\n this.options,\n );\n\n const target = await collection.get({ id: this.metaId });\n return target as T | null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,IAAa,6BAAb,cAAgD,WAAW;;;;;;;;;;CAUzD,OAAgB,gCAAgC;;CAGhD,WACW;;;;;;CAOX,SACS;;CAGT,OACO;;CAGP,YACoB;CAEpB,YAAY,UAA6C,CAAC,GAAG;EAC3D,MAAM,OAAO;EACb,IAAI,QAAQ,UAAU,KAAK,WAAW,QAAQ;EAC9C,IAAI,QAAQ,QAAQ,KAAK,SAAS,QAAQ;EAC1C,IAAI,QAAQ,MAAM,KAAK,OAAO,QAAQ;EACtC,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;CAChE;;;;;;;;;;;;;CAcA,MAAyB,qBAAoC;EAC3D,IAAI,KAAK,UAAU;GAGjB,MAAM,UAAU,MAAM,eAAe,0BACnC,KAAK,UACL,EAAE,QAAQ,kCAAkC,CAC9C;GACA,IAAI,WAAW,YAAY,KAAK,UAAU,KAAK,WAAW;EAC5D;EACA,MAAM,MAAM,mBAAmB;CACjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCA,MAAM,UAAgE;EACpE,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,QAAQ,OAAO;EAI3C,MAAM,SAAS,EAAE,QAAQ,qCAAqC;EAC9D,IAAI,aACF,eAAe,wBAAwB,KAAK,UAAU,MAAM,KAC5D,eAAe,SAAS,KAAK,QAAQ;EAOvC,IAAI,CAAC,YAAY;GAIf,IAAI,CAAC,MAHgB,eAAe,2BAClC,KAAK,QACP,GACa,OAAO;GACpB,aACE,eAAe,wBAAwB,KAAK,UAAU,MAAM,KAC5D,eAAe,SAAS,KAAK,QAAQ;EACzC;EAEA,IAAI,CAAC,YAAY,OAAO;EAWxB,OAAO,OADc,MALI,eAAe,cACtC,WAAW,iBAAiB,WAAW,MACvC,KAAK,OACP,EAAA,CAEgC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CAEzD;AACF;WA1HG,MAAM,EAAE,UAAU,KAAK,CAAC,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,YAAA,KAAA,CAAA;WAQxB,MAAM,EAAE,UAAU,KAAK,CAAC,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,UAAA,KAAA,CAAA;WAIxB,MAAM,EAAE,UAAU,KAAK,CAAC,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,QAAA,KAAA,CAAA;WAIxB,MAAM,GAAA,kBAAA,eAAA,MAAA,CAAA,GAAA,2BAAA,WAAA,aAAA,KAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"class-registration.d.ts","sourceRoot":"","sources":["../../src/registry/class-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuBH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAKV,qBAAqB,EAGtB,MAAM,qBAAqB,CAAC;AA2C7B,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAkDpB;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAS3E;AA4BD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAeT;AA+mBD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,UAAU,EACvB,MAAM,GAAE,iBAAsB,GAC7B,IAAI,CAON;AA8gCD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAMlB,qBAAqB,EAAE,WAAW,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,GAC3E,IAAI,CAeN;AA+BD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACpC,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAC,GAAG,SAAS,GACpE,IAAI,CAyCN;AAoHD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,eAAe,EACzB,gBAAgB,CAAC,EAAE;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,IAAI,CA4CN;AAkLD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,mBAAmB,CAAC,EAAE,MAAM,GAC3B,IAAI,CAQN"}
1
+ {"version":3,"file":"class-registration.d.ts","sourceRoot":"","sources":["../../src/registry/class-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuBH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAKV,qBAAqB,EAGtB,MAAM,qBAAqB,CAAC;AA4C7B,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAkDpB;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAS3E;AA4BD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAeT;AA4nBD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,UAAU,EACvB,MAAM,GAAE,iBAAsB,GAC7B,IAAI,CAON;AAmiCD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAMlB,qBAAqB,EAAE,WAAW,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,GAC3E,IAAI,CAeN;AA+BD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACpC,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAC,GAAG,SAAS,GACpE,IAAI,CAyCN;AAoHD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,eAAe,EACzB,gBAAgB,CAAC,EAAE;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,IAAI,CA4CN;AAkLD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,mBAAmB,CAAC,EAAE,MAAM,GAC3B,IAAI,CAQN"}
@@ -6,6 +6,7 @@ import { createQualifiedName, isQualifiedName, parseQualifiedName } from "../uti
6
6
  import { getClasses, getCollections, getConstructorFieldDecorators, getConstructorIndex, getConstructorTenantScopedDeclarations, getInheritanceCache, getLegacyFieldDecorators, getSourceFileFromStack, getStiSiblingsLoaded, verboseLog } from "./shared-state.js";
7
7
  import { cloneManifestSchemaColumns, findWorkspaceRootSync, getLocalTestManifestCache, getManifestCache, getNodeBuiltins, getStaticManifestCache, getTestManifestCache } from "../manifest/store.js";
8
8
  import { discoverManifestSync, discoverSTISiblingsSync, getPackageName, lookupInManifest, readProjectManifestSync } from "../manifest/manifest-loader.js";
9
+ import { assertQualifiedNameAliasesAvailable } from "./qualified-name-aliases.js";
9
10
  import { findClass, findClassesByName, getCanonicalClassName, hasClassCaseInsensitive, qualifyExtendsName } from "./name-resolver.js";
10
11
  import { buildInheritanceChain } from "./inheritance-resolver.js";
11
12
  import { compileValidators } from "./validator.js";
@@ -293,6 +294,13 @@ function applyManifestCollisionPolicy(args) {
293
294
  verboseLog(`[registry] ${decision.scenario}: '${args.name}' replaces '${args.existingKey}' (${decision.reason})`);
294
295
  return "continue";
295
296
  case "merge-manifest":
297
+ assertQualifiedNameAliasesAvailable(args.registrationKey, {
298
+ ...args.existing,
299
+ config: {
300
+ ...args.objectDef.decoratorConfig || {},
301
+ ...args.existing.config
302
+ }
303
+ }, args.existing);
296
304
  mergeManifestIntoExistingRegistration(args.existing, args.objectDef, args.packageName);
297
305
  if (args.registrationKey !== args.existingKey) {
298
306
  getClasses().set(args.registrationKey, args.existing);
@@ -438,6 +446,17 @@ function registerUntracked(ctor, config = {}) {
438
446
  name: existing.name,
439
447
  qualifiedName: existing.qualifiedName
440
448
  };
449
+ assertQualifiedNameAliasesAvailable(nextKey, {
450
+ ...existing,
451
+ name,
452
+ packageName: nextPackageName,
453
+ qualifiedName: nextPackageName ? createQualifiedName(nextPackageName, name) : void 0,
454
+ constructor: ctor,
455
+ config: {
456
+ ...existing.config,
457
+ ...config
458
+ }
459
+ }, existing);
441
460
  existing.name = name;
442
461
  existing.packageName = nextPackageName;
443
462
  bumpRegistryGeneration();
@@ -760,7 +779,7 @@ function registerUntracked(ctor, config = {}) {
760
779
  const qualifiedName = packageName ? createQualifiedName(packageName, name) : void 0;
761
780
  const visibility = config.visibility || manifestEntry?.visibility || "public";
762
781
  const registrationKey = qualifiedName || name;
763
- getClasses().set(registrationKey, {
782
+ const registration = {
764
783
  name,
765
784
  qualifiedName,
766
785
  constructor: ctor,
@@ -780,7 +799,9 @@ function registerUntracked(ctor, config = {}) {
780
799
  tenantScopedConfig,
781
800
  tenantScopedConfigSource,
782
801
  visibility
783
- });
802
+ };
803
+ assertQualifiedNameAliasesAvailable(registrationKey, registration);
804
+ getClasses().set(registrationKey, registration);
784
805
  getConstructorIndex().set(ctor, registrationKey);
785
806
  setSmrtQualifiedName(ctor, qualifiedName);
786
807
  verboseLog(`🎯 Registered smrt object: ${name} (key: ${registrationKey}) with schema for ${schema.tableName} and ${(validators?.length || 0) + (validationRules?.length || 0)} validators/rules`);
@@ -1140,7 +1161,7 @@ function registerFromManifestUntracked(name, objectDef, manifestPackageName) {
1140
1161
  const qualifiedName = qualifiedNameEarly;
1141
1162
  const visibility = objectDef.visibility || config.visibility || "public";
1142
1163
  const tenantScopedConfig = normalizeTenantScopedConfig(config.tenantScoped);
1143
- getClasses().set(registrationKey, {
1164
+ const registration = {
1144
1165
  name: simpleClassName,
1145
1166
  qualifiedName,
1146
1167
  constructor: stubConstructor,
@@ -1158,7 +1179,9 @@ function registerFromManifestUntracked(name, objectDef, manifestPackageName) {
1158
1179
  extends: qualifiedExtends,
1159
1180
  extendsTypeArg: objectDef.extendsTypeArg,
1160
1181
  visibility
1161
- });
1182
+ };
1183
+ assertQualifiedNameAliasesAvailable(registrationKey, registration);
1184
+ getClasses().set(registrationKey, registration);
1162
1185
  setSmrtQualifiedName(stubConstructor, qualifiedName);
1163
1186
  verboseLog(`📦 Registered ${simpleClassName} from manifest (key: ${registrationKey}, ${fields.size} fields, ${methods.size} methods)`);
1164
1187
  const collection = objectDef.collection;