@happyvertical/smrt-core 0.51.39 → 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 (122) hide show
  1. package/AGENTS.md +9 -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/agents/schema-paths.md +79 -0
  7. package/dist/cascade.d.ts.map +1 -1
  8. package/dist/cascade.js +6 -3
  9. package/dist/cascade.js.map +1 -1
  10. package/dist/collection.d.ts +10 -1
  11. package/dist/collection.d.ts.map +1 -1
  12. package/dist/collection.js +14 -4
  13. package/dist/collection.js.map +1 -1
  14. package/dist/errors.d.ts +18 -0
  15. package/dist/errors.d.ts.map +1 -1
  16. package/dist/errors.js +21 -0
  17. package/dist/errors.js.map +1 -1
  18. package/dist/generators/preflight-route.d.ts.map +1 -1
  19. package/dist/generators/preflight-route.js +1 -1
  20. package/dist/generators/preflight-route.js.map +1 -1
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -1
  24. package/dist/knowledge.d.ts.map +1 -1
  25. package/dist/knowledge.js +3 -0
  26. package/dist/knowledge.js.map +1 -1
  27. package/dist/manifest/static-manifest.d.ts.map +1 -1
  28. package/dist/manifest/static-manifest.js +9 -1
  29. package/dist/manifest/static-manifest.js.map +1 -1
  30. package/dist/manifest/store.js +1 -1
  31. package/dist/manifest/store.js.map +1 -1
  32. package/dist/manifest.json +9 -1
  33. package/dist/migrations/differ.d.ts +56 -0
  34. package/dist/migrations/differ.d.ts.map +1 -1
  35. package/dist/migrations/differ.js +152 -27
  36. package/dist/migrations/differ.js.map +1 -1
  37. package/dist/migrations/index.d.ts +1 -0
  38. package/dist/migrations/index.d.ts.map +1 -1
  39. package/dist/migrations/index.js +2 -1
  40. package/dist/migrations/null-equal-indexes.js +1 -1
  41. package/dist/migrations/orchestrate.d.ts +7 -0
  42. package/dist/migrations/orchestrate.d.ts.map +1 -1
  43. package/dist/migrations/orchestrate.js +4 -2
  44. package/dist/migrations/orchestrate.js.map +1 -1
  45. package/dist/migrations/qualified-name-aliases.d.ts +134 -0
  46. package/dist/migrations/qualified-name-aliases.d.ts.map +1 -0
  47. package/dist/migrations/qualified-name-aliases.js +294 -0
  48. package/dist/migrations/qualified-name-aliases.js.map +1 -0
  49. package/dist/migrations/tracker.d.ts +29 -1
  50. package/dist/migrations/tracker.d.ts.map +1 -1
  51. package/dist/migrations/tracker.js +92 -7
  52. package/dist/migrations/tracker.js.map +1 -1
  53. package/dist/migrations.js +2 -1
  54. package/dist/object.d.ts +128 -0
  55. package/dist/object.d.ts.map +1 -1
  56. package/dist/object.js +333 -44
  57. package/dist/object.js.map +1 -1
  58. package/dist/polymorphic-association.d.ts +18 -0
  59. package/dist/polymorphic-association.d.ts.map +1 -1
  60. package/dist/polymorphic-association.js +27 -2
  61. package/dist/polymorphic-association.js.map +1 -1
  62. package/dist/registry/class-registration.d.ts.map +1 -1
  63. package/dist/registry/class-registration.js +27 -4
  64. package/dist/registry/class-registration.js.map +1 -1
  65. package/dist/registry/name-resolver.d.ts +8 -2
  66. package/dist/registry/name-resolver.d.ts.map +1 -1
  67. package/dist/registry/name-resolver.js +17 -8
  68. package/dist/registry/name-resolver.js.map +1 -1
  69. package/dist/registry/qualified-name-aliases.d.ts +109 -0
  70. package/dist/registry/qualified-name-aliases.d.ts.map +1 -0
  71. package/dist/registry/qualified-name-aliases.js +286 -0
  72. package/dist/registry/qualified-name-aliases.js.map +1 -0
  73. package/dist/registry/relationship-graph.d.ts.map +1 -1
  74. package/dist/registry/relationship-graph.js +1 -1
  75. package/dist/registry/relationship-graph.js.map +1 -1
  76. package/dist/registry/schema-builder.d.ts.map +1 -1
  77. package/dist/registry/schema-builder.js +7 -5
  78. package/dist/registry/schema-builder.js.map +1 -1
  79. package/dist/registry/types.d.ts +26 -0
  80. package/dist/registry/types.d.ts.map +1 -1
  81. package/dist/registry.d.ts +127 -6
  82. package/dist/registry.d.ts.map +1 -1
  83. package/dist/registry.js +234 -14
  84. package/dist/registry.js.map +1 -1
  85. package/dist/scanner/index.d.ts +1 -1
  86. package/dist/scanner/index.d.ts.map +1 -1
  87. package/dist/scanner/manifest-generator.d.ts +14 -2
  88. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  89. package/dist/scanner/manifest-generator.js +48 -9
  90. package/dist/scanner/manifest-generator.js.map +1 -1
  91. package/dist/scanner/types.d.ts +21 -0
  92. package/dist/scanner/types.d.ts.map +1 -1
  93. package/dist/scanner/types.js.map +1 -1
  94. package/dist/schema/conflict-target.d.ts +68 -11
  95. package/dist/schema/conflict-target.d.ts.map +1 -1
  96. package/dist/schema/conflict-target.js +75 -12
  97. package/dist/schema/conflict-target.js.map +1 -1
  98. package/dist/schema/foreign-key-ddl.d.ts +17 -1
  99. package/dist/schema/foreign-key-ddl.d.ts.map +1 -1
  100. package/dist/schema/foreign-key-ddl.js +29 -3
  101. package/dist/schema/foreign-key-ddl.js.map +1 -1
  102. package/dist/schema/foreign-key-policy.d.ts +8 -0
  103. package/dist/schema/foreign-key-policy.d.ts.map +1 -1
  104. package/dist/schema/foreign-key-policy.js +2 -1
  105. package/dist/schema/foreign-key-policy.js.map +1 -1
  106. package/dist/schema/generator.d.ts +7 -0
  107. package/dist/schema/generator.d.ts.map +1 -1
  108. package/dist/schema/generator.js +18 -10
  109. package/dist/schema/generator.js.map +1 -1
  110. package/dist/schema/text-cast-probe.d.ts +50 -1
  111. package/dist/schema/text-cast-probe.d.ts.map +1 -1
  112. package/dist/schema/text-cast-probe.js +46 -11
  113. package/dist/schema/text-cast-probe.js.map +1 -1
  114. package/dist/schema/types.d.ts +6 -0
  115. package/dist/schema/types.d.ts.map +1 -1
  116. package/dist/scripts/browser-plain-json-regression.mjs +4 -1
  117. package/dist/smrt-knowledge.json +22 -11
  118. package/dist/utils/qualified-names.d.ts +11 -0
  119. package/dist/utils/qualified-names.d.ts.map +1 -1
  120. package/dist/utils/qualified-names.js +21 -1
  121. package/dist/utils/qualified-names.js.map +1 -1
  122. package/package.json +11 -11
@@ -143,7 +143,27 @@ function isType(qualifiedName, shortName) {
143
143
  if (!qualifiedName) return false;
144
144
  return getClassName(qualifiedName) === shortName;
145
145
  }
146
+ /**
147
+ * A valid `previousQualifiedNames` entry: exactly what {@link isQualifiedName}
148
+ * accepts (`@scope/package:ClassName` — the predicate eager lookups,
149
+ * `resolveType()` and the lazy manifest loader all use), with an identifier
150
+ * class name and exactly one colon. An unscoped `package:ClassName` is
151
+ * refused: no qualified lookup treats it as qualified, so it could never
152
+ * resolve (#3338).
153
+ */
154
+ function isQualifiedNameAliasFormat(name) {
155
+ if (typeof name !== "string" || !isQualifiedName(name)) return false;
156
+ const colon = name.lastIndexOf(":");
157
+ return name.indexOf(":") === colon && !/\s/u.test(name.slice(0, colon)) && /^[A-Za-z_$][\w$]*$/u.test(name.slice(colon + 1));
158
+ }
159
+ /** The declared aliases of one decorator/manifest config, as strings. */
160
+ function readPreviousQualifiedNames(config) {
161
+ if (!config || typeof config !== "object") return [];
162
+ const declared = config.previousQualifiedNames;
163
+ if (!Array.isArray(declared)) return [];
164
+ return declared.filter((name) => typeof name === "string");
165
+ }
146
166
  //#endregion
147
- export { createQualifiedName, getClassName, getPackageFromQualifiedName, isFromPackage, isQualifiedName, isType, parseQualifiedName, qualifiedNamesEqual };
167
+ export { createQualifiedName, getClassName, getPackageFromQualifiedName, isFromPackage, isQualifiedName, isQualifiedNameAliasFormat, isType, parseQualifiedName, qualifiedNamesEqual, readPreviousQualifiedNames };
148
168
 
149
169
  //# sourceMappingURL=qualified-names.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"qualified-names.js","names":[],"sources":["../../src/utils/qualified-names.ts"],"sourcesContent":["/**\n * Utilities for working with qualified class names in the SMRT framework.\n *\n * Qualified names follow the format: \"@package/name:ClassName\"\n * Example: \"@happyvertical/smrt-core:Product\"\n *\n * This format uniquely identifies classes across packages, eliminating\n * name collisions when multiple packages define classes with the same name.\n */\n\nimport type { QualifiedClassName } from '../scanner/types.js';\n\n/**\n * Creates a qualified class name from package name and class name.\n *\n * @param packageName - The npm package name (e.g., \"@happyvertical/smrt-core\")\n * @param className - The class name (e.g., \"Product\")\n * @returns Qualified name in format \"@package/name:ClassName\"\n *\n * @example\n * createQualifiedName('@happyvertical/smrt-core', 'Product')\n * // Returns: \"@happyvertical/smrt-core:Product\"\n */\nexport function createQualifiedName(\n packageName: string,\n className: string,\n): QualifiedClassName {\n if (!packageName) {\n throw new Error(\n `Cannot create qualified name: packageName is required. ` +\n `Got className=\"${className}\" but no packageName.`,\n );\n }\n if (!className) {\n throw new Error(\n `Cannot create qualified name: className is required. ` +\n `Got packageName=\"${packageName}\" but no className.`,\n );\n }\n return `${packageName}:${className}` as QualifiedClassName;\n}\n\n/**\n * Result of parsing a qualified class name.\n */\nexport interface ParsedQualifiedName {\n /** The package name (e.g., \"@happyvertical/smrt-core\") */\n packageName: string;\n /** The class name (e.g., \"Product\") */\n className: string;\n}\n\n/**\n * Parses a qualified class name into its components.\n *\n * @param qualifiedName - The qualified name to parse\n * @returns Object with packageName and className\n * @throws Error if the name is not a valid qualified name\n *\n * @example\n * parseQualifiedName('@happyvertical/smrt-core:Product')\n * // Returns: { packageName: '@happyvertical/smrt-core', className: 'Product' }\n */\nexport function parseQualifiedName(qualifiedName: string): ParsedQualifiedName {\n if (!isQualifiedName(qualifiedName)) {\n throw new Error(\n `Invalid qualified name: \"${qualifiedName}\". ` +\n `Expected format: \"@package/name:ClassName\"`,\n );\n }\n\n // Use lastIndexOf to handle edge cases like \"@scope/pkg:Nested:Class\"\n // (though class names shouldn't have colons, this is defensive)\n const colonIndex = qualifiedName.lastIndexOf(':');\n\n return {\n packageName: qualifiedName.slice(0, colonIndex),\n className: qualifiedName.slice(colonIndex + 1),\n };\n}\n\n/**\n * Checks if a name is a valid qualified class name.\n *\n * A valid qualified name:\n * - Contains a colon (:) separating package and class\n * - Has a package name with a forward slash (scoped npm package)\n * - Has a non-empty class name after the colon\n *\n * @param name - The name to check\n * @returns true if the name is a valid qualified class name\n *\n * @example\n * isQualifiedName('@happyvertical/smrt-core:Product') // true\n * isQualifiedName('Product') // false\n * isQualifiedName('smrt-core:Product') // false (no @ scope)\n */\nexport function isQualifiedName(name: string): name is QualifiedClassName {\n if (!name || typeof name !== 'string') {\n return false;\n }\n\n const colonIndex = name.lastIndexOf(':');\n if (colonIndex === -1) {\n return false;\n }\n\n const packageName = name.slice(0, colonIndex);\n const className = name.slice(colonIndex + 1);\n\n // Package name must be a scoped npm package (contains @)\n // and have a path (contains /)\n if (!packageName.startsWith('@') || !packageName.includes('/')) {\n return false;\n }\n\n // Class name must be non-empty\n if (!className) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Extracts just the class name from a qualified name or simple name.\n * Useful when you need the class name regardless of whether\n * the input is qualified or not.\n *\n * @param name - Qualified name or simple class name\n * @returns The simple class name\n *\n * @example\n * getClassName('@happyvertical/smrt-core:Product') // 'Product'\n * getClassName('Product') // 'Product'\n */\nexport function getClassName(name: string): string {\n if (isQualifiedName(name)) {\n return parseQualifiedName(name).className;\n }\n return name;\n}\n\n/**\n * Extracts the package name from a qualified name.\n * Returns undefined if the name is not qualified.\n *\n * @param name - Qualified name or simple class name\n * @returns The package name, or undefined if not qualified\n *\n * @example\n * getPackageFromQualifiedName('@happyvertical/smrt-core:Product')\n * // Returns: '@happyvertical/smrt-core'\n *\n * getPackageFromQualifiedName('Product')\n * // Returns: undefined\n */\nexport function getPackageFromQualifiedName(name: string): string | undefined {\n if (isQualifiedName(name)) {\n return parseQualifiedName(name).packageName;\n }\n return undefined;\n}\n\n/**\n * Compares two qualified names for equality.\n * Case-sensitive comparison.\n *\n * @param a - First qualified name\n * @param b - Second qualified name\n * @returns true if the qualified names are equal\n */\nexport function qualifiedNamesEqual(a: string, b: string): boolean {\n return a === b;\n}\n\n/**\n * Checks if a qualified name belongs to a specific package.\n *\n * @param qualifiedName - The qualified name to check\n * @param packageName - The package name to match against\n * @returns true if the qualified name is from the specified package\n *\n * @example\n * isFromPackage('@happyvertical/smrt-core:Product', '@happyvertical/smrt-core')\n * // Returns: true\n */\nexport function isFromPackage(\n qualifiedName: string,\n packageName: string,\n): boolean {\n if (!isQualifiedName(qualifiedName)) {\n return false;\n }\n const parsed = parseQualifiedName(qualifiedName);\n return parsed.packageName === packageName;\n}\n\n/**\n * Checks if a qualified name (like `_meta_type`) matches a short class name.\n * This is useful for STI filtering where the database stores qualified names\n * but code often uses short names for comparisons.\n *\n * @param qualifiedName - The qualified name or simple name to check (e.g., from `_meta_type`)\n * @param shortName - The short class name to match against\n * @returns true if the class name portion matches\n *\n * @example\n * ```typescript\n * // Filtering STI records by type\n * const meetings = events.filter(e => isType(e._meta_type, 'Meeting'));\n *\n * // Works with both qualified and simple names\n * isType('@happyvertical/praeco:MeetingRecap', 'MeetingRecap') // true\n * isType('@happyvertical/praeco:MeetingRecap', 'Article') // false\n * isType('MeetingRecap', 'MeetingRecap') // true (simple name passthrough)\n * ```\n */\nexport function isType(\n qualifiedName: string | null | undefined,\n shortName: string,\n): boolean {\n if (!qualifiedName) {\n return false;\n }\n return getClassName(qualifiedName) === shortName;\n}\n"],"mappings":";;;;;;;;;;;;AAuBA,SAAgB,oBACd,aACA,WACoB;CACpB,IAAI,CAAC,aACH,MAAM,IAAI,MACR,yEACoB,UAAU,sBAChC;CAEF,IAAI,CAAC,WACH,MAAM,IAAI,MACR,yEACsB,YAAY,oBACpC;CAEF,OAAO,GAAG,YAAY,GAAG;AAC3B;;;;;;;;;;;;AAuBA,SAAgB,mBAAmB,eAA4C;CAC7E,IAAI,CAAC,gBAAgB,aAAa,GAChC,MAAM,IAAI,MACR,4BAA4B,cAAc,8CAE5C;CAKF,MAAM,aAAa,cAAc,YAAY,GAAG;CAEhD,OAAO;EACL,aAAa,cAAc,MAAM,GAAG,UAAU;EAC9C,WAAW,cAAc,MAAM,aAAa,CAAC;CAC/C;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAAgB,MAA0C;CACxE,IAAI,CAAC,QAAQ,OAAO,SAAS,UAC3B,OAAO;CAGT,MAAM,aAAa,KAAK,YAAY,GAAG;CACvC,IAAI,eAAe,IACjB,OAAO;CAGT,MAAM,cAAc,KAAK,MAAM,GAAG,UAAU;CAC5C,MAAM,YAAY,KAAK,MAAM,aAAa,CAAC;CAI3C,IAAI,CAAC,YAAY,WAAW,GAAG,KAAK,CAAC,YAAY,SAAS,GAAG,GAC3D,OAAO;CAIT,IAAI,CAAC,WACH,OAAO;CAGT,OAAO;AACT;;;;;;;;;;;;;AAcA,SAAgB,aAAa,MAAsB;CACjD,IAAI,gBAAgB,IAAI,GACtB,OAAO,mBAAmB,IAAI,CAAC,CAAC;CAElC,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,4BAA4B,MAAkC;CAC5E,IAAI,gBAAgB,IAAI,GACtB,OAAO,mBAAmB,IAAI,CAAC,CAAC;AAGpC;;;;;;;;;AAUA,SAAgB,oBAAoB,GAAW,GAAoB;CACjE,OAAO,MAAM;AACf;;;;;;;;;;;;AAaA,SAAgB,cACd,eACA,aACS;CACT,IAAI,CAAC,gBAAgB,aAAa,GAChC,OAAO;CAGT,OADe,mBAAmB,aAC3B,CAAA,CAAO,gBAAgB;AAChC;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,OACd,eACA,WACS;CACT,IAAI,CAAC,eACH,OAAO;CAET,OAAO,aAAa,aAAa,MAAM;AACzC"}
1
+ {"version":3,"file":"qualified-names.js","names":[],"sources":["../../src/utils/qualified-names.ts"],"sourcesContent":["/**\n * Utilities for working with qualified class names in the SMRT framework.\n *\n * Qualified names follow the format: \"@package/name:ClassName\"\n * Example: \"@happyvertical/smrt-core:Product\"\n *\n * This format uniquely identifies classes across packages, eliminating\n * name collisions when multiple packages define classes with the same name.\n */\n\nimport type { QualifiedClassName } from '../scanner/types.js';\n\n/**\n * Creates a qualified class name from package name and class name.\n *\n * @param packageName - The npm package name (e.g., \"@happyvertical/smrt-core\")\n * @param className - The class name (e.g., \"Product\")\n * @returns Qualified name in format \"@package/name:ClassName\"\n *\n * @example\n * createQualifiedName('@happyvertical/smrt-core', 'Product')\n * // Returns: \"@happyvertical/smrt-core:Product\"\n */\nexport function createQualifiedName(\n packageName: string,\n className: string,\n): QualifiedClassName {\n if (!packageName) {\n throw new Error(\n `Cannot create qualified name: packageName is required. ` +\n `Got className=\"${className}\" but no packageName.`,\n );\n }\n if (!className) {\n throw new Error(\n `Cannot create qualified name: className is required. ` +\n `Got packageName=\"${packageName}\" but no className.`,\n );\n }\n return `${packageName}:${className}` as QualifiedClassName;\n}\n\n/**\n * Result of parsing a qualified class name.\n */\nexport interface ParsedQualifiedName {\n /** The package name (e.g., \"@happyvertical/smrt-core\") */\n packageName: string;\n /** The class name (e.g., \"Product\") */\n className: string;\n}\n\n/**\n * Parses a qualified class name into its components.\n *\n * @param qualifiedName - The qualified name to parse\n * @returns Object with packageName and className\n * @throws Error if the name is not a valid qualified name\n *\n * @example\n * parseQualifiedName('@happyvertical/smrt-core:Product')\n * // Returns: { packageName: '@happyvertical/smrt-core', className: 'Product' }\n */\nexport function parseQualifiedName(qualifiedName: string): ParsedQualifiedName {\n if (!isQualifiedName(qualifiedName)) {\n throw new Error(\n `Invalid qualified name: \"${qualifiedName}\". ` +\n `Expected format: \"@package/name:ClassName\"`,\n );\n }\n\n // Use lastIndexOf to handle edge cases like \"@scope/pkg:Nested:Class\"\n // (though class names shouldn't have colons, this is defensive)\n const colonIndex = qualifiedName.lastIndexOf(':');\n\n return {\n packageName: qualifiedName.slice(0, colonIndex),\n className: qualifiedName.slice(colonIndex + 1),\n };\n}\n\n/**\n * Checks if a name is a valid qualified class name.\n *\n * A valid qualified name:\n * - Contains a colon (:) separating package and class\n * - Has a package name with a forward slash (scoped npm package)\n * - Has a non-empty class name after the colon\n *\n * @param name - The name to check\n * @returns true if the name is a valid qualified class name\n *\n * @example\n * isQualifiedName('@happyvertical/smrt-core:Product') // true\n * isQualifiedName('Product') // false\n * isQualifiedName('smrt-core:Product') // false (no @ scope)\n */\nexport function isQualifiedName(name: string): name is QualifiedClassName {\n if (!name || typeof name !== 'string') {\n return false;\n }\n\n const colonIndex = name.lastIndexOf(':');\n if (colonIndex === -1) {\n return false;\n }\n\n const packageName = name.slice(0, colonIndex);\n const className = name.slice(colonIndex + 1);\n\n // Package name must be a scoped npm package (contains @)\n // and have a path (contains /)\n if (!packageName.startsWith('@') || !packageName.includes('/')) {\n return false;\n }\n\n // Class name must be non-empty\n if (!className) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Extracts just the class name from a qualified name or simple name.\n * Useful when you need the class name regardless of whether\n * the input is qualified or not.\n *\n * @param name - Qualified name or simple class name\n * @returns The simple class name\n *\n * @example\n * getClassName('@happyvertical/smrt-core:Product') // 'Product'\n * getClassName('Product') // 'Product'\n */\nexport function getClassName(name: string): string {\n if (isQualifiedName(name)) {\n return parseQualifiedName(name).className;\n }\n return name;\n}\n\n/**\n * Extracts the package name from a qualified name.\n * Returns undefined if the name is not qualified.\n *\n * @param name - Qualified name or simple class name\n * @returns The package name, or undefined if not qualified\n *\n * @example\n * getPackageFromQualifiedName('@happyvertical/smrt-core:Product')\n * // Returns: '@happyvertical/smrt-core'\n *\n * getPackageFromQualifiedName('Product')\n * // Returns: undefined\n */\nexport function getPackageFromQualifiedName(name: string): string | undefined {\n if (isQualifiedName(name)) {\n return parseQualifiedName(name).packageName;\n }\n return undefined;\n}\n\n/**\n * Compares two qualified names for equality.\n * Case-sensitive comparison.\n *\n * @param a - First qualified name\n * @param b - Second qualified name\n * @returns true if the qualified names are equal\n */\nexport function qualifiedNamesEqual(a: string, b: string): boolean {\n return a === b;\n}\n\n/**\n * Checks if a qualified name belongs to a specific package.\n *\n * @param qualifiedName - The qualified name to check\n * @param packageName - The package name to match against\n * @returns true if the qualified name is from the specified package\n *\n * @example\n * isFromPackage('@happyvertical/smrt-core:Product', '@happyvertical/smrt-core')\n * // Returns: true\n */\nexport function isFromPackage(\n qualifiedName: string,\n packageName: string,\n): boolean {\n if (!isQualifiedName(qualifiedName)) {\n return false;\n }\n const parsed = parseQualifiedName(qualifiedName);\n return parsed.packageName === packageName;\n}\n\n/**\n * Checks if a qualified name (like `_meta_type`) matches a short class name.\n * This is useful for STI filtering where the database stores qualified names\n * but code often uses short names for comparisons.\n *\n * @param qualifiedName - The qualified name or simple name to check (e.g., from `_meta_type`)\n * @param shortName - The short class name to match against\n * @returns true if the class name portion matches\n *\n * @example\n * ```typescript\n * // Filtering STI records by type\n * const meetings = events.filter(e => isType(e._meta_type, 'Meeting'));\n *\n * // Works with both qualified and simple names\n * isType('@happyvertical/praeco:MeetingRecap', 'MeetingRecap') // true\n * isType('@happyvertical/praeco:MeetingRecap', 'Article') // false\n * isType('MeetingRecap', 'MeetingRecap') // true (simple name passthrough)\n * ```\n */\nexport function isType(\n qualifiedName: string | null | undefined,\n shortName: string,\n): boolean {\n if (!qualifiedName) {\n return false;\n }\n return getClassName(qualifiedName) === shortName;\n}\n\n/**\n * A valid `previousQualifiedNames` entry: exactly what {@link isQualifiedName}\n * accepts (`@scope/package:ClassName` — the predicate eager lookups,\n * `resolveType()` and the lazy manifest loader all use), with an identifier\n * class name and exactly one colon. An unscoped `package:ClassName` is\n * refused: no qualified lookup treats it as qualified, so it could never\n * resolve (#3338).\n */\nexport function isQualifiedNameAliasFormat(name: unknown): name is string {\n if (typeof name !== 'string' || !isQualifiedName(name)) return false;\n const colon = name.lastIndexOf(':');\n // `isQualifiedName()` splits at the LAST colon, so `@scope/pkg:x:Class`\n // would name the package `@scope/pkg:x`, which the lazy loader cannot\n // resolve. An alias's package part may not contain a colon.\n return (\n name.indexOf(':') === colon &&\n !/\\s/u.test(name.slice(0, colon)) &&\n /^[A-Za-z_$][\\w$]*$/u.test(name.slice(colon + 1))\n );\n}\n\n/** The declared aliases of one decorator/manifest config, as strings. */\nexport function readPreviousQualifiedNames(config: unknown): string[] {\n if (!config || typeof config !== 'object') return [];\n const declared = (config as { previousQualifiedNames?: unknown })\n .previousQualifiedNames;\n if (!Array.isArray(declared)) return [];\n return declared.filter((name): name is string => typeof name === 'string');\n}\n"],"mappings":";;;;;;;;;;;;AAuBA,SAAgB,oBACd,aACA,WACoB;CACpB,IAAI,CAAC,aACH,MAAM,IAAI,MACR,yEACoB,UAAU,sBAChC;CAEF,IAAI,CAAC,WACH,MAAM,IAAI,MACR,yEACsB,YAAY,oBACpC;CAEF,OAAO,GAAG,YAAY,GAAG;AAC3B;;;;;;;;;;;;AAuBA,SAAgB,mBAAmB,eAA4C;CAC7E,IAAI,CAAC,gBAAgB,aAAa,GAChC,MAAM,IAAI,MACR,4BAA4B,cAAc,8CAE5C;CAKF,MAAM,aAAa,cAAc,YAAY,GAAG;CAEhD,OAAO;EACL,aAAa,cAAc,MAAM,GAAG,UAAU;EAC9C,WAAW,cAAc,MAAM,aAAa,CAAC;CAC/C;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAAgB,MAA0C;CACxE,IAAI,CAAC,QAAQ,OAAO,SAAS,UAC3B,OAAO;CAGT,MAAM,aAAa,KAAK,YAAY,GAAG;CACvC,IAAI,eAAe,IACjB,OAAO;CAGT,MAAM,cAAc,KAAK,MAAM,GAAG,UAAU;CAC5C,MAAM,YAAY,KAAK,MAAM,aAAa,CAAC;CAI3C,IAAI,CAAC,YAAY,WAAW,GAAG,KAAK,CAAC,YAAY,SAAS,GAAG,GAC3D,OAAO;CAIT,IAAI,CAAC,WACH,OAAO;CAGT,OAAO;AACT;;;;;;;;;;;;;AAcA,SAAgB,aAAa,MAAsB;CACjD,IAAI,gBAAgB,IAAI,GACtB,OAAO,mBAAmB,IAAI,CAAC,CAAC;CAElC,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,4BAA4B,MAAkC;CAC5E,IAAI,gBAAgB,IAAI,GACtB,OAAO,mBAAmB,IAAI,CAAC,CAAC;AAGpC;;;;;;;;;AAUA,SAAgB,oBAAoB,GAAW,GAAoB;CACjE,OAAO,MAAM;AACf;;;;;;;;;;;;AAaA,SAAgB,cACd,eACA,aACS;CACT,IAAI,CAAC,gBAAgB,aAAa,GAChC,OAAO;CAGT,OADe,mBAAmB,aAC3B,CAAA,CAAO,gBAAgB;AAChC;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,OACd,eACA,WACS;CACT,IAAI,CAAC,eACH,OAAO;CAET,OAAO,aAAa,aAAa,MAAM;AACzC;;;;;;;;;AAUA,SAAgB,2BAA2B,MAA+B;CACxE,IAAI,OAAO,SAAS,YAAY,CAAC,gBAAgB,IAAI,GAAG,OAAO;CAC/D,MAAM,QAAQ,KAAK,YAAY,GAAG;CAIlC,OACE,KAAK,QAAQ,GAAG,MAAM,SACtB,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG,KAAK,CAAC,KAChC,sBAAsB,KAAK,KAAK,MAAM,QAAQ,CAAC,CAAC;AAEpD;;AAGA,SAAgB,2BAA2B,QAA2B;CACpE,IAAI,CAAC,UAAU,OAAO,WAAW,UAAU,OAAO,CAAC;CACnD,MAAM,WAAY,OACf;CACH,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO,CAAC;CACtC,OAAO,SAAS,QAAQ,SAAyB,OAAO,SAAS,QAAQ;AAC3E"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-core",
3
- "version": "0.51.39",
3
+ "version": "0.53.0",
4
4
  "description": "Core AI agent framework with standardized collections, object-relational mapping, and code generators",
5
5
  "author": "HappyVertical",
6
6
  "type": "module",
7
7
  "engines": {
8
- "node": ">=24.18.0"
8
+ "node": ">=26.0.0"
9
9
  },
10
10
  "main": "dist/index.js",
11
11
  "types": "dist/index.d.ts",
@@ -150,15 +150,15 @@
150
150
  }
151
151
  },
152
152
  "dependencies": {
153
- "@happyvertical/ai": "^0.96.0",
154
- "@happyvertical/files": "^0.96.0",
155
- "@happyvertical/json": "^0.96.0",
156
- "@happyvertical/logger": "^0.96.0",
157
- "@happyvertical/smrt-config": "0.51.39",
158
- "@happyvertical/smrt-scanner": "0.51.39",
159
- "@happyvertical/smrt-types": "0.51.39",
160
- "@happyvertical/sql": "^0.96.0",
161
- "@happyvertical/utils": "^0.96.0",
153
+ "@happyvertical/ai": "^0.98.0",
154
+ "@happyvertical/files": "^0.98.0",
155
+ "@happyvertical/json": "^0.98.0",
156
+ "@happyvertical/logger": "^0.98.0",
157
+ "@happyvertical/smrt-config": "0.53.0",
158
+ "@happyvertical/smrt-scanner": "0.53.0",
159
+ "@happyvertical/smrt-types": "0.53.0",
160
+ "@happyvertical/sql": "^0.98.0",
161
+ "@happyvertical/utils": "^0.98.0",
162
162
  "@oxc-project/runtime": "^0.150.0",
163
163
  "cheerio": "^1.2.0",
164
164
  "fast-glob": "3.3.3",