@happyvertical/smrt-core 0.30.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 (631) hide show
  1. package/AGENTS.md +124 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +265 -0
  5. package/bin/smrt-prebuild.js +26 -0
  6. package/dist/__tests__/fixtures/advisor-test-classes.d.ts +28 -0
  7. package/dist/__tests__/fixtures/advisor-test-classes.d.ts.map +1 -0
  8. package/dist/__tests__/fixtures/collection-coverage-fixtures.d.ts +12 -0
  9. package/dist/__tests__/fixtures/collection-coverage-fixtures.d.ts.map +1 -0
  10. package/dist/__tests__/fixtures/inheritance-resolver-fixtures.d.ts +28 -0
  11. package/dist/__tests__/fixtures/inheritance-resolver-fixtures.d.ts.map +1 -0
  12. package/dist/__tests__/fixtures/inheritance-test-classes.d.ts +43 -0
  13. package/dist/__tests__/fixtures/inheritance-test-classes.d.ts.map +1 -0
  14. package/dist/__tests__/fixtures/mcp-integration-test-classes.d.ts +18 -0
  15. package/dist/__tests__/fixtures/mcp-integration-test-classes.d.ts.map +1 -0
  16. package/dist/__tests__/fixtures/object-ai-memory-fixtures.d.ts +15 -0
  17. package/dist/__tests__/fixtures/object-ai-memory-fixtures.d.ts.map +1 -0
  18. package/dist/__tests__/fixtures/object-spec-test-classes.d.ts +13 -0
  19. package/dist/__tests__/fixtures/object-spec-test-classes.d.ts.map +1 -0
  20. package/dist/__tests__/fixtures/registry-test-classes.d.ts +23 -0
  21. package/dist/__tests__/fixtures/registry-test-classes.d.ts.map +1 -0
  22. package/dist/adapters/ai-usage.d.ts +23 -0
  23. package/dist/adapters/ai-usage.d.ts.map +1 -0
  24. package/dist/adapters/ai-usage.js +105 -0
  25. package/dist/adapters/ai-usage.js.map +1 -0
  26. package/dist/adapters/cost-rates.d.ts +20 -0
  27. package/dist/adapters/cost-rates.d.ts.map +1 -0
  28. package/dist/adapters/cost-rates.js +40 -0
  29. package/dist/adapters/cost-rates.js.map +1 -0
  30. package/dist/adapters/index.d.ts +19 -0
  31. package/dist/adapters/index.d.ts.map +1 -0
  32. package/dist/adapters/metrics.d.ts +111 -0
  33. package/dist/adapters/metrics.d.ts.map +1 -0
  34. package/dist/adapters/metrics.js +169 -0
  35. package/dist/adapters/metrics.js.map +1 -0
  36. package/dist/adapters/pubsub.d.ts +124 -0
  37. package/dist/adapters/pubsub.d.ts.map +1 -0
  38. package/dist/adapters/pubsub.js +121 -0
  39. package/dist/adapters/pubsub.js.map +1 -0
  40. package/dist/browser.d.ts +32 -0
  41. package/dist/browser.d.ts.map +1 -0
  42. package/dist/browser.js +68 -0
  43. package/dist/browser.js.map +1 -0
  44. package/dist/child-accessors.d.ts +27 -0
  45. package/dist/child-accessors.d.ts.map +1 -0
  46. package/dist/child-accessors.js +35 -0
  47. package/dist/child-accessors.js.map +1 -0
  48. package/dist/class.d.ts +313 -0
  49. package/dist/class.d.ts.map +1 -0
  50. package/dist/class.js +896 -0
  51. package/dist/class.js.map +1 -0
  52. package/dist/collection-cache.d.ts +110 -0
  53. package/dist/collection-cache.d.ts.map +1 -0
  54. package/dist/collection-cache.js +187 -0
  55. package/dist/collection-cache.js.map +1 -0
  56. package/dist/collection.d.ts +894 -0
  57. package/dist/collection.d.ts.map +1 -0
  58. package/dist/collection.js +1987 -0
  59. package/dist/collection.js.map +1 -0
  60. package/dist/config/global-config.d.ts +3 -0
  61. package/dist/config/global-config.d.ts.map +1 -0
  62. package/dist/config/global-config.js +19 -0
  63. package/dist/config/global-config.js.map +1 -0
  64. package/dist/config.d.ts +145 -0
  65. package/dist/config.d.ts.map +1 -0
  66. package/dist/config.js +57 -0
  67. package/dist/config.js.map +1 -0
  68. package/dist/consumer-plugin/index.d.ts +22 -0
  69. package/dist/consumer-plugin/index.d.ts.map +1 -0
  70. package/dist/consumer-plugin/index.js +452 -0
  71. package/dist/consumer-plugin/index.js.map +1 -0
  72. package/dist/consumer-plugin.d.ts +8 -0
  73. package/dist/consumer-plugin.d.ts.map +1 -0
  74. package/dist/consumer-plugin.js +5 -0
  75. package/dist/consumer-plugin.js.map +1 -0
  76. package/dist/database.d.ts +95 -0
  77. package/dist/database.d.ts.map +1 -0
  78. package/dist/database.js +32 -0
  79. package/dist/database.js.map +1 -0
  80. package/dist/decorators/compatibility.d.ts +14 -0
  81. package/dist/decorators/compatibility.d.ts.map +1 -0
  82. package/dist/decorators/compatibility.js +111 -0
  83. package/dist/decorators/compatibility.js.map +1 -0
  84. package/dist/decorators/index.d.ts +381 -0
  85. package/dist/decorators/index.d.ts.map +1 -0
  86. package/dist/decorators/index.js +104 -0
  87. package/dist/decorators/index.js.map +1 -0
  88. package/dist/dispatch/bus.d.ts +306 -0
  89. package/dist/dispatch/bus.d.ts.map +1 -0
  90. package/dist/dispatch/bus.js +583 -0
  91. package/dist/dispatch/bus.js.map +1 -0
  92. package/dist/dispatch/collections/DispatchSubscriptions.d.ts +79 -0
  93. package/dist/dispatch/collections/DispatchSubscriptions.d.ts.map +1 -0
  94. package/dist/dispatch/collections/DispatchSubscriptions.js +243 -0
  95. package/dist/dispatch/collections/DispatchSubscriptions.js.map +1 -0
  96. package/dist/dispatch/collections/Dispatches.d.ts +98 -0
  97. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -0
  98. package/dist/dispatch/collections/Dispatches.js +358 -0
  99. package/dist/dispatch/collections/Dispatches.js.map +1 -0
  100. package/dist/dispatch/index.d.ts +47 -0
  101. package/dist/dispatch/index.d.ts.map +1 -0
  102. package/dist/dispatch/models/Dispatch.d.ts +101 -0
  103. package/dist/dispatch/models/Dispatch.d.ts.map +1 -0
  104. package/dist/dispatch/models/Dispatch.js +162 -0
  105. package/dist/dispatch/models/Dispatch.js.map +1 -0
  106. package/dist/dispatch/models/DispatchSubscription.d.ts +83 -0
  107. package/dist/dispatch/models/DispatchSubscription.d.ts.map +1 -0
  108. package/dist/dispatch/models/DispatchSubscription.js +112 -0
  109. package/dist/dispatch/models/DispatchSubscription.js.map +1 -0
  110. package/dist/dispatch/tenant-resolver.d.ts +98 -0
  111. package/dist/dispatch/tenant-resolver.d.ts.map +1 -0
  112. package/dist/dispatch/tenant-resolver.js +32 -0
  113. package/dist/dispatch/tenant-resolver.js.map +1 -0
  114. package/dist/dispatch/types.d.ts +149 -0
  115. package/dist/dispatch/types.d.ts.map +1 -0
  116. package/dist/embeddings/hash.d.ts +33 -0
  117. package/dist/embeddings/hash.d.ts.map +1 -0
  118. package/dist/embeddings/hash.js +37 -0
  119. package/dist/embeddings/hash.js.map +1 -0
  120. package/dist/embeddings/index.d.ts +36 -0
  121. package/dist/embeddings/index.d.ts.map +1 -0
  122. package/dist/embeddings/provider.d.ts +75 -0
  123. package/dist/embeddings/provider.d.ts.map +1 -0
  124. package/dist/embeddings/provider.js +170 -0
  125. package/dist/embeddings/provider.js.map +1 -0
  126. package/dist/embeddings/similarity.d.ts +47 -0
  127. package/dist/embeddings/similarity.d.ts.map +1 -0
  128. package/dist/embeddings/similarity.js +64 -0
  129. package/dist/embeddings/similarity.js.map +1 -0
  130. package/dist/embeddings/storage.d.ts +125 -0
  131. package/dist/embeddings/storage.d.ts.map +1 -0
  132. package/dist/embeddings/storage.js +283 -0
  133. package/dist/embeddings/storage.js.map +1 -0
  134. package/dist/embeddings/types.d.ts +250 -0
  135. package/dist/embeddings/types.d.ts.map +1 -0
  136. package/dist/errors.d.ts +363 -0
  137. package/dist/errors.d.ts.map +1 -0
  138. package/dist/errors.js +669 -0
  139. package/dist/errors.js.map +1 -0
  140. package/dist/generators/cli.d.ts +162 -0
  141. package/dist/generators/cli.d.ts.map +1 -0
  142. package/dist/generators/cli.js +462 -0
  143. package/dist/generators/cli.js.map +1 -0
  144. package/dist/generators/index.d.ts +13 -0
  145. package/dist/generators/index.d.ts.map +1 -0
  146. package/dist/generators/mcp-runtime-template.d.ts +60 -0
  147. package/dist/generators/mcp-runtime-template.d.ts.map +1 -0
  148. package/dist/generators/mcp-runtime-template.js +509 -0
  149. package/dist/generators/mcp-runtime-template.js.map +1 -0
  150. package/dist/generators/mcp.d.ts +231 -0
  151. package/dist/generators/mcp.d.ts.map +1 -0
  152. package/dist/generators/mcp.js +1220 -0
  153. package/dist/generators/mcp.js.map +1 -0
  154. package/dist/generators/rest.d.ts +171 -0
  155. package/dist/generators/rest.d.ts.map +1 -0
  156. package/dist/generators/rest.js +591 -0
  157. package/dist/generators/rest.js.map +1 -0
  158. package/dist/generators/swagger.d.ts +21 -0
  159. package/dist/generators/swagger.d.ts.map +1 -0
  160. package/dist/generators/swagger.js +307 -0
  161. package/dist/generators/swagger.js.map +1 -0
  162. package/dist/generators/tenant-gate.d.ts +74 -0
  163. package/dist/generators/tenant-gate.d.ts.map +1 -0
  164. package/dist/generators/tenant-gate.js +15 -0
  165. package/dist/generators/tenant-gate.js.map +1 -0
  166. package/dist/generators.d.ts +8 -0
  167. package/dist/generators.d.ts.map +1 -0
  168. package/dist/generators.js +19 -0
  169. package/dist/generators.js.map +1 -0
  170. package/dist/hierarchical.d.ts +103 -0
  171. package/dist/hierarchical.d.ts.map +1 -0
  172. package/dist/hierarchical.js +184 -0
  173. package/dist/hierarchical.js.map +1 -0
  174. package/dist/index.d.ts +57 -0
  175. package/dist/index.d.ts.map +1 -0
  176. package/dist/index.js +202 -0
  177. package/dist/index.js.map +1 -0
  178. package/dist/interceptors.d.ts +251 -0
  179. package/dist/interceptors.d.ts.map +1 -0
  180. package/dist/interceptors.js +259 -0
  181. package/dist/interceptors.js.map +1 -0
  182. package/dist/junction.d.ts +99 -0
  183. package/dist/junction.d.ts.map +1 -0
  184. package/dist/junction.js +136 -0
  185. package/dist/junction.js.map +1 -0
  186. package/dist/knowledge.d.ts +11 -0
  187. package/dist/knowledge.d.ts.map +1 -0
  188. package/dist/knowledge.js +310 -0
  189. package/dist/knowledge.js.map +1 -0
  190. package/dist/lazy-config.d.ts +160 -0
  191. package/dist/lazy-config.d.ts.map +1 -0
  192. package/dist/lazy-config.js +146 -0
  193. package/dist/lazy-config.js.map +1 -0
  194. package/dist/manifest/discover-base-classes.d.ts +78 -0
  195. package/dist/manifest/discover-base-classes.d.ts.map +1 -0
  196. package/dist/manifest/discover-base-classes.js +85 -0
  197. package/dist/manifest/discover-base-classes.js.map +1 -0
  198. package/dist/manifest/discover-smrt-packages.d.ts +48 -0
  199. package/dist/manifest/discover-smrt-packages.d.ts.map +1 -0
  200. package/dist/manifest/discover-smrt-packages.js +361 -0
  201. package/dist/manifest/discover-smrt-packages.js.map +1 -0
  202. package/dist/manifest/generator.d.ts +93 -0
  203. package/dist/manifest/generator.d.ts.map +1 -0
  204. package/dist/manifest/generator.js +380 -0
  205. package/dist/manifest/generator.js.map +1 -0
  206. package/dist/manifest/index.d.ts +16 -0
  207. package/dist/manifest/index.d.ts.map +1 -0
  208. package/dist/manifest/index.js +51 -0
  209. package/dist/manifest/index.js.map +1 -0
  210. package/dist/manifest/manager.d.ts +51 -0
  211. package/dist/manifest/manager.d.ts.map +1 -0
  212. package/dist/manifest/manager.js +89 -0
  213. package/dist/manifest/manager.js.map +1 -0
  214. package/dist/manifest/manifest-loader.d.ts +187 -0
  215. package/dist/manifest/manifest-loader.d.ts.map +1 -0
  216. package/dist/manifest/manifest-loader.js +847 -0
  217. package/dist/manifest/manifest-loader.js.map +1 -0
  218. package/dist/manifest/sources/composite.d.ts +22 -0
  219. package/dist/manifest/sources/composite.d.ts.map +1 -0
  220. package/dist/manifest/sources/composite.js +60 -0
  221. package/dist/manifest/sources/composite.js.map +1 -0
  222. package/dist/manifest/sources/embedded.d.ts +7 -0
  223. package/dist/manifest/sources/embedded.d.ts.map +1 -0
  224. package/dist/manifest/sources/embedded.js +30 -0
  225. package/dist/manifest/sources/embedded.js.map +1 -0
  226. package/dist/manifest/sources/explicit-paths.d.ts +17 -0
  227. package/dist/manifest/sources/explicit-paths.d.ts.map +1 -0
  228. package/dist/manifest/sources/explicit-paths.js +35 -0
  229. package/dist/manifest/sources/explicit-paths.js.map +1 -0
  230. package/dist/manifest/sources/fallback.d.ts +25 -0
  231. package/dist/manifest/sources/fallback.d.ts.map +1 -0
  232. package/dist/manifest/sources/fallback.js +63 -0
  233. package/dist/manifest/sources/fallback.js.map +1 -0
  234. package/dist/manifest/sources/index.d.ts +17 -0
  235. package/dist/manifest/sources/index.d.ts.map +1 -0
  236. package/dist/manifest/sources/local-test.d.ts +7 -0
  237. package/dist/manifest/sources/local-test.d.ts.map +1 -0
  238. package/dist/manifest/sources/local-test.js +21 -0
  239. package/dist/manifest/sources/local-test.js.map +1 -0
  240. package/dist/manifest/sources/static.d.ts +7 -0
  241. package/dist/manifest/sources/static.d.ts.map +1 -0
  242. package/dist/manifest/sources/static.js +19 -0
  243. package/dist/manifest/sources/static.js.map +1 -0
  244. package/dist/manifest/sources/test.d.ts +7 -0
  245. package/dist/manifest/sources/test.d.ts.map +1 -0
  246. package/dist/manifest/sources/test.js +21 -0
  247. package/dist/manifest/sources/test.js.map +1 -0
  248. package/dist/manifest/sources/types.d.ts +79 -0
  249. package/dist/manifest/sources/types.d.ts.map +1 -0
  250. package/dist/manifest/sources/types.js +61 -0
  251. package/dist/manifest/sources/types.js.map +1 -0
  252. package/dist/manifest/static-manifest.d.ts +4 -0
  253. package/dist/manifest/static-manifest.d.ts.map +1 -0
  254. package/dist/manifest/static-manifest.js +1535 -0
  255. package/dist/manifest/static-manifest.js.map +1 -0
  256. package/dist/manifest/store.d.ts +111 -0
  257. package/dist/manifest/store.d.ts.map +1 -0
  258. package/dist/manifest/store.js +431 -0
  259. package/dist/manifest/store.js.map +1 -0
  260. package/dist/manifest/test-manifest-loader.d.ts +3 -0
  261. package/dist/manifest/test-manifest-loader.d.ts.map +1 -0
  262. package/dist/manifest/test-manifest-stub.d.ts +4 -0
  263. package/dist/manifest/test-manifest-stub.d.ts.map +1 -0
  264. package/dist/manifest/test-manifest-stub.js +80013 -0
  265. package/dist/manifest/test-manifest-stub.js.map +1 -0
  266. package/dist/manifest.d.ts +8 -0
  267. package/dist/manifest.d.ts.map +1 -0
  268. package/dist/manifest.js +20 -0
  269. package/dist/manifest.js.map +1 -0
  270. package/dist/manifest.json +1489 -0
  271. package/dist/mcp-advisor/index.d.ts +499 -0
  272. package/dist/mcp-advisor/index.d.ts.map +1 -0
  273. package/dist/mcp-advisor/tools/add-ai-methods.d.ts +6 -0
  274. package/dist/mcp-advisor/tools/add-ai-methods.d.ts.map +1 -0
  275. package/dist/mcp-advisor/tools/configure-decorators.d.ts +6 -0
  276. package/dist/mcp-advisor/tools/configure-decorators.d.ts.map +1 -0
  277. package/dist/mcp-advisor/tools/generate-collection.d.ts +6 -0
  278. package/dist/mcp-advisor/tools/generate-collection.d.ts.map +1 -0
  279. package/dist/mcp-advisor/tools/generate-field-definitions.d.ts +6 -0
  280. package/dist/mcp-advisor/tools/generate-field-definitions.d.ts.map +1 -0
  281. package/dist/mcp-advisor/tools/generate-smrt-class.d.ts +6 -0
  282. package/dist/mcp-advisor/tools/generate-smrt-class.d.ts.map +1 -0
  283. package/dist/mcp-advisor/tools/get-object-config.d.ts +6 -0
  284. package/dist/mcp-advisor/tools/get-object-config.d.ts.map +1 -0
  285. package/dist/mcp-advisor/tools/get-object-schema.d.ts +10 -0
  286. package/dist/mcp-advisor/tools/get-object-schema.d.ts.map +1 -0
  287. package/dist/mcp-advisor/tools/list-registered-objects.d.ts +9 -0
  288. package/dist/mcp-advisor/tools/list-registered-objects.d.ts.map +1 -0
  289. package/dist/mcp-advisor/tools/preview-api-endpoints.d.ts +9 -0
  290. package/dist/mcp-advisor/tools/preview-api-endpoints.d.ts.map +1 -0
  291. package/dist/mcp-advisor/tools/preview-mcp-tools.d.ts +9 -0
  292. package/dist/mcp-advisor/tools/preview-mcp-tools.d.ts.map +1 -0
  293. package/dist/mcp-advisor/tools/validate-smrt-object.d.ts +6 -0
  294. package/dist/mcp-advisor/tools/validate-smrt-object.d.ts.map +1 -0
  295. package/dist/mcp-advisor/types.d.ts +209 -0
  296. package/dist/mcp-advisor/types.d.ts.map +1 -0
  297. package/dist/migrations/backfill-tracker.d.ts +84 -0
  298. package/dist/migrations/backfill-tracker.d.ts.map +1 -0
  299. package/dist/migrations/backfill-tracker.js +118 -0
  300. package/dist/migrations/backfill-tracker.js.map +1 -0
  301. package/dist/migrations/checksum.d.ts +43 -0
  302. package/dist/migrations/checksum.d.ts.map +1 -0
  303. package/dist/migrations/checksum.js +32 -0
  304. package/dist/migrations/checksum.js.map +1 -0
  305. package/dist/migrations/differ.d.ts +186 -0
  306. package/dist/migrations/differ.d.ts.map +1 -0
  307. package/dist/migrations/differ.js +601 -0
  308. package/dist/migrations/differ.js.map +1 -0
  309. package/dist/migrations/generator.d.ts +133 -0
  310. package/dist/migrations/generator.d.ts.map +1 -0
  311. package/dist/migrations/generator.js +328 -0
  312. package/dist/migrations/generator.js.map +1 -0
  313. package/dist/migrations/index.d.ts +20 -0
  314. package/dist/migrations/index.d.ts.map +1 -0
  315. package/dist/migrations/orchestrate.d.ts +148 -0
  316. package/dist/migrations/orchestrate.d.ts.map +1 -0
  317. package/dist/migrations/orchestrate.js +118 -0
  318. package/dist/migrations/orchestrate.js.map +1 -0
  319. package/dist/migrations/tracker.d.ts +134 -0
  320. package/dist/migrations/tracker.d.ts.map +1 -0
  321. package/dist/migrations/tracker.js +624 -0
  322. package/dist/migrations/tracker.js.map +1 -0
  323. package/dist/migrations/types.d.ts +221 -0
  324. package/dist/migrations/types.d.ts.map +1 -0
  325. package/dist/migrations.d.ts +7 -0
  326. package/dist/migrations.d.ts.map +1 -0
  327. package/dist/migrations.js +26 -0
  328. package/dist/migrations.js.map +1 -0
  329. package/dist/node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js +56 -0
  330. package/dist/node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js.map +1 -0
  331. package/dist/node_modules/.pnpm/brace-expansion@5.0.5/node_modules/brace-expansion/dist/esm/index.js +163 -0
  332. package/dist/node_modules/.pnpm/brace-expansion@5.0.5/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
  333. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/assert-valid-pattern.js +13 -0
  334. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -0
  335. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js +654 -0
  336. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js.map +1 -0
  337. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/brace-expressions.js +111 -0
  338. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -0
  339. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/escape.js +10 -0
  340. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/escape.js.map +1 -0
  341. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js +824 -0
  342. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js.map +1 -0
  343. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js +10 -0
  344. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js.map +1 -0
  345. package/dist/object.d.ts +1202 -0
  346. package/dist/object.d.ts.map +1 -0
  347. package/dist/object.js +2731 -0
  348. package/dist/object.js.map +1 -0
  349. package/dist/polymorphic-association.d.ts +69 -0
  350. package/dist/polymorphic-association.d.ts.map +1 -0
  351. package/dist/polymorphic-association.js +96 -0
  352. package/dist/polymorphic-association.js.map +1 -0
  353. package/dist/prebuild/cli.d.ts +7 -0
  354. package/dist/prebuild/cli.d.ts.map +1 -0
  355. package/dist/prebuild/cli.js +29 -0
  356. package/dist/prebuild/cli.js.map +1 -0
  357. package/dist/prebuild/index.d.ts +22 -0
  358. package/dist/prebuild/index.d.ts.map +1 -0
  359. package/dist/prebuild/index.js +239 -0
  360. package/dist/prebuild/index.js.map +1 -0
  361. package/dist/prebuild.d.ts +8 -0
  362. package/dist/prebuild.d.ts.map +1 -0
  363. package/dist/prebuild.js +6 -0
  364. package/dist/prebuild.js.map +1 -0
  365. package/dist/registry/cache-config.d.ts +13 -0
  366. package/dist/registry/cache-config.d.ts.map +1 -0
  367. package/dist/registry/cache-config.js +17 -0
  368. package/dist/registry/cache-config.js.map +1 -0
  369. package/dist/registry/class-registration.d.ts +31 -0
  370. package/dist/registry/class-registration.d.ts.map +1 -0
  371. package/dist/registry/class-registration.js +1074 -0
  372. package/dist/registry/class-registration.js.map +1 -0
  373. package/dist/registry/collection-resolution.d.ts +45 -0
  374. package/dist/registry/collection-resolution.d.ts.map +1 -0
  375. package/dist/registry/collection-resolution.js +121 -0
  376. package/dist/registry/collection-resolution.js.map +1 -0
  377. package/dist/registry/collision-policy.d.ts +179 -0
  378. package/dist/registry/collision-policy.d.ts.map +1 -0
  379. package/dist/registry/collision-policy.js +153 -0
  380. package/dist/registry/collision-policy.js.map +1 -0
  381. package/dist/registry/diagnostics.d.ts +58 -0
  382. package/dist/registry/diagnostics.d.ts.map +1 -0
  383. package/dist/registry/diagnostics.js +54 -0
  384. package/dist/registry/diagnostics.js.map +1 -0
  385. package/dist/registry/embedding-manager.d.ts +23 -0
  386. package/dist/registry/embedding-manager.d.ts.map +1 -0
  387. package/dist/registry/embedding-manager.js +62 -0
  388. package/dist/registry/embedding-manager.js.map +1 -0
  389. package/dist/registry/index.d.ts +13 -0
  390. package/dist/registry/index.d.ts.map +1 -0
  391. package/dist/registry/inheritance-resolver.d.ts +13 -0
  392. package/dist/registry/inheritance-resolver.d.ts.map +1 -0
  393. package/dist/registry/inheritance-resolver.js +244 -0
  394. package/dist/registry/inheritance-resolver.js.map +1 -0
  395. package/dist/registry/manifest-field-merge.d.ts +4 -0
  396. package/dist/registry/manifest-field-merge.d.ts.map +1 -0
  397. package/dist/registry/manifest-field-merge.js +82 -0
  398. package/dist/registry/manifest-field-merge.js.map +1 -0
  399. package/dist/registry/name-resolver.d.ts +102 -0
  400. package/dist/registry/name-resolver.d.ts.map +1 -0
  401. package/dist/registry/name-resolver.js +241 -0
  402. package/dist/registry/name-resolver.js.map +1 -0
  403. package/dist/registry/relationship-graph.d.ts +16 -0
  404. package/dist/registry/relationship-graph.d.ts.map +1 -0
  405. package/dist/registry/relationship-graph.js +79 -0
  406. package/dist/registry/relationship-graph.js.map +1 -0
  407. package/dist/registry/schema-builder.d.ts +113 -0
  408. package/dist/registry/schema-builder.d.ts.map +1 -0
  409. package/dist/registry/schema-builder.js +474 -0
  410. package/dist/registry/schema-builder.js.map +1 -0
  411. package/dist/registry/shared-state.d.ts +62 -0
  412. package/dist/registry/shared-state.d.ts.map +1 -0
  413. package/dist/registry/shared-state.js +135 -0
  414. package/dist/registry/shared-state.js.map +1 -0
  415. package/dist/registry/types.d.ts +667 -0
  416. package/dist/registry/types.d.ts.map +1 -0
  417. package/dist/registry/validator.d.ts +13 -0
  418. package/dist/registry/validator.d.ts.map +1 -0
  419. package/dist/registry/validator.js +138 -0
  420. package/dist/registry/validator.js.map +1 -0
  421. package/dist/registry.d.ts +1358 -0
  422. package/dist/registry.d.ts.map +1 -0
  423. package/dist/registry.js +2301 -0
  424. package/dist/registry.js.map +1 -0
  425. package/dist/runtime/client.d.ts +34 -0
  426. package/dist/runtime/client.d.ts.map +1 -0
  427. package/dist/runtime/client.js +104 -0
  428. package/dist/runtime/client.js.map +1 -0
  429. package/dist/runtime/index.d.ts +10 -0
  430. package/dist/runtime/index.d.ts.map +1 -0
  431. package/dist/runtime/mcp.d.ts +47 -0
  432. package/dist/runtime/mcp.d.ts.map +1 -0
  433. package/dist/runtime/mcp.js +72 -0
  434. package/dist/runtime/mcp.js.map +1 -0
  435. package/dist/runtime/server.d.ts +92 -0
  436. package/dist/runtime/server.d.ts.map +1 -0
  437. package/dist/runtime/server.js +390 -0
  438. package/dist/runtime/server.js.map +1 -0
  439. package/dist/runtime/types.d.ts +58 -0
  440. package/dist/runtime/types.d.ts.map +1 -0
  441. package/dist/runtime.d.ts +8 -0
  442. package/dist/runtime.d.ts.map +1 -0
  443. package/dist/runtime.js +10 -0
  444. package/dist/runtime.js.map +1 -0
  445. package/dist/scanner/import-scanner.d.ts +7 -0
  446. package/dist/scanner/import-scanner.d.ts.map +1 -0
  447. package/dist/scanner/index.d.ts +12 -0
  448. package/dist/scanner/index.d.ts.map +1 -0
  449. package/dist/scanner/manifest-generator.d.ts +304 -0
  450. package/dist/scanner/manifest-generator.d.ts.map +1 -0
  451. package/dist/scanner/manifest-generator.js +1707 -0
  452. package/dist/scanner/manifest-generator.js.map +1 -0
  453. package/dist/scanner/test-file-patterns.d.ts +18 -0
  454. package/dist/scanner/test-file-patterns.d.ts.map +1 -0
  455. package/dist/scanner/test-file-patterns.js +16 -0
  456. package/dist/scanner/test-file-patterns.js.map +1 -0
  457. package/dist/scanner/types.d.ts +313 -0
  458. package/dist/scanner/types.d.ts.map +1 -0
  459. package/dist/scanner/types.js +2 -0
  460. package/dist/scanner/types.js.map +1 -0
  461. package/dist/scanner.d.ts +6 -0
  462. package/dist/scanner.d.ts.map +1 -0
  463. package/dist/scanner.js +6 -0
  464. package/dist/scanner.js.map +1 -0
  465. package/dist/schema/code-generator.d.ts +53 -0
  466. package/dist/schema/code-generator.d.ts.map +1 -0
  467. package/dist/schema/ddl/base-strategy.d.ts +80 -0
  468. package/dist/schema/ddl/base-strategy.d.ts.map +1 -0
  469. package/dist/schema/ddl/base-strategy.js +240 -0
  470. package/dist/schema/ddl/base-strategy.js.map +1 -0
  471. package/dist/schema/ddl/duckdb-strategy.d.ts +33 -0
  472. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -0
  473. package/dist/schema/ddl/duckdb-strategy.js +74 -0
  474. package/dist/schema/ddl/duckdb-strategy.js.map +1 -0
  475. package/dist/schema/ddl/index.d.ts +53 -0
  476. package/dist/schema/ddl/index.d.ts.map +1 -0
  477. package/dist/schema/ddl/index.js +80 -0
  478. package/dist/schema/ddl/index.js.map +1 -0
  479. package/dist/schema/ddl/json-duckdb-strategy.d.ts +8 -0
  480. package/dist/schema/ddl/json-duckdb-strategy.d.ts.map +1 -0
  481. package/dist/schema/ddl/json-duckdb-strategy.js +14 -0
  482. package/dist/schema/ddl/json-duckdb-strategy.js.map +1 -0
  483. package/dist/schema/ddl/postgres-strategy.d.ts +29 -0
  484. package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -0
  485. package/dist/schema/ddl/postgres-strategy.js +102 -0
  486. package/dist/schema/ddl/postgres-strategy.js.map +1 -0
  487. package/dist/schema/ddl/sqlite-strategy.d.ts +38 -0
  488. package/dist/schema/ddl/sqlite-strategy.d.ts.map +1 -0
  489. package/dist/schema/ddl/sqlite-strategy.js +74 -0
  490. package/dist/schema/ddl/sqlite-strategy.js.map +1 -0
  491. package/dist/schema/ddl/types.d.ts +114 -0
  492. package/dist/schema/ddl/types.d.ts.map +1 -0
  493. package/dist/schema/generator.d.ts +176 -0
  494. package/dist/schema/generator.d.ts.map +1 -0
  495. package/dist/schema/generator.js +1076 -0
  496. package/dist/schema/generator.js.map +1 -0
  497. package/dist/schema/index-utils.d.ts +19 -0
  498. package/dist/schema/index-utils.d.ts.map +1 -0
  499. package/dist/schema/index-utils.js +32 -0
  500. package/dist/schema/index-utils.js.map +1 -0
  501. package/dist/schema/index.d.ts +13 -0
  502. package/dist/schema/index.d.ts.map +1 -0
  503. package/dist/schema/override-system.d.ts +43 -0
  504. package/dist/schema/override-system.d.ts.map +1 -0
  505. package/dist/schema/schema-aggregator.d.ts +112 -0
  506. package/dist/schema/schema-aggregator.d.ts.map +1 -0
  507. package/dist/schema/schema-manager.d.ts +95 -0
  508. package/dist/schema/schema-manager.d.ts.map +1 -0
  509. package/dist/schema/schema-manager.js +283 -0
  510. package/dist/schema/schema-manager.js.map +1 -0
  511. package/dist/schema/sql-identifiers.d.ts +107 -0
  512. package/dist/schema/sql-identifiers.d.ts.map +1 -0
  513. package/dist/schema/sql-identifiers.js +190 -0
  514. package/dist/schema/sql-identifiers.js.map +1 -0
  515. package/dist/schema/table-verifier.d.ts +10 -0
  516. package/dist/schema/table-verifier.d.ts.map +1 -0
  517. package/dist/schema/table-verifier.js +37 -0
  518. package/dist/schema/table-verifier.js.map +1 -0
  519. package/dist/schema/types.d.ts +241 -0
  520. package/dist/schema/types.d.ts.map +1 -0
  521. package/dist/schema/utils.d.ts +32 -0
  522. package/dist/schema/utils.d.ts.map +1 -0
  523. package/dist/schema/utils.js +134 -0
  524. package/dist/schema/utils.js.map +1 -0
  525. package/dist/scripts/create-wrappers.js +89 -0
  526. package/dist/scripts/generate-manifest.js +155 -0
  527. package/dist/scripts/generate-test-manifest.js +77 -0
  528. package/dist/scripts/migrate-datetime-to-timestamp.ts +310 -0
  529. package/dist/scripts/prepack.js +49 -0
  530. package/dist/signals/bus.d.ts +64 -0
  531. package/dist/signals/bus.d.ts.map +1 -0
  532. package/dist/signals/bus.js +102 -0
  533. package/dist/signals/bus.js.map +1 -0
  534. package/dist/signals/index.d.ts +11 -0
  535. package/dist/signals/index.d.ts.map +1 -0
  536. package/dist/signals/sanitizer.d.ts +54 -0
  537. package/dist/signals/sanitizer.d.ts.map +1 -0
  538. package/dist/signals/sanitizer.js +111 -0
  539. package/dist/signals/sanitizer.js.map +1 -0
  540. package/dist/smrt-knowledge.json +335 -0
  541. package/dist/system/compatibility.d.ts +8 -0
  542. package/dist/system/compatibility.d.ts.map +1 -0
  543. package/dist/system/compatibility.js +409 -0
  544. package/dist/system/compatibility.js.map +1 -0
  545. package/dist/system/index.d.ts +9 -0
  546. package/dist/system/index.d.ts.map +1 -0
  547. package/dist/system/schema.d.ts +69 -0
  548. package/dist/system/schema.d.ts.map +1 -0
  549. package/dist/system/schema.js +271 -0
  550. package/dist/system/schema.js.map +1 -0
  551. package/dist/system/types.d.ts +135 -0
  552. package/dist/system/types.d.ts.map +1 -0
  553. package/dist/system-fields.d.ts +44 -0
  554. package/dist/system-fields.d.ts.map +1 -0
  555. package/dist/system-fields.js +55 -0
  556. package/dist/system-fields.js.map +1 -0
  557. package/dist/table-cache.d.ts +28 -0
  558. package/dist/table-cache.d.ts.map +1 -0
  559. package/dist/table-cache.js +21 -0
  560. package/dist/table-cache.js.map +1 -0
  561. package/dist/test-utils.d.ts +140 -0
  562. package/dist/test-utils.d.ts.map +1 -0
  563. package/dist/testing/database.d.ts +73 -0
  564. package/dist/testing/database.d.ts.map +1 -0
  565. package/dist/testing/database.js +204 -0
  566. package/dist/testing/database.js.map +1 -0
  567. package/dist/testing/index.d.ts +21 -0
  568. package/dist/testing/index.d.ts.map +1 -0
  569. package/dist/testing.d.ts +6 -0
  570. package/dist/testing.d.ts.map +1 -0
  571. package/dist/testing.js +5 -0
  572. package/dist/testing.js.map +1 -0
  573. package/dist/tools/index.d.ts +8 -0
  574. package/dist/tools/index.d.ts.map +1 -0
  575. package/dist/tools/tool-executor.d.ts +101 -0
  576. package/dist/tools/tool-executor.d.ts.map +1 -0
  577. package/dist/tools/tool-executor.js +142 -0
  578. package/dist/tools/tool-executor.js.map +1 -0
  579. package/dist/tools/tool-generator.d.ts +54 -0
  580. package/dist/tools/tool-generator.d.ts.map +1 -0
  581. package/dist/tools/tool-generator.js +121 -0
  582. package/dist/tools/tool-generator.js.map +1 -0
  583. package/dist/utils/chunk.d.ts +32 -0
  584. package/dist/utils/chunk.d.ts.map +1 -0
  585. package/dist/utils/chunk.js +14 -0
  586. package/dist/utils/chunk.js.map +1 -0
  587. package/dist/utils/import-workspace-module.d.ts +8 -0
  588. package/dist/utils/import-workspace-module.d.ts.map +1 -0
  589. package/dist/utils/import-workspace-module.js +81 -0
  590. package/dist/utils/import-workspace-module.js.map +1 -0
  591. package/dist/utils/json.d.ts +102 -0
  592. package/dist/utils/json.d.ts.map +1 -0
  593. package/dist/utils/json.js +43 -0
  594. package/dist/utils/json.js.map +1 -0
  595. package/dist/utils/lru-cache.d.ts +69 -0
  596. package/dist/utils/lru-cache.d.ts.map +1 -0
  597. package/dist/utils/lru-cache.js +100 -0
  598. package/dist/utils/lru-cache.js.map +1 -0
  599. package/dist/utils/naming.d.ts +16 -0
  600. package/dist/utils/naming.d.ts.map +1 -0
  601. package/dist/utils/naming.js +23 -0
  602. package/dist/utils/naming.js.map +1 -0
  603. package/dist/utils/qualified-names.d.ts +122 -0
  604. package/dist/utils/qualified-names.d.ts.map +1 -0
  605. package/dist/utils/qualified-names.js +82 -0
  606. package/dist/utils/qualified-names.js.map +1 -0
  607. package/dist/utils/scanner-module.d.ts +37 -0
  608. package/dist/utils/scanner-module.d.ts.map +1 -0
  609. package/dist/utils.d.ts +177 -0
  610. package/dist/utils.d.ts.map +1 -0
  611. package/dist/utils.js +185 -0
  612. package/dist/utils.js.map +1 -0
  613. package/dist/vite-plugin/import-build-aware.d.ts +68 -0
  614. package/dist/vite-plugin/import-build-aware.d.ts.map +1 -0
  615. package/dist/vite-plugin/import-build-aware.js +72 -0
  616. package/dist/vite-plugin/import-build-aware.js.map +1 -0
  617. package/dist/vite-plugin/index.d.ts +59 -0
  618. package/dist/vite-plugin/index.d.ts.map +1 -0
  619. package/dist/vite-plugin/index.js +1400 -0
  620. package/dist/vite-plugin/index.js.map +1 -0
  621. package/dist/vite-plugin/sveltekit-generator.d.ts +66 -0
  622. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -0
  623. package/dist/vite-plugin/sveltekit-generator.js +1375 -0
  624. package/dist/vite-plugin/sveltekit-generator.js.map +1 -0
  625. package/dist/vite-plugin/templates/default-ui.ts +432 -0
  626. package/dist/vite-plugin/templates/default.html +206 -0
  627. package/dist/vite-plugin.d.ts +8 -0
  628. package/dist/vite-plugin.d.ts.map +1 -0
  629. package/dist/vite-plugin.js +11 -0
  630. package/dist/vite-plugin.js.map +1 -0
  631. package/package.json +208 -0
@@ -0,0 +1,2301 @@
1
+ import { createLogger } from "@happyvertical/logger";
2
+ import { applyOneToManyChildAccessors } from "./child-accessors.js";
3
+ import { SmrtCollection } from "./collection.js";
4
+ import { applyPendingDecoratorRegistrations } from "./decorators/compatibility.js";
5
+ import { ConfigurationError } from "./errors.js";
6
+ import { getDefaultCompositeSource } from "./manifest/sources/composite.js";
7
+ import { ExplicitPathsManifestSource } from "./manifest/sources/explicit-paths.js";
8
+ import { getNodeBuiltins, loadExternalManifestSyncWithNode, cloneManifestSchemaColumns, discoverCachedManifestSync } from "./manifest/store.js";
9
+ import { resolveCollectionCacheConfig } from "./registry/cache-config.js";
10
+ import { register, registerCollection, registerFromManifest, invalidateInheritanceEntries } from "./registry/class-registration.js";
11
+ import { recordRegistryDiagnostic, getRegistryDiagnostics, clearRegistryDiagnostics, flushRegistryDiagnostics } from "./registry/diagnostics.js";
12
+ import { getEmbeddingConfig, hasEmbeddings, getEmbeddingClasses, getProjectEmbeddingConfig, resolveEmbeddingConfig } from "./registry/embedding-manager.js";
13
+ import { getInheritanceChain, getAllFields, mergeFieldConfigs, getAllMethods } from "./registry/inheritance-resolver.js";
14
+ import { manifestFieldDiffers, createFieldFromManifest, mergeManifestField } from "./registry/manifest-field-merge.js";
15
+ import { getCanonicalClassName, hasClassCaseInsensitive, findClass, getClass, getClassByConstructor, getClassByQualifiedName, getClassInPackage, findClassesByName, resolveType, getClassesByPackage, getClassesByVisibility, getPublicClasses, getAllClasses, getClassNames, getQualifiedClassNames, hasClass } from "./registry/name-resolver.js";
16
+ import { getDependencyGraph, getRelationshipMap } from "./registry/relationship-graph.js";
17
+ import { getSchema, getSchemaDDL, getTableName, getAllSchemas, getAllSchemasAsDefinitions } from "./registry/schema-builder.js";
18
+ import { getClasses, getCollections, getCollectionTableNames, getCollectionCache, getDbInstanceIds, getNextDbId, setNextDbId, getFieldDecorators, getStiSiblingsLoaded, getInheritanceCache, getDiscoveryAttemptCache, verboseLog } from "./registry/shared-state.js";
19
+ import { compileValidators } from "./registry/validator.js";
20
+ import "./utils.js";
21
+ import { LRUCache } from "./utils/lru-cache.js";
22
+ import { isQualifiedName, parseQualifiedName, createQualifiedName } from "./utils/qualified-names.js";
23
+ import { SMRT_COLLECTION_BASE_NAMES, isSmrtCollectionExtendsName } from "./registry/collection-resolution.js";
24
+ import { classnameToTablename, toSnakeCase } from "./utils/naming.js";
25
+ const logger = createLogger({ level: "info" });
26
+ function getManifestLoaderSpecifier() {
27
+ return import.meta.url.endsWith(".ts") ? "./manifest/index.ts" : "./manifest/index.js";
28
+ }
29
+ async function importManifestLoader() {
30
+ return await import(getManifestLoaderSpecifier());
31
+ }
32
+ function getReferenceKindFromFieldOptions(fieldOptions) {
33
+ if (fieldOptions?.__tenancy?.isTenantIdField || fieldOptions?._meta?.__tenancy?.isTenantIdField) {
34
+ return "tenantId";
35
+ }
36
+ if (fieldOptions?.type === "foreignKey") {
37
+ return "foreignKey";
38
+ }
39
+ if (fieldOptions?.type === "crossPackageRef") {
40
+ return "crossPackageRef";
41
+ }
42
+ return void 0;
43
+ }
44
+ function applyManifestFieldColumnMetadata(columns, fieldEntries) {
45
+ if (!fieldEntries) {
46
+ return;
47
+ }
48
+ for (const [fieldName, fieldOptions] of fieldEntries) {
49
+ const sqlType = fieldOptions?.sqlType ?? fieldOptions?._meta?.sqlType;
50
+ const referenceKind = getReferenceKindFromFieldOptions(fieldOptions);
51
+ if (!sqlType && !referenceKind) {
52
+ continue;
53
+ }
54
+ const columnName = toSnakeCase(fieldName);
55
+ const existingColumn = columns[columnName];
56
+ if (!existingColumn) {
57
+ continue;
58
+ }
59
+ columns[columnName] = {
60
+ ...existingColumn,
61
+ ...sqlType ? { type: String(sqlType).toUpperCase() } : {},
62
+ ...referenceKind ? { referenceKind } : {}
63
+ };
64
+ }
65
+ }
66
+ async function discoverInstalledSmrtPackages() {
67
+ const discoverSpecifier = import.meta.url.endsWith(".ts") ? "./manifest/discover-smrt-packages.ts" : "./manifest/discover-smrt-packages.js";
68
+ const { discoverSmrtPackages } = await import(discoverSpecifier);
69
+ return discoverSmrtPackages();
70
+ }
71
+ function resolveManifestByUpwardSearch(builtins, missingPath) {
72
+ const { fs, path } = builtins;
73
+ const fileName = path.basename(missingPath);
74
+ const MAX_LEVELS = 4;
75
+ let dir = path.dirname(missingPath);
76
+ for (let level = 0; level < MAX_LEVELS; level++) {
77
+ const parent = path.dirname(dir);
78
+ if (parent === dir) {
79
+ break;
80
+ }
81
+ const candidate = path.join(parent, fileName);
82
+ if (fs.existsSync(candidate)) {
83
+ return candidate;
84
+ }
85
+ if (fs.existsSync(path.join(parent, "package.json"))) {
86
+ break;
87
+ }
88
+ dir = parent;
89
+ }
90
+ return null;
91
+ }
92
+ class ObjectRegistry {
93
+ /**
94
+ * Get the classes map from globalThis, initializing if needed
95
+ */
96
+ static get classes() {
97
+ return getClasses();
98
+ }
99
+ /**
100
+ * Get the collections map from globalThis, initializing if needed
101
+ */
102
+ static get collections() {
103
+ return getCollections();
104
+ }
105
+ /**
106
+ * Get the collection table names map from globalThis, initializing if needed
107
+ * Maps collection class name -> tableName for getTableName lookups
108
+ */
109
+ static get collectionTableNames() {
110
+ return getCollectionTableNames();
111
+ }
112
+ /**
113
+ * Set the table name for a collection class
114
+ * Used by @smrt() decorator to enable getTableName lookups for collections
115
+ */
116
+ static setCollectionTableName(collectionName, tableName) {
117
+ ObjectRegistry.collectionTableNames.set(collectionName, tableName);
118
+ }
119
+ /**
120
+ * Get the collection cache from globalThis, initializing if needed
121
+ */
122
+ static get collectionCache() {
123
+ return getCollectionCache();
124
+ }
125
+ /**
126
+ * Configure the collection cache size (for testing purposes)
127
+ *
128
+ * Resets the collection cache with a new maximum size.
129
+ * Use this in tests to avoid creating many database files.
130
+ *
131
+ * @param maxSize - Maximum number of collections to cache (system default is 100)
132
+ * @throws Error if maxSize is not a positive finite number
133
+ * @example
134
+ * ```typescript
135
+ * // In test setup, use a small cache to test LRU eviction with fewer DBs
136
+ * ObjectRegistry.configureCollectionCache(5);
137
+ * ```
138
+ */
139
+ static configureCollectionCache(maxSize) {
140
+ if (!Number.isFinite(maxSize) || maxSize <= 0) {
141
+ throw new Error(`maxSize must be a positive number, got: ${maxSize}`);
142
+ }
143
+ globalThis.__smrtRegistryCollectionCache = new LRUCache(maxSize);
144
+ }
145
+ /**
146
+ * WeakMap to assign unique IDs to database instances for cache keys
147
+ * Prevents cache key collisions when different db instances are used
148
+ */
149
+ static get dbInstanceIds() {
150
+ return getDbInstanceIds();
151
+ }
152
+ /**
153
+ * Get/set the next database ID counter
154
+ */
155
+ static get nextDbId() {
156
+ return getNextDbId();
157
+ }
158
+ static set nextDbId(value) {
159
+ setNextDbId(value);
160
+ }
161
+ /**
162
+ * Storage for field decorator metadata (decorator pattern)
163
+ * Maps className → Map<propertyKey, FieldOptions>
164
+ * Used by @field(), @foreignKey(), @oneToMany(), @manyToMany() decorators
165
+ */
166
+ static get fieldDecorators() {
167
+ return getFieldDecorators();
168
+ }
169
+ /**
170
+ * Track collections that have been processed for STI siblings
171
+ * Prevents infinite recursion when loading siblings
172
+ */
173
+ static get stiSiblingsLoaded() {
174
+ return getStiSiblingsLoaded();
175
+ }
176
+ /**
177
+ * Check if a class is already registered (case-insensitive)
178
+ * Returns the canonical name if found, undefined otherwise.
179
+ *
180
+ * Release B (#1133): iteration over `classes` replaces the old eagerly-
181
+ * maintained classNameMap index. Negligible cost at production scale and
182
+ * removes an entire class of cache-sync bugs.
183
+ */
184
+ static getCanonicalClassName(name) {
185
+ return getCanonicalClassName(name);
186
+ }
187
+ /**
188
+ * Check if a class exists by name (case-insensitive)
189
+ */
190
+ static hasClassCaseInsensitive(name) {
191
+ return hasClassCaseInsensitive(name);
192
+ }
193
+ /**
194
+ * Global cache for inheritance chains (shared across all instances)
195
+ * Maps className → full inheritance chain (base to child)
196
+ * Performance optimization: ~100x faster than re-walking prototype chain
197
+ * Cache size is configurable via smrt.inheritance.cacheSize (default: 200)
198
+ */
199
+ static getInheritanceCache() {
200
+ return getInheritanceCache();
201
+ }
202
+ /**
203
+ * Global cache for manifest discovery attempts (Issue #735 optimization)
204
+ * Maps className → boolean (true = found and registered, false = not found)
205
+ * Prevents repeated discoverManifestSync calls for the same class name
206
+ */
207
+ static getDiscoveryAttemptCache() {
208
+ return getDiscoveryAttemptCache();
209
+ }
210
+ /**
211
+ * Register field decorator metadata
212
+ *
213
+ * Called by property decorators (@field, @foreignKey, etc.) to store
214
+ * field configuration metadata. This enables the decorator pattern
215
+ * where field metadata is attached at class definition time.
216
+ *
217
+ * @param className - Name of the class containing the field
218
+ * @param propertyKey - Name of the property being decorated
219
+ * @param options - Field options (type, constraints, etc.)
220
+ * @example
221
+ * ```typescript
222
+ * // Called internally by decorators
223
+ * ObjectRegistry.registerFieldDecorator('Product', 'name', {
224
+ * type: 'text',
225
+ * required: true
226
+ * });
227
+ * ```
228
+ */
229
+ static registerFieldDecorator(className, propertyKey, options) {
230
+ if (!ObjectRegistry.fieldDecorators.has(className)) {
231
+ ObjectRegistry.fieldDecorators.set(className, /* @__PURE__ */ new Map());
232
+ }
233
+ const classDecorators = ObjectRegistry.fieldDecorators.get(className);
234
+ if (!classDecorators) {
235
+ return;
236
+ }
237
+ const existing = classDecorators.get(propertyKey);
238
+ if (existing) {
239
+ classDecorators.set(propertyKey, { ...existing, ...options });
240
+ } else {
241
+ classDecorators.set(propertyKey, options);
242
+ }
243
+ }
244
+ /**
245
+ * Get field decorator metadata for a specific field
246
+ *
247
+ * @param className - Name of the class
248
+ * @param propertyKey - Name of the property
249
+ * @returns Field options or undefined if not decorated
250
+ * @example
251
+ * ```typescript
252
+ * const options = ObjectRegistry.getFieldDecorator('Product', 'name');
253
+ * // { type: 'text', required: true }
254
+ * ```
255
+ */
256
+ static getFieldDecorator(className, propertyKey) {
257
+ return ObjectRegistry.fieldDecorators.get(className)?.get(propertyKey);
258
+ }
259
+ /**
260
+ * Get all field decorator metadata for a class
261
+ *
262
+ * @param className - Name of the class
263
+ * @returns Map of property names to field options
264
+ * @example
265
+ * ```typescript
266
+ * const fields = ObjectRegistry.getFieldDecorators('Product');
267
+ * // Map { 'name' => { type: 'text', required: true }, ... }
268
+ * ```
269
+ */
270
+ static getFieldDecorators(className) {
271
+ return ObjectRegistry.fieldDecorators.get(className) || /* @__PURE__ */ new Map();
272
+ }
273
+ /**
274
+ * Check if a class has any field decorators registered
275
+ *
276
+ * @param className - Name of the class
277
+ * @returns True if the class has field decorators, false otherwise
278
+ * @example
279
+ * ```typescript
280
+ * if (ObjectRegistry.hasFieldDecorators('Product')) {
281
+ * // Class uses decorators - skip legacy field initialization
282
+ * }
283
+ * ```
284
+ */
285
+ static hasFieldDecorators(className) {
286
+ const decorators = ObjectRegistry.fieldDecorators.get(className);
287
+ return decorators !== void 0 && decorators.size > 0;
288
+ }
289
+ /**
290
+ * Register a new SMRT object class with the global registry
291
+ *
292
+ * @param constructor - The class constructor extending SmrtObject
293
+ * @param config - Configuration options for API/CLI/MCP generation
294
+ * @throws {Error} If the class cannot be introspected for field definitions
295
+ * @example
296
+ * ```typescript
297
+ * ObjectRegistry.register(Product, {
298
+ * api: { exclude: ['delete'] },
299
+ * cli: true,
300
+ * mcp: { include: ['list', 'get'] }
301
+ * });
302
+ * ```
303
+ */
304
+ static register(ctor, config = {}) {
305
+ register(ctor, config);
306
+ }
307
+ /**
308
+ * Register a collection class for an object
309
+ *
310
+ * @param objectName - Name of the object class this collection manages
311
+ * @param collectionConstructor - The collection class constructor
312
+ * @example
313
+ * ```typescript
314
+ * ObjectRegistry.registerCollection('Product', ProductCollection);
315
+ * ```
316
+ */
317
+ static registerCollection(objectName, collectionConstructor) {
318
+ registerCollection(objectName, collectionConstructor);
319
+ }
320
+ static registerFromManifest(name, objectDef, packageName) {
321
+ registerFromManifest(name, objectDef, packageName);
322
+ }
323
+ /**
324
+ * Helper method for class lookup with qualified name support.
325
+ *
326
+ * Lookup priority:
327
+ * 1. Direct hit on classes map (works for qualified names as keys)
328
+ * 2. If input contains ':', treat as qualified name — direct only, no fallback
329
+ * 3. classNameMap lookup by simple name (lowercase)
330
+ * - Unambiguous (1 entry) → return it
331
+ * - Ambiguous (>1 entry) → throw descriptive error
332
+ * 4. Case-insensitive iteration fallback (backward compat)
333
+ *
334
+ * @param name - Name of the class to find (simple or qualified)
335
+ * @returns Registered class information or undefined if not found
336
+ * @remarks When a simple name is ambiguous (multiple packages define it),
337
+ * logs a warning and returns the first match. Use qualified names
338
+ * or resolveType() for strict disambiguation.
339
+ * @private
340
+ */
341
+ static findClass(name) {
342
+ return findClass(name);
343
+ }
344
+ // The private `findClassStrict` wrapper that used to live here was removed
345
+ // with the inline inheritance-chain copy (#1378); strict, package-aware
346
+ // resolution now lives solely in registry/inheritance-resolver, which calls
347
+ // the name-resolver helper directly.
348
+ /**
349
+ * Get a registered class by name (case-insensitive)
350
+ *
351
+ * @param name - Name of the registered class
352
+ * @returns Registered class information or undefined if not found
353
+ * @example
354
+ * ```typescript
355
+ * const productInfo = ObjectRegistry.getClass('Product');
356
+ * // Also works with: 'product', 'PRODUCT', etc.
357
+ * if (productInfo) {
358
+ * console.log(productInfo.config.api?.exclude);
359
+ * }
360
+ * ```
361
+ */
362
+ static getClass(name) {
363
+ return getClass(name);
364
+ }
365
+ /**
366
+ * Get a registered class by its constructor reference.
367
+ * This is the most reliable lookup method as it avoids name collision issues
368
+ * that can occur when multiple packages define classes with the same name.
369
+ *
370
+ * Uses a WeakMap index for O(1) lookups.
371
+ *
372
+ * @param ctor - The class constructor to look up
373
+ * @returns Registered class information or undefined if not found
374
+ * @example
375
+ * ```typescript
376
+ * import { Meeting } from '@happyvertical/praeco';
377
+ *
378
+ * const info = ObjectRegistry.getClassByConstructor(Meeting);
379
+ * if (info) {
380
+ * console.log(info.qualifiedName); // '@happyvertical/praeco:Meeting'
381
+ * }
382
+ * ```
383
+ */
384
+ static getClassByConstructor(ctor) {
385
+ return getClassByConstructor(ctor);
386
+ }
387
+ /**
388
+ * Get a registered class by its qualified name.
389
+ * Qualified names are in format "@package/name:ClassName".
390
+ *
391
+ * @param qualifiedName - The fully qualified class name
392
+ * @returns Registered class information or undefined if not found
393
+ * @example
394
+ * ```typescript
395
+ * const product = ObjectRegistry.getClassByQualifiedName('@happyvertical/smrt-products:Product');
396
+ * if (product) {
397
+ * console.log(`Found: ${product.name} from ${product.packageName}`);
398
+ * }
399
+ * ```
400
+ */
401
+ static getClassByQualifiedName(qualifiedName) {
402
+ return getClassByQualifiedName(qualifiedName);
403
+ }
404
+ /**
405
+ * Get a registered class by package name and class name.
406
+ * This is a convenience method for looking up classes by their namespace components.
407
+ *
408
+ * @param packageName - The package name (e.g., "@happyvertical/smrt-products")
409
+ * @param className - The class name (e.g., "Product")
410
+ * @returns Registered class information or undefined if not found
411
+ * @example
412
+ * ```typescript
413
+ * const product = ObjectRegistry.getClassInPackage('@happyvertical/smrt-products', 'Product');
414
+ * ```
415
+ */
416
+ static getClassInPackage(packageName, className) {
417
+ return getClassInPackage(packageName, className);
418
+ }
419
+ /**
420
+ * Find all registered classes with a given simple class name.
421
+ * Useful for detecting collisions or when multiple packages have the same class name.
422
+ *
423
+ * @param className - The simple class name to search for
424
+ * @returns Array of registered classes with matching name
425
+ * @example
426
+ * ```typescript
427
+ * const products = ObjectRegistry.findClassesByName('Product');
428
+ * if (products.length > 1) {
429
+ * console.log(`Found ${products.length} classes named "Product":`);
430
+ * for (const p of products) {
431
+ * console.log(` - ${p.qualifiedName} from ${p.packageName}`);
432
+ * }
433
+ * }
434
+ * ```
435
+ */
436
+ static findClassesByName(className) {
437
+ return findClassesByName(className);
438
+ }
439
+ /**
440
+ * Resolve a short class name to its qualified name.
441
+ * Throws an error if the name is ambiguous (multiple packages define the same class name).
442
+ *
443
+ * @param shortName - The simple class name to resolve (e.g., 'MeetingRecap')
444
+ * @returns The qualified class name (e.g., '@happyvertical/praeco:MeetingRecap')
445
+ * @throws {Error} If no class with that name is registered
446
+ * @throws {Error} If multiple classes with that name exist (ambiguous)
447
+ *
448
+ * @example
449
+ * ```typescript
450
+ * // Unambiguous resolution
451
+ * const qualified = ObjectRegistry.resolveType('MeetingRecap');
452
+ * // Returns: '@happyvertical/praeco:MeetingRecap'
453
+ *
454
+ * // Already qualified names pass through
455
+ * const same = ObjectRegistry.resolveType('@happyvertical/praeco:MeetingRecap');
456
+ * // Returns: '@happyvertical/praeco:MeetingRecap'
457
+ *
458
+ * // Ambiguous names throw
459
+ * ObjectRegistry.resolveType('Event');
460
+ * // Error: "Event" is ambiguous. Found in multiple packages:
461
+ * // - @happyvertical/smrt-events:Event
462
+ * // - @happyvertical/calendar:Event
463
+ * // Use the fully qualified name instead.
464
+ * ```
465
+ */
466
+ static resolveType(shortName) {
467
+ return resolveType(shortName);
468
+ }
469
+ /**
470
+ * Get all registered classes from a specific package.
471
+ *
472
+ * @param packageName - The package name to filter by
473
+ * @returns Map of class names to registered class information
474
+ * @example
475
+ * ```typescript
476
+ * const coreClasses = ObjectRegistry.getClassesByPackage('@happyvertical/smrt-core');
477
+ * for (const [name, info] of coreClasses) {
478
+ * console.log(` ${name}: ${info.qualifiedName}`);
479
+ * }
480
+ * ```
481
+ */
482
+ static getClassesByPackage(packageName) {
483
+ return getClassesByPackage(packageName);
484
+ }
485
+ /**
486
+ * Get all registered classes with a specific visibility level.
487
+ *
488
+ * @param visibility - The visibility level to filter by
489
+ * @returns Map of class names to registered class information
490
+ * @example
491
+ * ```typescript
492
+ * const publicClasses = ObjectRegistry.getClassesByVisibility('public');
493
+ * console.log(`Found ${publicClasses.size} public classes`);
494
+ * ```
495
+ */
496
+ static getClassesByVisibility(visibility) {
497
+ return getClassesByVisibility(visibility);
498
+ }
499
+ /**
500
+ * Get all public registered classes (excludes 'internal' and 'test' visibility).
501
+ * Useful for generating published manifests or public APIs.
502
+ *
503
+ * @returns Map of class names to registered class information
504
+ * @example
505
+ * ```typescript
506
+ * const publicClasses = ObjectRegistry.getPublicClasses();
507
+ * console.log(`Publishing ${publicClasses.size} public classes to manifest`);
508
+ * ```
509
+ */
510
+ static getPublicClasses() {
511
+ return getPublicClasses();
512
+ }
513
+ /**
514
+ * Get all registered classes
515
+ *
516
+ * @returns Map of class names to registered class information
517
+ * @example
518
+ * ```typescript
519
+ * const allClasses = ObjectRegistry.getAllClasses();
520
+ * for (const [name, info] of allClasses) {
521
+ * console.log(`Class: ${name}, Fields: ${info.fields.size}`);
522
+ * }
523
+ * ```
524
+ */
525
+ static getAllClasses() {
526
+ return getAllClasses();
527
+ }
528
+ /**
529
+ * Get class names, deduplicated by simple class name.
530
+ *
531
+ * This is useful for display and backwards compatibility. Use
532
+ * `getQualifiedClassNames()` for schema/bootstrap loops that must preserve
533
+ * cross-package collisions.
534
+ */
535
+ static getClassNames() {
536
+ return getClassNames();
537
+ }
538
+ /**
539
+ * Get one lookup name per registered class, preserving cross-package
540
+ * collisions by preferring qualified class names where available.
541
+ */
542
+ static getQualifiedClassNames() {
543
+ return getQualifiedClassNames();
544
+ }
545
+ /**
546
+ * Try to load and register a class from external SMRT packages
547
+ *
548
+ * This method attempts to auto-discover classes from @happyvertical/smrt-* packages
549
+ * when they're referenced but not yet registered. Solves issue #343 where STI classes
550
+ * from external packages (e.g., Person from smrt-profiles) weren't loading correctly.
551
+ *
552
+ * @param className - Name of the class to load
553
+ * @returns Promise<boolean> - True if successfully loaded and registered, false otherwise
554
+ * @private
555
+ */
556
+ static async tryLoadFromExternalPackage(className) {
557
+ const requestedQualifiedName = isQualifiedName(className) ? parseQualifiedName(className) : null;
558
+ const requestedClassName = requestedQualifiedName?.className || className;
559
+ const requestedPackageName = requestedQualifiedName?.packageName;
560
+ const smrtPackages = requestedPackageName ? [requestedPackageName] : await discoverInstalledSmrtPackages();
561
+ const { loadExternalManifest } = await importManifestLoader();
562
+ verboseLog(
563
+ `[ObjectRegistry] Attempting to auto-load ${className} from ${smrtPackages.length} external packages...`
564
+ );
565
+ const matches = [];
566
+ for (const packageName2 of smrtPackages) {
567
+ const manifest2 = await loadExternalManifest(packageName2);
568
+ if (!manifest2 || !manifest2.objects) {
569
+ continue;
570
+ }
571
+ const lowerClassName = requestedClassName.toLowerCase();
572
+ let objectDef2 = manifest2.objects[lowerClassName] || manifest2.objects[requestedClassName] || (requestedPackageName ? manifest2.objects[`${requestedPackageName}:${requestedClassName}`] : void 0);
573
+ if (!objectDef2) {
574
+ for (const [_key, def] of Object.entries(
575
+ manifest2.objects
576
+ )) {
577
+ if (def.className?.toLowerCase() === lowerClassName || def.className === requestedClassName) {
578
+ objectDef2 = def;
579
+ break;
580
+ }
581
+ }
582
+ }
583
+ if (!objectDef2) {
584
+ continue;
585
+ }
586
+ matches.push({
587
+ manifest: manifest2,
588
+ packageName: manifest2.packageName || packageName2,
589
+ objectDef: objectDef2
590
+ });
591
+ }
592
+ if (matches.length === 0) {
593
+ verboseLog(
594
+ `[ObjectRegistry] ❌ Could not find ${className} in any SMRT package`
595
+ );
596
+ return false;
597
+ }
598
+ if (!requestedPackageName && matches.length > 1) {
599
+ throw new ConfigurationError(
600
+ `Ambiguous class name "${className}" — found in multiple external SMRT packages: ${matches.map((match) => match.packageName).join(", ")}. Preserve package identity or use a qualified class name to disambiguate.`,
601
+ "CONFIG_AMBIGUOUS_CLASS",
602
+ {
603
+ className,
604
+ candidates: matches.map((match) => match.packageName)
605
+ }
606
+ );
607
+ }
608
+ const { manifest, packageName, objectDef } = matches[0];
609
+ verboseLog(
610
+ `[ObjectRegistry] ✅ Found ${className} in ${packageName} manifest`
611
+ );
612
+ ObjectRegistry.registerFromManifest(
613
+ objectDef.className || requestedClassName,
614
+ objectDef,
615
+ manifest.packageName
616
+ );
617
+ const childClassName = objectDef.className || requestedClassName;
618
+ if (objectDef.extends && objectDef.extends !== childClassName) {
619
+ const parentName = objectDef.extends;
620
+ const lowerParentName = parentName.toLowerCase();
621
+ let parentDef = manifest.objects[lowerParentName] || manifest.objects[parentName];
622
+ if (!parentDef) {
623
+ for (const [_key, def] of Object.entries(
624
+ manifest.objects
625
+ )) {
626
+ if (def.className?.toLowerCase() === lowerParentName || def.className === parentName) {
627
+ parentDef = def;
628
+ break;
629
+ }
630
+ }
631
+ }
632
+ if (parentDef && !ObjectRegistry.hasClass(objectDef.extends)) {
633
+ verboseLog(
634
+ `[ObjectRegistry] Also registering parent class ${objectDef.extends} for STI`
635
+ );
636
+ ObjectRegistry.registerFromManifest(
637
+ parentDef.className || objectDef.extends,
638
+ parentDef,
639
+ manifest.packageName
640
+ );
641
+ }
642
+ verboseLog(
643
+ `[ObjectRegistry] Merging inherited fields for ${className}...`
644
+ );
645
+ await ObjectRegistry.getAllFields(requestedClassName);
646
+ const registered = ObjectRegistry.findClass(requestedClassName);
647
+ if (registered?.inheritedFields) {
648
+ verboseLog(
649
+ `[ObjectRegistry] ✅ ${className} now has ${registered.inheritedFields.size} total fields (including inherited)`
650
+ );
651
+ }
652
+ }
653
+ return true;
654
+ }
655
+ /**
656
+ * Load all manifests upfront so inheritance queries are pure lookups.
657
+ *
658
+ * After this method completes, every class across all packages is
659
+ * registered and `getInheritanceChain()` will never need to mutate
660
+ * registry state.
661
+ *
662
+ * @param options - Optional configuration
663
+ * @param options.manifestPaths - Explicit list of manifest.json file paths to load.
664
+ * When omitted the method discovers packages via `loadExternalManifestSync()`
665
+ * for every `@happyvertical` package found in `node_modules`.
666
+ * @returns Summary statistics about the load operation
667
+ *
668
+ * @example
669
+ * ```typescript
670
+ * // At CLI / server startup
671
+ * ObjectRegistry.loadAllManifests();
672
+ * // All classes are now registered — inheritance lookups are side-effect free
673
+ * ```
674
+ *
675
+ * @see https://github.com/happyvertical/smrt/issues/1007
676
+ */
677
+ static loadAllManifests(options) {
678
+ let packagesLoaded = 0;
679
+ let objectsRegistered = 0;
680
+ if (options?.manifestPaths) {
681
+ const source = new ExplicitPathsManifestSource(options.manifestPaths);
682
+ for (const entry of source.entries()) {
683
+ if (!ObjectRegistry.hasClassCaseInsensitive(entry.className)) {
684
+ ObjectRegistry.registerFromManifest(
685
+ entry.className,
686
+ entry.def,
687
+ entry.packageName
688
+ );
689
+ objectsRegistered++;
690
+ }
691
+ }
692
+ packagesLoaded = source.loadedCount;
693
+ } else {
694
+ const packagePrefixes = ["@happyvertical/smrt-"];
695
+ try {
696
+ const builtins = getNodeBuiltins();
697
+ if (!builtins) {
698
+ return { packagesLoaded, objectsRegistered };
699
+ }
700
+ const scopeDir = builtins.path.join(
701
+ process.cwd(),
702
+ "node_modules",
703
+ "@happyvertical"
704
+ );
705
+ if (!builtins.fs.existsSync(scopeDir)) {
706
+ return { packagesLoaded, objectsRegistered };
707
+ }
708
+ const packages = builtins.fs.readdirSync(scopeDir).filter(
709
+ (name) => packagePrefixes.some(
710
+ (prefix) => `@happyvertical/${name}`.startsWith(prefix)
711
+ )
712
+ );
713
+ const seenPackages = /* @__PURE__ */ new Set();
714
+ for (const pkgDir of packages) {
715
+ const packageName = `@happyvertical/${pkgDir}`;
716
+ const manifest = loadExternalManifestSyncWithNode(packageName);
717
+ if (!manifest?.objects) continue;
718
+ seenPackages.add(packageName);
719
+ }
720
+ const composite = getDefaultCompositeSource();
721
+ for (const entry of composite.entries()) {
722
+ if (!entry.packageName || !seenPackages.has(entry.packageName)) {
723
+ continue;
724
+ }
725
+ if (!ObjectRegistry.hasClassCaseInsensitive(entry.className)) {
726
+ ObjectRegistry.registerFromManifest(
727
+ entry.className,
728
+ entry.def,
729
+ entry.packageName
730
+ );
731
+ objectsRegistered++;
732
+ }
733
+ }
734
+ packagesLoaded = seenPackages.size;
735
+ } catch (err) {
736
+ verboseLog(
737
+ `[ObjectRegistry] Auto-discovery of manifests failed: ${err}`
738
+ );
739
+ }
740
+ }
741
+ verboseLog(
742
+ `[ObjectRegistry] loadAllManifests complete: ${packagesLoaded} packages, ${objectsRegistered} objects registered`
743
+ );
744
+ return { packagesLoaded, objectsRegistered };
745
+ }
746
+ /**
747
+ * Register a package's own bundled manifest, called by the package itself at
748
+ * import time to eliminate the consumer-runtime field-drop bug (issue #1132).
749
+ *
750
+ * Packages ship a `dist/manifest.json` next to their compiled entry. A small
751
+ * `__smrt-register__.js` side-effect module imports that file URL and calls
752
+ * this method *before* any `@smrt()` decorator in the package fires, so the
753
+ * decorator's synchronous manifest lookup hits a populated cache instead of
754
+ * registering classes with zero fields.
755
+ *
756
+ * Silently no-ops if the URL can't be read — in dev/test the vitest plugin
757
+ * populates manifests through a different path, and this fallback is expected
758
+ * to miss in those contexts.
759
+ *
760
+ * @param manifestUrl - File URL (or string) pointing to the package's
761
+ * manifest.json. Typical call site:
762
+ * `new URL('./manifest.json', import.meta.url)`
763
+ * @returns Summary with loaded status, package name, and object count
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * // packages/smrt-places/src/__smrt-register__.ts
768
+ * import { ObjectRegistry } from '@happyvertical/smrt-core';
769
+ * ObjectRegistry.registerPackageManifest(
770
+ * new URL('./manifest.json', import.meta.url),
771
+ * );
772
+ * ```
773
+ *
774
+ * @see https://github.com/happyvertical/smrt/issues/1132
775
+ */
776
+ static registerPackageManifest(manifestUrl) {
777
+ const builtins = getNodeBuiltins();
778
+ if (!builtins) {
779
+ return { loaded: false, objectsRegistered: 0 };
780
+ }
781
+ let manifest = null;
782
+ try {
783
+ const urlString = manifestUrl instanceof URL ? manifestUrl.href : manifestUrl;
784
+ let filePath;
785
+ if (manifestUrl instanceof URL) {
786
+ filePath = builtins.url.fileURLToPath(manifestUrl);
787
+ } else if (urlString.startsWith("file:")) {
788
+ filePath = builtins.url.fileURLToPath(urlString);
789
+ } else {
790
+ filePath = urlString;
791
+ }
792
+ if (!builtins.fs.existsSync(filePath)) {
793
+ const recovered = resolveManifestByUpwardSearch(builtins, filePath);
794
+ if (!recovered) {
795
+ recordRegistryDiagnostic(
796
+ "warn",
797
+ "PACKAGE_MANIFEST_NOT_FOUND",
798
+ `Package manifest not found at ${filePath}. Self-registration is a no-op; the vitest plugin may still populate this manifest via its own path.`,
799
+ { manifestUrl: String(manifestUrl), filePath }
800
+ );
801
+ return { loaded: false, objectsRegistered: 0 };
802
+ }
803
+ filePath = recovered;
804
+ }
805
+ const parsed = JSON.parse(
806
+ builtins.fs.readFileSync(filePath, "utf-8")
807
+ );
808
+ if (!parsed?.objects || typeof parsed.objects !== "object") {
809
+ recordRegistryDiagnostic(
810
+ "warn",
811
+ "PACKAGE_MANIFEST_INVALID_SHAPE",
812
+ `Package manifest at ${String(manifestUrl)} is missing an "objects" record`,
813
+ { manifestUrl: String(manifestUrl) }
814
+ );
815
+ return { loaded: false, objectsRegistered: 0 };
816
+ }
817
+ manifest = parsed;
818
+ } catch (error) {
819
+ const errorMessage = error instanceof Error ? error.message : String(error);
820
+ recordRegistryDiagnostic(
821
+ "error",
822
+ "PACKAGE_MANIFEST_READ_FAILED",
823
+ `registerPackageManifest: failed to read manifest at ${String(manifestUrl)}: ${errorMessage}`,
824
+ { manifestUrl: String(manifestUrl), errorMessage }
825
+ );
826
+ verboseLog(
827
+ `[ObjectRegistry] registerPackageManifest: failed to read manifest at ${String(manifestUrl)}: ${errorMessage}`
828
+ );
829
+ return { loaded: false, objectsRegistered: 0 };
830
+ }
831
+ const packageName = manifest.packageName;
832
+ const manifestGlobals = globalThis;
833
+ if (!manifestGlobals.__smrtManifestCache) {
834
+ manifestGlobals.__smrtManifestCache = /* @__PURE__ */ new Map();
835
+ }
836
+ const cacheKey = packageName || String(manifestUrl);
837
+ manifestGlobals.__smrtManifestCache.set(cacheKey, manifest);
838
+ let objectsRegistered = 0;
839
+ for (const [key, def] of Object.entries(manifest.objects)) {
840
+ const objectDef = def;
841
+ const className = objectDef.className || key;
842
+ ObjectRegistry.registerFromManifest(className, objectDef, packageName);
843
+ objectsRegistered++;
844
+ }
845
+ verboseLog(
846
+ `[ObjectRegistry] registerPackageManifest: loaded ${objectsRegistered} objects from ${packageName || String(manifestUrl)}`
847
+ );
848
+ return { loaded: true, packageName, objectsRegistered };
849
+ }
850
+ /**
851
+ * Snapshot of diagnostics collected from registry load paths.
852
+ *
853
+ * Registry paths that previously `console.warn(...); return null` also
854
+ * record a structured diagnostic. Apps can inspect this buffer at startup
855
+ * or from an error route to surface failures that would otherwise be silent.
856
+ *
857
+ * Strict mode is **on by default** since Release C (#1134): severity
858
+ * `'error'` diagnostics throw at record time. Set
859
+ * `SMRT_STRICT_REGISTRY=false` to restore the pre-Release-C permissive
860
+ * behavior where only the diagnostic is recorded and nothing throws.
861
+ *
862
+ * @see https://github.com/happyvertical/smrt/issues/1132
863
+ * @see https://github.com/happyvertical/smrt/issues/1134
864
+ */
865
+ static getDiagnostics() {
866
+ return getRegistryDiagnostics();
867
+ }
868
+ /** Clear the diagnostic buffer. Primarily for tests. */
869
+ static clearDiagnostics() {
870
+ clearRegistryDiagnostics();
871
+ }
872
+ /**
873
+ * Pretty-print the diagnostic buffer via `console.warn` / `console.error`.
874
+ * No-op when the buffer is empty.
875
+ */
876
+ static flushDiagnostics() {
877
+ flushRegistryDiagnostics();
878
+ }
879
+ /**
880
+ * Check if a class is registered (case-insensitive)
881
+ */
882
+ static hasClass(name) {
883
+ return hasClass(name);
884
+ }
885
+ /**
886
+ * Clear all registered classes (mainly for testing)
887
+ */
888
+ static clear() {
889
+ ObjectRegistry.classes.clear();
890
+ ObjectRegistry.collections.clear();
891
+ ObjectRegistry.collectionCache.clear();
892
+ ObjectRegistry.collectionTableNames.clear();
893
+ ObjectRegistry.getInheritanceCache().clear();
894
+ ObjectRegistry.getDiscoveryAttemptCache().clear();
895
+ ObjectRegistry.fieldDecorators.clear();
896
+ ObjectRegistry.stiSiblingsLoaded.clear();
897
+ ObjectRegistry.nextDbId = 1;
898
+ }
899
+ /**
900
+ * Invalidate inheritance cache for a specific class
901
+ *
902
+ * Clears cached inheritance chain and merged fields/methods for the given class.
903
+ * Call this when a class definition changes at runtime (e.g., hot module reload).
904
+ *
905
+ * @param className - The class name to invalidate cache for
906
+ * @example
907
+ * ```typescript
908
+ * // After hot module reload of a parent class
909
+ * ObjectRegistry.invalidateInheritanceCache('BentleyContent');
910
+ * ```
911
+ */
912
+ static invalidateInheritanceCache(className) {
913
+ const registered = ObjectRegistry.findClass(className);
914
+ if (!registered) {
915
+ ObjectRegistry.getInheritanceCache().delete(className);
916
+ return;
917
+ }
918
+ invalidateInheritanceEntries(registered);
919
+ }
920
+ /**
921
+ * Invalidate all inheritance caches
922
+ *
923
+ * Clears all cached inheritance chains and merged fields/methods.
924
+ * Call this when multiple classes change at runtime.
925
+ *
926
+ * @example
927
+ * ```typescript
928
+ * // After hot module reload of multiple classes
929
+ * ObjectRegistry.invalidateAllInheritanceCaches();
930
+ * ```
931
+ */
932
+ static invalidateAllInheritanceCaches() {
933
+ ObjectRegistry.getInheritanceCache().clear();
934
+ ObjectRegistry.getDiscoveryAttemptCache().clear();
935
+ for (const registered of ObjectRegistry.classes.values()) {
936
+ registered.inheritedFields = void 0;
937
+ registered.inheritedMethods = void 0;
938
+ }
939
+ }
940
+ /**
941
+ * Resolve a collection lookup name to the registered object metadata and
942
+ * collection constructor that should back it.
943
+ *
944
+ * Accepts any supported collection identifier:
945
+ * - simple class name (`FactRecord`)
946
+ * - qualified class name (`@pkg:FactRecord`)
947
+ * - explicit collection alias (`fact_records`) when registered
948
+ *
949
+ * Returns a canonical class identity so cache keys remain stable across
950
+ * aliases that refer to the same underlying collection.
951
+ */
952
+ static resolveCollectionRegistration(className) {
953
+ let registered = ObjectRegistry.findClass(className);
954
+ let collectionConstructor = registered?.collectionConstructor;
955
+ if (!collectionConstructor) {
956
+ collectionConstructor = ObjectRegistry.collections.get(className);
957
+ }
958
+ if (!registered && collectionConstructor) {
959
+ const itemClass = collectionConstructor._itemClass;
960
+ if (itemClass) {
961
+ registered = ObjectRegistry.getClassByConstructor(itemClass) || ObjectRegistry.findClass(itemClass.name);
962
+ }
963
+ }
964
+ const canonicalName = registered?.qualifiedName || registered?.name || className;
965
+ return {
966
+ canonicalName,
967
+ registered,
968
+ collectionConstructor
969
+ };
970
+ }
971
+ /**
972
+ * Get or create a cached collection instance (Singleton pattern - Phase 4 optimization)
973
+ *
974
+ * Returns a cached collection if one exists for the given class and options,
975
+ * otherwise creates, initializes, and caches a new instance. This significantly
976
+ * improves performance by avoiding repeated collection initialization.
977
+ *
978
+ * **Performance Impact**: 60-80% reduction in collection initialization overhead
979
+ *
980
+ * **Cache Key Strategy**: Collections are cached based on:
981
+ * - className
982
+ * - persistence configuration (type, url, baseUrl)
983
+ * - db presence (not full config)
984
+ * - ai presence (not full config)
985
+ *
986
+ * Different persistence configurations create separate cached instances.
987
+ *
988
+ * @param className - Name of the object class
989
+ * @param options - Configuration options for the collection
990
+ * @returns Cached or newly created collection instance
991
+ * @throws {Error} If the class is not registered or has no collection
992
+ *
993
+ * @example
994
+ * ```typescript
995
+ * // First call creates and caches the collection
996
+ * const orders1 = await ObjectRegistry.getCollection('Order', {
997
+ * persistence: { type: 'sql', url: 'orders.db' }
998
+ * });
999
+ *
1000
+ * // Subsequent calls return the cached instance (much faster)
1001
+ * const orders2 = await ObjectRegistry.getCollection('Order', {
1002
+ * persistence: { type: 'sql', url: 'orders.db' }
1003
+ * });
1004
+ * console.log(orders1 === orders2); // true (same instance)
1005
+ *
1006
+ * // Different configuration creates new instance
1007
+ * const orders3 = await ObjectRegistry.getCollection('Order', {
1008
+ * persistence: { type: 'sql', url: 'orders-copy.db' }
1009
+ * });
1010
+ * console.log(orders1 === orders3); // false (different config)
1011
+ * ```
1012
+ *
1013
+ * @see {@link https://github.com/happyvertical/sdk/blob/main/packages/core/CLAUDE.md#singleton-collection-management-phase-4|Phase 4 Documentation}
1014
+ */
1015
+ static async getCollection(className, options = {}) {
1016
+ let { canonicalName, registered, collectionConstructor } = ObjectRegistry.resolveCollectionRegistration(className);
1017
+ if (!registered && !collectionConstructor) {
1018
+ const loaded = await ObjectRegistry.tryLoadFromExternalPackage(className);
1019
+ if (loaded) {
1020
+ ({ canonicalName, registered, collectionConstructor } = ObjectRegistry.resolveCollectionRegistration(className));
1021
+ }
1022
+ if (!registered && !collectionConstructor) {
1023
+ throw new Error(
1024
+ `Class ${className} not found in ObjectRegistry. Make sure to register it with @smrt() decorator or ObjectRegistry.register()`
1025
+ );
1026
+ }
1027
+ }
1028
+ let dbId;
1029
+ if (options.db && typeof options.db === "object") {
1030
+ if (!ObjectRegistry.dbInstanceIds.has(options.db)) {
1031
+ ObjectRegistry.dbInstanceIds.set(options.db, ObjectRegistry.nextDbId++);
1032
+ }
1033
+ dbId = ObjectRegistry.dbInstanceIds.get(options.db);
1034
+ }
1035
+ const cacheKey = `${canonicalName}:${JSON.stringify({
1036
+ persistence: options.persistence,
1037
+ db: dbId !== void 0 ? `db:${dbId}` : void 0,
1038
+ ai: options.ai ? "present" : void 0
1039
+ })}`;
1040
+ if (ObjectRegistry.collectionCache.has(cacheKey)) {
1041
+ return ObjectRegistry.collectionCache.get(cacheKey);
1042
+ }
1043
+ if (!collectionConstructor) {
1044
+ if (!registered) {
1045
+ throw new Error(
1046
+ `Collection ${className} is registered without a backing object class, which is not supported.`
1047
+ );
1048
+ }
1049
+ const { SmrtCollection: SmrtCollectionClass } = await import("./collection.js");
1050
+ class DefaultCollection extends SmrtCollectionClass {
1051
+ static _itemClass = registered?.constructor;
1052
+ }
1053
+ collectionConstructor = DefaultCollection;
1054
+ registered.collectionConstructor = DefaultCollection;
1055
+ ObjectRegistry.collections.set(canonicalName, DefaultCollection);
1056
+ }
1057
+ const collection = await collectionConstructor.create(
1058
+ options
1059
+ );
1060
+ ObjectRegistry.collectionCache.set(cacheKey, collection);
1061
+ return collection;
1062
+ }
1063
+ /**
1064
+ * Get field definitions for a registered class.
1065
+ * Supports both qualified names and simple class names.
1066
+ */
1067
+ static getFields(name) {
1068
+ const registered = ObjectRegistry.findClass(name);
1069
+ return registered ? registered.fields : /* @__PURE__ */ new Map();
1070
+ }
1071
+ /**
1072
+ * Get method definitions for a registered class
1073
+ *
1074
+ * Returns method metadata extracted from the manifest during AST scanning.
1075
+ * This enables code generators (CLI, API, MCP) to discover custom methods
1076
+ * and automatically generate corresponding commands/endpoints/tools.
1077
+ *
1078
+ * @param name - Name of the registered class
1079
+ * @returns Map of method names to MethodDefinition objects
1080
+ * @example
1081
+ * ```typescript
1082
+ * const methods = ObjectRegistry.getMethods('Agent');
1083
+ * for (const [name, methodDef] of methods) {
1084
+ * console.log(`Method: ${name}`);
1085
+ * console.log(` Async: ${methodDef.async}`);
1086
+ * console.log(` Public: ${methodDef.isPublic}`);
1087
+ * console.log(` Params: ${methodDef.parameters.map(p => p.name).join(', ')}`);
1088
+ * }
1089
+ * ```
1090
+ */
1091
+ static getMethods(name) {
1092
+ const registered = ObjectRegistry.findClass(name);
1093
+ if (registered) {
1094
+ return registered.methods;
1095
+ }
1096
+ return /* @__PURE__ */ new Map();
1097
+ }
1098
+ static compileValidators(className, fields) {
1099
+ return compileValidators(className, fields);
1100
+ }
1101
+ /**
1102
+ * Ensure manifest is loaded for external package classes
1103
+ *
1104
+ * For classes from external packages, the manifest may not be loaded during
1105
+ * initial registration (which must be synchronous for decorator support).
1106
+ * This method loads the manifest asynchronously when needed.
1107
+ *
1108
+ * @param className - Name of the class to ensure manifest is loaded for
1109
+ * @returns Promise that resolves when manifest is loaded (or already loaded)
1110
+ * @throws {Error} If manifest cannot be found
1111
+ *
1112
+ * @example
1113
+ * ```typescript
1114
+ * // Before using fields from external package
1115
+ * await ObjectRegistry.ensureManifestLoaded('Place');
1116
+ * const fields = ObjectRegistry.getFields('Place'); // Now has fields
1117
+ * ```
1118
+ */
1119
+ static async ensureManifestLoaded(className) {
1120
+ let registered = ObjectRegistry.findClass(className);
1121
+ if (!registered) {
1122
+ const loaded = await ObjectRegistry.tryLoadFromExternalPackage(className);
1123
+ if (loaded) {
1124
+ registered = ObjectRegistry.findClass(className);
1125
+ }
1126
+ }
1127
+ if (!registered) {
1128
+ const isTestEnv = process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof globalThis.describe !== "undefined" || typeof globalThis.it !== "undefined";
1129
+ const testHint = isTestEnv ? `
1130
+
1131
+ ⚠️ Are you using 'smrt test'? Tests require manifest generation.
1132
+ ✅ Use: smrt test
1133
+ ❌ NOT: npx vitest
1134
+ ` : "";
1135
+ throw new Error(
1136
+ `Class '${className}' is not registered. Ensure the class is decorated with @smrt() before using it.` + testHint
1137
+ );
1138
+ }
1139
+ const existingFieldCount = registered.fields.size;
1140
+ const { discoverManifestEntry } = await importManifestLoader();
1141
+ const manifestEntry = await discoverManifestEntry(
1142
+ registered.constructor,
1143
+ className
1144
+ );
1145
+ if (!manifestEntry) {
1146
+ if (!registered.packageName || !registered.qualifiedName) {
1147
+ const loaded = await ObjectRegistry.tryLoadFromExternalPackage(className);
1148
+ if (loaded) {
1149
+ ObjectRegistry.invalidateInheritanceCache(className);
1150
+ }
1151
+ }
1152
+ return;
1153
+ }
1154
+ if (manifestEntry?.fields) {
1155
+ const manifestFieldCount = Object.keys(manifestEntry.fields).length;
1156
+ let didHydrate = false;
1157
+ const needsFieldHydration = Object.entries(manifestEntry.fields).some(
1158
+ ([fieldName, fieldDef]) => {
1159
+ const existingField = registered.fields.get(fieldName);
1160
+ if (!existingField) {
1161
+ return true;
1162
+ }
1163
+ return manifestFieldDiffers(existingField, fieldDef);
1164
+ }
1165
+ );
1166
+ const needsMethodHydration = !!manifestEntry.methods && Object.entries(manifestEntry.methods).some(
1167
+ ([methodName, methodDef]) => {
1168
+ return JSON.stringify(registered.methods.get(methodName)) !== JSON.stringify(methodDef);
1169
+ }
1170
+ );
1171
+ const needsRegistrationHydration = !!manifestEntry.packageName && registered.packageName !== manifestEntry.packageName || !!manifestEntry.extends && registered.extends !== manifestEntry.extends;
1172
+ if (existingFieldCount > 0 && existingFieldCount >= manifestFieldCount && !needsFieldHydration && !needsMethodHydration && !needsRegistrationHydration) {
1173
+ return;
1174
+ }
1175
+ for (const [fieldName, fieldDef] of Object.entries(
1176
+ manifestEntry.fields
1177
+ )) {
1178
+ const existingField = registered.fields.get(fieldName);
1179
+ if (!existingField) {
1180
+ registered.fields.set(fieldName, createFieldFromManifest(fieldDef));
1181
+ didHydrate = true;
1182
+ continue;
1183
+ }
1184
+ if (manifestFieldDiffers(existingField, fieldDef)) {
1185
+ registered.fields.set(
1186
+ fieldName,
1187
+ mergeManifestField(existingField, fieldDef)
1188
+ );
1189
+ didHydrate = true;
1190
+ }
1191
+ }
1192
+ if (manifestEntry.methods) {
1193
+ for (const [methodName, methodDef] of Object.entries(
1194
+ manifestEntry.methods
1195
+ )) {
1196
+ registered.methods.set(methodName, methodDef);
1197
+ }
1198
+ didHydrate = true;
1199
+ }
1200
+ if (manifestEntry.schema) {
1201
+ const columns = cloneManifestSchemaColumns(
1202
+ manifestEntry.schema.columns
1203
+ );
1204
+ applyManifestFieldColumnMetadata(columns, registered.fields.entries());
1205
+ registered.schema = {
1206
+ ddl: manifestEntry.schema.ddl,
1207
+ tableName: manifestEntry.schema.tableName || registered.schema?.tableName || classnameToTablename(registered.name),
1208
+ columns,
1209
+ indexes: manifestEntry.schema.indexes?.map((indexDef) => ({
1210
+ ...indexDef,
1211
+ columns: [...indexDef.columns || []]
1212
+ })) || [],
1213
+ triggers: [],
1214
+ foreignKeys: [],
1215
+ dependencies: [],
1216
+ version: manifestEntry.schema.version || "",
1217
+ packageName: manifestEntry.packageName,
1218
+ baseClass: registered.schema?.baseClass
1219
+ };
1220
+ didHydrate = true;
1221
+ }
1222
+ if (manifestEntry.packageName) {
1223
+ registered.packageName = manifestEntry.packageName;
1224
+ registered.qualifiedName = createQualifiedName(
1225
+ manifestEntry.packageName,
1226
+ registered.name
1227
+ );
1228
+ didHydrate = true;
1229
+ }
1230
+ if (manifestEntry.extends) {
1231
+ registered.extends = manifestEntry.extends;
1232
+ didHydrate = true;
1233
+ }
1234
+ if (didHydrate) {
1235
+ ObjectRegistry.invalidateInheritanceCache(className);
1236
+ }
1237
+ verboseLog(
1238
+ `📦 Loaded manifest for external package class: ${className} (${registered.fields.size} fields, ${registered.methods.size} methods)`
1239
+ );
1240
+ } else {
1241
+ throw new Error(
1242
+ `Cannot find manifest for class '${className}'.
1243
+
1244
+ SMRT classes require a manifest generated at build time by the AST scanner.
1245
+
1246
+ If this is an external package class, verify:
1247
+ 1. Package exports manifest: Check package.json has:
1248
+ "exports": { "./manifest": "./dist/manifest.json" }
1249
+ 2. Package is built: Run npm run build in the package
1250
+ 3. Manifest exists: Confirm dist/manifest.json exists
1251
+
1252
+ See: https://github.com/happyvertical/smrt/issues/131`
1253
+ );
1254
+ }
1255
+ }
1256
+ /**
1257
+ * Get configuration for a registered class
1258
+ */
1259
+ static getConfig(name) {
1260
+ const registered = ObjectRegistry.findClass(name);
1261
+ return registered ? registered.config : {};
1262
+ }
1263
+ /**
1264
+ * Get cached schema definition for a registered class
1265
+ */
1266
+ static getSchema(name) {
1267
+ return getSchema(name);
1268
+ }
1269
+ /**
1270
+ * Get SQL DDL statement for a registered class
1271
+ */
1272
+ static getSchemaDDL(name) {
1273
+ return getSchemaDDL(name);
1274
+ }
1275
+ /**
1276
+ * Get table name for a registered class
1277
+ */
1278
+ static getTableName(name) {
1279
+ return getTableName(name);
1280
+ }
1281
+ /**
1282
+ * Get all pre-generated schemas for passing to database adapters
1283
+ */
1284
+ static getAllSchemas() {
1285
+ return getAllSchemas();
1286
+ }
1287
+ /**
1288
+ * Get all registered schemas as SchemaDefinition objects
1289
+ */
1290
+ static getAllSchemasAsDefinitions() {
1291
+ return getAllSchemasAsDefinitions();
1292
+ }
1293
+ /**
1294
+ * Get compiled validation functions for a registered class
1295
+ *
1296
+ * Returns pre-compiled validation functions that can be executed
1297
+ * at runtime for efficient validation without repeated setup.
1298
+ *
1299
+ * @param name - Name of the registered class
1300
+ * @returns Array of validation functions or undefined if not found
1301
+ * @example
1302
+ * ```typescript
1303
+ * const validators = ObjectRegistry.getValidators('Product');
1304
+ * for (const validator of validators || []) {
1305
+ * const error = await validator(productInstance);
1306
+ * if (error) console.error(error);
1307
+ * }
1308
+ * ```
1309
+ */
1310
+ static getValidators(name) {
1311
+ const registered = ObjectRegistry.findClass(name);
1312
+ return registered?.validators;
1313
+ }
1314
+ /**
1315
+ * Get pre-computed validation rules for a registered class
1316
+ *
1317
+ * Returns serializable validation rules that can be evaluated at runtime
1318
+ * without needing pre-compiled validator closures. This significantly
1319
+ * reduces CLI startup time for projects with many SMRT objects.
1320
+ *
1321
+ * @param name - Name of the registered class
1322
+ * @returns Array of validation rules or undefined if not found
1323
+ * @see https://github.com/happyvertical/smrt/issues/782
1324
+ */
1325
+ static getValidationRules(name) {
1326
+ const registered = ObjectRegistry.findClass(name);
1327
+ return registered?.validationRules;
1328
+ }
1329
+ /**
1330
+ * Validate an instance using pre-computed validation rules
1331
+ *
1332
+ * This method evaluates validation rules without creating closures,
1333
+ * providing faster validation than compiled validator functions.
1334
+ *
1335
+ * @param instance - The object instance to validate
1336
+ * @param rules - Array of validation rules to apply
1337
+ * @param className - Name of the class for error messages
1338
+ * @returns Array of validation errors (empty if valid)
1339
+ * @see https://github.com/happyvertical/smrt/issues/782
1340
+ */
1341
+ static async validateWithRules(instance, rules, className) {
1342
+ const { ValidationError } = await import("./errors.js");
1343
+ const errors = [];
1344
+ for (const rule of rules) {
1345
+ const value = instance[rule.field];
1346
+ switch (rule.rule) {
1347
+ case "required":
1348
+ if (value === null || value === void 0 || value === "") {
1349
+ errors.push(ValidationError.requiredField(rule.field, className));
1350
+ }
1351
+ break;
1352
+ case "min":
1353
+ if (value !== null && value !== void 0 && value < rule.value) {
1354
+ errors.push(
1355
+ ValidationError.rangeError(
1356
+ rule.field,
1357
+ value,
1358
+ rule.value,
1359
+ void 0
1360
+ )
1361
+ );
1362
+ }
1363
+ break;
1364
+ case "max":
1365
+ if (value !== null && value !== void 0 && value > rule.value) {
1366
+ errors.push(
1367
+ ValidationError.rangeError(
1368
+ rule.field,
1369
+ value,
1370
+ void 0,
1371
+ rule.value
1372
+ )
1373
+ );
1374
+ }
1375
+ break;
1376
+ case "minLength":
1377
+ if (value && typeof value === "string" && value.length < rule.value) {
1378
+ errors.push(
1379
+ ValidationError.invalidValue(
1380
+ rule.field,
1381
+ value,
1382
+ `string with minimum length ${rule.value}`
1383
+ )
1384
+ );
1385
+ }
1386
+ break;
1387
+ case "maxLength":
1388
+ if (value && typeof value === "string" && value.length > rule.value) {
1389
+ errors.push(
1390
+ ValidationError.invalidValue(
1391
+ rule.field,
1392
+ value,
1393
+ `string with maximum length ${rule.value}`
1394
+ )
1395
+ );
1396
+ }
1397
+ break;
1398
+ case "pattern":
1399
+ if (value && typeof value === "string") {
1400
+ const regex = new RegExp(rule.value);
1401
+ if (!regex.test(value)) {
1402
+ errors.push(
1403
+ ValidationError.invalidValue(
1404
+ rule.field,
1405
+ value,
1406
+ `string matching pattern ${rule.value}`
1407
+ )
1408
+ );
1409
+ }
1410
+ }
1411
+ break;
1412
+ }
1413
+ }
1414
+ return errors;
1415
+ }
1416
+ /**
1417
+ * Build dependency graph from foreignKey relationships
1418
+ *
1419
+ * Returns a map where keys are class names and values are arrays
1420
+ * of class names that the key depends on (via foreignKey fields).
1421
+ *
1422
+ * @returns Map of class name to array of dependency class names
1423
+ * @example
1424
+ * ```typescript
1425
+ * const deps = ObjectRegistry.getDependencyGraph();
1426
+ * // { 'Order': ['Customer', 'Product'], 'Customer': [], 'Product': ['Category'] }
1427
+ * ```
1428
+ */
1429
+ static getDependencyGraph() {
1430
+ return getDependencyGraph();
1431
+ }
1432
+ /**
1433
+ * Get initialization order for classes based on dependency graph
1434
+ *
1435
+ * Uses topological sort to ensure that classes are initialized in
1436
+ * an order that respects foreignKey dependencies (dependencies first).
1437
+ *
1438
+ * Foreign-key cycles (e.g. smrt-chat's ChatMessage.threadId -> ChatThread
1439
+ * and ChatThread.rootMessageId -> ChatMessage) are BROKEN rather than
1440
+ * treated as a fatal error: when a back-edge is encountered the recursion
1441
+ * stops there, so every class still appears in the returned order. SMRT does
1442
+ * not emit real DB `FOREIGN KEY` constraints in its generated CREATE TABLE
1443
+ * DDL, so a table can be created before its cyclic reference target exists —
1444
+ * the reference is satisfied once both tables are present. This mirrors the
1445
+ * standard RDBMS approach (create tables first, wire cyclic references
1446
+ * afterward) and matches SchemaManager.sortByDependencies, which already
1447
+ * tolerates cycles. See issue #1333.
1448
+ *
1449
+ * @returns Array of class names in initialization order. Every registered
1450
+ * class appears exactly once; cycle back-edges are dropped from the
1451
+ * ordering constraints.
1452
+ * @example
1453
+ * ```typescript
1454
+ * const order = ObjectRegistry.getInitializationOrder();
1455
+ * // ['Category', 'Product', 'Customer', 'Order']
1456
+ * // Tables are created in this order to avoid foreign key errors
1457
+ * ```
1458
+ */
1459
+ static getInitializationOrder() {
1460
+ const graph = ObjectRegistry.getDependencyGraph();
1461
+ const visited = /* @__PURE__ */ new Set();
1462
+ const visiting = /* @__PURE__ */ new Set();
1463
+ const order = [];
1464
+ const cycleMembers = /* @__PURE__ */ new Set();
1465
+ function visit(className) {
1466
+ if (visiting.has(className)) {
1467
+ cycleMembers.add(className);
1468
+ return;
1469
+ }
1470
+ if (visited.has(className)) {
1471
+ return;
1472
+ }
1473
+ visiting.add(className);
1474
+ const dependencies = graph.get(className) || [];
1475
+ for (const dep of dependencies) {
1476
+ visit(dep);
1477
+ }
1478
+ visiting.delete(className);
1479
+ visited.add(className);
1480
+ order.push(className);
1481
+ }
1482
+ for (const className of graph.keys()) {
1483
+ if (!visited.has(className)) {
1484
+ visit(className);
1485
+ }
1486
+ }
1487
+ if (cycleMembers.size > 0) {
1488
+ logger.warn(
1489
+ `[ObjectRegistry] Foreign-key cycle(s) detected and broken for ordering: ${[
1490
+ ...cycleMembers
1491
+ ].join(", ")}. Tables are created without strict cyclic ordering; SMRT does not emit DB-level FOREIGN KEY constraints, so this is safe.`
1492
+ );
1493
+ }
1494
+ return order;
1495
+ }
1496
+ /**
1497
+ * Build comprehensive relationship map from all field types
1498
+ *
1499
+ * Returns a map containing all relationships (foreignKey, oneToMany, manyToMany)
1500
+ * discovered in registered classes. This enables runtime relationship traversal
1501
+ * and eager/lazy loading of related objects.
1502
+ *
1503
+ * @returns Map of class name to array of relationship metadata
1504
+ * @example
1505
+ * ```typescript
1506
+ * const relationships = ObjectRegistry.getRelationshipMap();
1507
+ * // {
1508
+ * // 'Order': [
1509
+ * // { sourceClass: 'Order', fieldName: 'customerId', targetClass: 'Customer',
1510
+ * // type: 'foreignKey', options: { onDelete: 'restrict' } }
1511
+ * // ],
1512
+ * // 'Customer': [
1513
+ * // { sourceClass: 'Customer', fieldName: 'orders', targetClass: 'Order',
1514
+ * // type: 'oneToMany', options: {} }
1515
+ * // ]
1516
+ * // }
1517
+ * ```
1518
+ */
1519
+ static getRelationshipMap() {
1520
+ return getRelationshipMap();
1521
+ }
1522
+ /**
1523
+ * Get relationships for a specific class
1524
+ *
1525
+ * @param className - Name of the class to get relationships for
1526
+ * @returns Array of relationship metadata for the class
1527
+ * @example
1528
+ * ```typescript
1529
+ * const orderRelationships = ObjectRegistry.getRelationships('Order');
1530
+ * // [{ sourceClass: 'Order', fieldName: 'customerId', ... }]
1531
+ * ```
1532
+ */
1533
+ static getRelationships(className) {
1534
+ return ObjectRegistry.getRelationshipMap().get(className) || [];
1535
+ }
1536
+ /**
1537
+ * Get full inheritance chain for a class
1538
+ *
1539
+ * Returns array of registered ancestor class names from the oldest
1540
+ * registered ancestor down to the input class. Framework base classes
1541
+ * (`SmrtObject`, `SmrtClass`, `SmrtCollection`) are **NOT** included
1542
+ * because they are never registered — the walk terminates one step
1543
+ * before them.
1544
+ *
1545
+ * Chain entries are **qualified names** (`@package/name:ClassName`)
1546
+ * whenever the corresponding registration has one — i.e. for every
1547
+ * class loaded via a manifest or `@smrt()` decorator with a package
1548
+ * context. Classes registered without a package (some tests) fall
1549
+ * back to their simple name.
1550
+ *
1551
+ * Results are cached globally for performance (~100x faster than re-walking).
1552
+ *
1553
+ * @param className - Name of the registered class (simple or qualified)
1554
+ * @returns Array of class names from oldest registered ancestor to
1555
+ * the input class, or empty array if not found
1556
+ * @example
1557
+ * ```typescript
1558
+ * const chain = ObjectRegistry.getInheritanceChain(
1559
+ * '@happyvertical/smrt-content:BentleyContent',
1560
+ * );
1561
+ * // [
1562
+ * // '@happyvertical/smrt-content:Content',
1563
+ * // '@happyvertical/smrt-content:PraecoContent',
1564
+ * // '@happyvertical/smrt-content:BentleyContent',
1565
+ * // ]
1566
+ * ```
1567
+ */
1568
+ static getInheritanceChain(className) {
1569
+ return getInheritanceChain(className);
1570
+ }
1571
+ /**
1572
+ * Get all fields including inherited ones from parent classes
1573
+ *
1574
+ * **Hybrid approach (v0.17+):**
1575
+ * - External packages: Use build-time merged fields from manifests
1576
+ * - Local classes: Use runtime merging by walking inheritance chain
1577
+ *
1578
+ * @param className - Name of the registered class
1579
+ * @returns Map of all fields (including inherited)
1580
+ */
1581
+ static async getAllFields(className) {
1582
+ return getAllFields(className);
1583
+ }
1584
+ /**
1585
+ * Merge field configurations from parent and child.
1586
+ *
1587
+ * Thin wrapper around the single shared implementation in
1588
+ * registry/inheritance-resolver (#1378). The previous inline copy here had
1589
+ * drifted from the module; both paths now run the same code. Kept as a
1590
+ * private static so existing reach-in tests (issue #841 field-merge coverage)
1591
+ * still resolve it.
1592
+ *
1593
+ * @param parentField - Field config from parent class
1594
+ * @param childField - Field config from child class
1595
+ * @param fieldName - Name of the field (for warning messages)
1596
+ * @returns Merged field configuration
1597
+ */
1598
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: reached in by issue #841 field-merge tests via `(ObjectRegistry as any).mergeFieldConfigs`; kept as the registry-side surface delegating to the shared resolver impl.
1599
+ static mergeFieldConfigs(parentField, childField, fieldName) {
1600
+ return mergeFieldConfigs(parentField, childField, fieldName);
1601
+ }
1602
+ /**
1603
+ * Get all methods including inherited ones from parent classes
1604
+ *
1605
+ * Walks the full inheritance chain and merges methods:
1606
+ * - Parent methods are added first
1607
+ * - Child methods override parent methods (no config merging for methods)
1608
+ *
1609
+ * Results are cached per-class for performance.
1610
+ *
1611
+ * **Note:** This is an async method that ensures manifests are loaded for external package classes.
1612
+ *
1613
+ * @param className - Name of the registered class
1614
+ * @returns Promise resolving to Map of all methods (own + inherited)
1615
+ * @example
1616
+ * ```typescript
1617
+ * // Given: Content → PraecoContent → BentleyContent
1618
+ * const allMethods = await ObjectRegistry.getAllMethods('BentleyContent');
1619
+ * // Includes: generateSummary() (from PraecoContent) + analyzeLocal() (from BentleyContent)
1620
+ * ```
1621
+ */
1622
+ static async getAllMethods(className) {
1623
+ return getAllMethods(className);
1624
+ }
1625
+ /**
1626
+ * Get complete metadata for a single object (convenience method)
1627
+ *
1628
+ * Returns all available metadata for an object in a single call, including:
1629
+ * - Class information
1630
+ * - Field definitions
1631
+ * - Configuration
1632
+ * - Schema definition
1633
+ * - Validators
1634
+ * - Relationships
1635
+ * - Tools (AI-callable methods)
1636
+ *
1637
+ * This is a convenience method that aggregates multiple registry queries
1638
+ * into a single comprehensive metadata object.
1639
+ *
1640
+ * @param className - Name of the class to get metadata for
1641
+ * @returns Complete metadata object or null if class not found
1642
+ * @example
1643
+ * ```typescript
1644
+ * const productMeta = ObjectRegistry.getObjectMetadata('Product');
1645
+ * if (productMeta) {
1646
+ * console.log('Name:', productMeta.name);
1647
+ * console.log('Table:', productMeta.schema.tableName);
1648
+ * console.log('Fields:', productMeta.fields.size);
1649
+ * console.log('API config:', productMeta.config.api);
1650
+ * console.log('Relationships:', productMeta.relationships.length);
1651
+ * }
1652
+ * ```
1653
+ */
1654
+ static getObjectMetadata(className) {
1655
+ const registered = ObjectRegistry.findClass(className);
1656
+ if (!registered) {
1657
+ return null;
1658
+ }
1659
+ return {
1660
+ name: registered.name,
1661
+ constructor: registered.constructor,
1662
+ collectionConstructor: registered.collectionConstructor,
1663
+ config: registered.config,
1664
+ fields: new Map(registered.fields),
1665
+ // Return copy to prevent mutations
1666
+ methods: new Map(registered.methods),
1667
+ // Return copy to prevent mutations
1668
+ schema: registered.schema,
1669
+ validators: registered.validators || [],
1670
+ relationships: ObjectRegistry.getRelationships(className),
1671
+ inverseRelationships: ObjectRegistry.getInverseRelationships(className),
1672
+ tools: registered.tools
1673
+ };
1674
+ }
1675
+ /**
1676
+ * Get metadata for all registered objects (convenience method)
1677
+ *
1678
+ * Returns comprehensive metadata for every registered object, combining
1679
+ * multiple registry queries into a single convenient data structure.
1680
+ *
1681
+ * This is particularly useful for:
1682
+ * - Admin dashboards showing all objects
1683
+ * - Documentation generation
1684
+ * - Schema visualization
1685
+ * - Debugging and introspection
1686
+ *
1687
+ * @returns Array of complete metadata objects for all registered classes
1688
+ * @example
1689
+ * ```typescript
1690
+ * const allMetadata = ObjectRegistry.getAllObjectMetadata();
1691
+ *
1692
+ * // Generate admin dashboard
1693
+ * for (const meta of allMetadata) {
1694
+ * console.log(`${meta.name}:`);
1695
+ * console.log(` Table: ${meta.schema?.tableName}`);
1696
+ * console.log(` Fields: ${meta.fields.size}`);
1697
+ * console.log(` API: ${meta.config.api ? 'enabled' : 'disabled'}`);
1698
+ * console.log(` Relationships: ${meta.relationships.length}`);
1699
+ * }
1700
+ *
1701
+ * // Generate schema documentation
1702
+ * const schemaDoc = allMetadata.map(meta => ({
1703
+ * name: meta.name,
1704
+ * table: meta.schema?.tableName,
1705
+ * fields: Array.from(meta.fields.entries()).map(([name, field]) => ({
1706
+ * name,
1707
+ * type: field.type,
1708
+ * required: field._meta?.required || false
1709
+ * })),
1710
+ * relationships: meta.relationships.map(rel => ({
1711
+ * field: rel.fieldName,
1712
+ * target: rel.targetClass,
1713
+ * type: rel.type
1714
+ * }))
1715
+ * }));
1716
+ * ```
1717
+ */
1718
+ static getAllObjectMetadata() {
1719
+ const allMetadata = [];
1720
+ for (const [_key, entry] of ObjectRegistry.classes) {
1721
+ const metadata = ObjectRegistry.getObjectMetadata(entry.name || _key);
1722
+ if (metadata) {
1723
+ allMetadata.push(metadata);
1724
+ }
1725
+ }
1726
+ return allMetadata;
1727
+ }
1728
+ /**
1729
+ * Get inverse relationships (relationships where this class is the target)
1730
+ *
1731
+ * @param className - Name of the class to find inverse relationships for
1732
+ * @returns Array of relationship metadata where this class is the target
1733
+ * @example
1734
+ * ```typescript
1735
+ * const customerInverseRels = ObjectRegistry.getInverseRelationships('Customer');
1736
+ * // [{ sourceClass: 'Order', fieldName: 'customerId', targetClass: 'Customer', ... }]
1737
+ * ```
1738
+ */
1739
+ static getInverseRelationships(className) {
1740
+ const allRelationships = ObjectRegistry.getRelationshipMap();
1741
+ const inverseRelationships = [];
1742
+ for (const [_sourceClass, relationships] of allRelationships) {
1743
+ for (const rel of relationships) {
1744
+ if (rel.targetClass === className) {
1745
+ inverseRelationships.push(rel);
1746
+ }
1747
+ }
1748
+ }
1749
+ return inverseRelationships;
1750
+ }
1751
+ /**
1752
+ * Names by which an instance of `className` can be referenced by an inverse
1753
+ * foreign key: its own (simple) class name plus every registered ancestor in
1754
+ * its inheritance chain.
1755
+ *
1756
+ * Used by oneToMany resolution so an STI subclass can resolve a relationship
1757
+ * declared on its base — the inverse `@foreignKey` is declared against the
1758
+ * base class name, while the runtime instance may be a subclass.
1759
+ *
1760
+ * @param className - Simple or qualified class name
1761
+ * @returns Set of names (simple and, where available, qualified) the
1762
+ * instance is assignable to
1763
+ */
1764
+ static getSelfReferableNames(className) {
1765
+ const names = /* @__PURE__ */ new Set([className]);
1766
+ for (const ancestor of ObjectRegistry.getInheritanceChain(className)) {
1767
+ names.add(ancestor);
1768
+ const simple = ObjectRegistry.getClass(ancestor)?.name;
1769
+ if (simple) {
1770
+ names.add(simple);
1771
+ }
1772
+ }
1773
+ return names;
1774
+ }
1775
+ /**
1776
+ * Inverse relationships targeting `className` OR any (STI) ancestor it
1777
+ * inherits from.
1778
+ *
1779
+ * `getInverseRelationships` matches the target class name exactly. This
1780
+ * variant also matches inverse foreign keys declared against an ancestor,
1781
+ * so an STI subclass instance can resolve a `@oneToMany` declared on its
1782
+ * base — whose inverse `@foreignKey` points at the base class name.
1783
+ *
1784
+ * @param className - Name of the class to find inverse relationships for
1785
+ * @returns Relationship metadata whose target is the class or one of its
1786
+ * registered ancestors
1787
+ */
1788
+ static getInverseRelationshipsForSelf(className) {
1789
+ const names = ObjectRegistry.getSelfReferableNames(className);
1790
+ const result = [];
1791
+ for (const [, relationships] of ObjectRegistry.getRelationshipMap()) {
1792
+ for (const rel of relationships) {
1793
+ if (names.has(rel.targetClass)) {
1794
+ result.push(rel);
1795
+ }
1796
+ }
1797
+ }
1798
+ return result;
1799
+ }
1800
+ /**
1801
+ * Get table inheritance strategy for a class
1802
+ *
1803
+ * Returns the table strategy (CTI or STI) for a class, with automatic
1804
+ * inheritance from parent classes. If not explicitly configured,
1805
+ * walks up the inheritance chain to find the strategy.
1806
+ *
1807
+ * **Strategy Inheritance:**
1808
+ * - Set once on base class, children inherit automatically
1809
+ * - Children can explicitly override (not recommended)
1810
+ * - Default is 'cti' if not found in hierarchy
1811
+ *
1812
+ * @param className - Name of the class to get strategy for
1813
+ * @returns 'cti' (Class Table Inheritance) or 'sti' (Single Table Inheritance)
1814
+ * @example
1815
+ * ```typescript
1816
+ * @smrt({ tableStrategy: 'sti' })
1817
+ * class Event extends SmrtObject { }
1818
+ *
1819
+ * @smrt() // Inherits 'sti'
1820
+ * class Meeting extends Event { }
1821
+ *
1822
+ * ObjectRegistry.getTableStrategy('Meeting'); // 'sti'
1823
+ * ObjectRegistry.getTableStrategy('Event'); // 'sti'
1824
+ * ```
1825
+ */
1826
+ static getTableStrategy(className) {
1827
+ const registered = ObjectRegistry.findClass(className);
1828
+ if (!registered) {
1829
+ return "cti";
1830
+ }
1831
+ if (registered.config?.tableStrategy) {
1832
+ return registered.config.tableStrategy;
1833
+ }
1834
+ const chain = ObjectRegistry.getInheritanceChain(className);
1835
+ for (const ancestorName of chain) {
1836
+ const ancestor = ObjectRegistry.findClass(ancestorName);
1837
+ if (ancestor?.config?.tableStrategy) {
1838
+ return ancestor.config.tableStrategy;
1839
+ }
1840
+ }
1841
+ return "cti";
1842
+ }
1843
+ /**
1844
+ * Get the conflict columns for UPSERT operations on a class
1845
+ *
1846
+ * Returns custom conflict columns if specified, otherwise defaults based on
1847
+ * table strategy:
1848
+ * - CTI: ['slug', 'context']
1849
+ * - STI: ['slug', 'context', '_meta_type']
1850
+ *
1851
+ * STI subclasses share a table, so the discriminator participates in
1852
+ * identity — two subtypes can coexist with the same (slug, context). The
1853
+ * matching unique constraint on `(slug, context, _meta_type)` must exist
1854
+ * in the live schema; if a deployment carries a stale 2-column unique
1855
+ * instead, run `smrt db:migrate` to repair it (see issue #1165).
1856
+ *
1857
+ * @param className - Name of the class to get conflict columns for
1858
+ * @returns Array of column names to use for conflict detection
1859
+ *
1860
+ * @example
1861
+ * ```typescript
1862
+ * // Junction table with custom conflict columns
1863
+ * @smrt({ conflictColumns: ['event_id', 'profile_id'] })
1864
+ * class EventParticipant extends SmrtObject {}
1865
+ *
1866
+ * ObjectRegistry.getConflictColumns('EventParticipant');
1867
+ * // Returns: ['event_id', 'profile_id']
1868
+ * ```
1869
+ */
1870
+ static getConflictColumns(className) {
1871
+ const registered = ObjectRegistry.findClass(className);
1872
+ if (!registered) {
1873
+ return ["slug", "context"];
1874
+ }
1875
+ if (registered.config?.conflictColumns) {
1876
+ return registered.config.conflictColumns;
1877
+ }
1878
+ const tableStrategy = ObjectRegistry.getTableStrategy(className);
1879
+ return tableStrategy === "sti" ? ["slug", "context", "_meta_type"] : ["slug", "context"];
1880
+ }
1881
+ /**
1882
+ * Get the tenant scoping configuration for a class (Issue #688)
1883
+ *
1884
+ * Returns the normalized tenant scoping configuration if the class
1885
+ * was registered with `tenantScoped: true` or a tenantScoped config object.
1886
+ *
1887
+ * @param className - Name of the class to check
1888
+ * @returns Tenant scoping config or undefined if not tenant-scoped
1889
+ *
1890
+ * @example
1891
+ * ```typescript
1892
+ * @smrt({ tenantScoped: true })
1893
+ * class Document extends SmrtObject { }
1894
+ *
1895
+ * const config = ObjectRegistry.getTenantScopedConfig('Document');
1896
+ * // { mode: 'required', field: 'tenantId', autoFilter: true, autoPopulate: true, allowSuperAdminBypass: false }
1897
+ * ```
1898
+ */
1899
+ static getTenantScopedConfig(className) {
1900
+ const registered = ObjectRegistry.findClass(className);
1901
+ return registered?.tenantScopedConfig;
1902
+ }
1903
+ /**
1904
+ * Check if a class is tenant-scoped (Issue #688)
1905
+ *
1906
+ * @param className - Name of the class to check
1907
+ * @returns true if the class has tenantScoped configuration
1908
+ */
1909
+ static isTenantScoped(className) {
1910
+ return ObjectRegistry.getTenantScopedConfig(className) !== void 0;
1911
+ }
1912
+ /**
1913
+ * Get the base class for an STI hierarchy
1914
+ *
1915
+ * Walks up the inheritance chain to find the first class configured
1916
+ * with `tableStrategy: 'sti'`. This is the class that owns the shared table.
1917
+ *
1918
+ * **Returns:**
1919
+ * - The base class's **qualified name** (`@package/name:ClassName`) when
1920
+ * the registration has one — same convention as
1921
+ * `getInheritanceChain`. Falls back to the simple name only for
1922
+ * registrations without a package context (some test classes).
1923
+ * - `null` if the class uses CTI strategy.
1924
+ *
1925
+ * Accepts either a simple or a qualified name on input.
1926
+ *
1927
+ * @param className - Name of the class to find STI base for
1928
+ * @returns Qualified base class name or null if CTI
1929
+ * @example
1930
+ * ```typescript
1931
+ * @smrt({ tableStrategy: 'sti' })
1932
+ * class Event extends SmrtObject { }
1933
+ *
1934
+ * @smrt()
1935
+ * class Meeting extends Event { }
1936
+ *
1937
+ * ObjectRegistry.getSTIBase('@happyvertical/smrt-events:Meeting');
1938
+ * // '@happyvertical/smrt-events:Event'
1939
+ * ObjectRegistry.getSTIBase('@happyvertical/smrt-events:Event');
1940
+ * // '@happyvertical/smrt-events:Event'
1941
+ * ```
1942
+ */
1943
+ static getSTIBase(className) {
1944
+ const strategy = ObjectRegistry.getTableStrategy(className);
1945
+ if (strategy === "cti") {
1946
+ return null;
1947
+ }
1948
+ const chain = ObjectRegistry.getInheritanceChain(className);
1949
+ for (const ancestorName of chain) {
1950
+ const ancestor = ObjectRegistry.findClass(ancestorName);
1951
+ if (!ancestor) continue;
1952
+ if (ancestor.config?.tableStrategy === "sti") {
1953
+ return ancestor.qualifiedName ?? ancestor.name;
1954
+ }
1955
+ }
1956
+ const self = ObjectRegistry.findClass(className);
1957
+ return self?.qualifiedName ?? self?.name ?? className;
1958
+ }
1959
+ /**
1960
+ * Get all descendant classes of a base class
1961
+ *
1962
+ * Returns all registered classes that inherit from the specified base class.
1963
+ * Uses the `extends` field from manifest to build the descendant tree.
1964
+ *
1965
+ * **Use cases:**
1966
+ * - Schema generation: Aggregate fields from all children for STI table
1967
+ * - Polymorphic queries: Find all types to instantiate
1968
+ * - Documentation: Show class hierarchy
1969
+ *
1970
+ * Accepts either a simple or a qualified name on input. The returned
1971
+ * descendant names are **qualified** (`@package/name:ClassName`) when
1972
+ * the registration has one — same convention as `getInheritanceChain`
1973
+ * and `getSTIBase`.
1974
+ *
1975
+ * @param className - Name of the base class (simple or qualified)
1976
+ * @returns Array of qualified descendant class names (direct and indirect)
1977
+ * @example
1978
+ * ```typescript
1979
+ * @smrt({ tableStrategy: 'sti' })
1980
+ * class Event extends SmrtObject { }
1981
+ *
1982
+ * @smrt()
1983
+ * class Meeting extends Event { }
1984
+ *
1985
+ * @smrt()
1986
+ * class HockeyGame extends Event { }
1987
+ *
1988
+ * ObjectRegistry.getDescendants('@happyvertical/smrt-events:Event');
1989
+ * // [
1990
+ * // '@happyvertical/smrt-events:Meeting',
1991
+ * // '@happyvertical/smrt-events:HockeyGame',
1992
+ * // ]
1993
+ * ```
1994
+ */
1995
+ static getDescendants(className) {
1996
+ const descendants = [];
1997
+ const seenRegistrations = /* @__PURE__ */ new Set();
1998
+ const target = ObjectRegistry.findClass(className);
1999
+ const targetKey = target?.qualifiedName ?? target?.name ?? className;
2000
+ for (const [_key, childClass] of ObjectRegistry.classes) {
2001
+ if (seenRegistrations.has(childClass)) {
2002
+ continue;
2003
+ }
2004
+ seenRegistrations.add(childClass);
2005
+ const childKey = childClass.qualifiedName ?? childClass.name ?? _key;
2006
+ if (childKey === targetKey) continue;
2007
+ const chain = ObjectRegistry.getInheritanceChain(childKey);
2008
+ if (chain.includes(targetKey)) {
2009
+ descendants.push(childKey);
2010
+ }
2011
+ }
2012
+ return descendants;
2013
+ }
2014
+ /**
2015
+ * Persist registry state to system tables
2016
+ *
2017
+ * Saves all registered class metadata to the _smrt_registry system table
2018
+ * for runtime introspection and debugging. This enables applications to
2019
+ * query what SMRT objects exist and their configurations.
2020
+ *
2021
+ * @param db - Database interface to persist to
2022
+ * @returns Promise that resolves when persistence is complete
2023
+ * @example
2024
+ * ```typescript
2025
+ * // After registering all classes
2026
+ * await ObjectRegistry.persistToDatabase(db);
2027
+ *
2028
+ * // Later, query the system table
2029
+ * const rows = await db.all('SELECT * FROM _smrt_registry');
2030
+ * console.log('Registered classes:', rows.map(r => r.class_name));
2031
+ * ```
2032
+ */
2033
+ static async persistToDatabase(db) {
2034
+ for (const [className, registered] of ObjectRegistry.classes.entries()) {
2035
+ const fieldsData = {};
2036
+ for (const [key, value] of registered.fields) {
2037
+ fieldsData[key] = {
2038
+ type: value.type,
2039
+ options: value.options
2040
+ };
2041
+ }
2042
+ await db.upsert(
2043
+ "_smrt_registry",
2044
+ ["class_name"],
2045
+ // PRIMARY KEY for conflict detection
2046
+ {
2047
+ class_name: className,
2048
+ schema_version: "1.0.0",
2049
+ // Could be derived from package version
2050
+ fields: JSON.stringify(fieldsData),
2051
+ relationships: JSON.stringify(
2052
+ ObjectRegistry.getRelationships(className)
2053
+ ),
2054
+ config: JSON.stringify(registered.config),
2055
+ manifest: JSON.stringify({
2056
+ name: registered.name,
2057
+ tableName: registered.schema?.tableName,
2058
+ tools: registered.tools
2059
+ }),
2060
+ last_updated: /* @__PURE__ */ new Date()
2061
+ }
2062
+ );
2063
+ }
2064
+ }
2065
+ /**
2066
+ * Load registry metadata from system tables
2067
+ *
2068
+ * Reads the _smrt_registry system table to inspect what classes
2069
+ * have been registered. This is primarily for introspection and
2070
+ * debugging - actual class registration happens via @smrt() decorator.
2071
+ *
2072
+ * @param db - Database interface to load from
2073
+ * @returns Promise resolving to array of class metadata
2074
+ * @example
2075
+ * ```typescript
2076
+ * const metadata = await ObjectRegistry.loadFromDatabase(db);
2077
+ * for (const meta of metadata) {
2078
+ * console.log(`Class: ${meta.class_name}`);
2079
+ * console.log(`Table: ${JSON.parse(meta.manifest).tableName}`);
2080
+ * }
2081
+ * ```
2082
+ */
2083
+ static async loadFromDatabase(db) {
2084
+ const { rows } = await db.query(
2085
+ "SELECT * FROM _smrt_registry ORDER BY class_name"
2086
+ );
2087
+ return rows;
2088
+ }
2089
+ // ============================================================================
2090
+ // Embedding Configuration Methods
2091
+ // ============================================================================
2092
+ /**
2093
+ * Get embedding configuration for a class
2094
+ *
2095
+ * Returns the class-specific embedding config if embeddings are enabled.
2096
+ * This includes the fields to embed, provider override, and generation options.
2097
+ *
2098
+ * @param className - Name of the class to get embedding config for
2099
+ * @returns Class embedding config or undefined if not configured
2100
+ * @example
2101
+ * ```typescript
2102
+ * @smrt({
2103
+ * embeddings: {
2104
+ * fields: ['title', 'body'],
2105
+ * autoGenerate: true
2106
+ * }
2107
+ * })
2108
+ * class Article extends SmrtObject { }
2109
+ *
2110
+ * const config = ObjectRegistry.getEmbeddingConfig('Article');
2111
+ * // { fields: ['title', 'body'], autoGenerate: true }
2112
+ * ```
2113
+ */
2114
+ static getEmbeddingConfig(className) {
2115
+ return getEmbeddingConfig(className);
2116
+ }
2117
+ /**
2118
+ * Check if a class has embeddings enabled
2119
+ *
2120
+ * @param className - Name of the class to check
2121
+ * @returns True if the class has embedding configuration
2122
+ * @example
2123
+ * ```typescript
2124
+ * if (ObjectRegistry.hasEmbeddings('Article')) {
2125
+ * await article.generateEmbeddings();
2126
+ * }
2127
+ * ```
2128
+ */
2129
+ static hasEmbeddings(className) {
2130
+ return hasEmbeddings(className);
2131
+ }
2132
+ /**
2133
+ * Get all registered classes that have embeddings enabled
2134
+ *
2135
+ * @returns Array of class names with embedding configuration
2136
+ * @example
2137
+ * ```typescript
2138
+ * const embeddableClasses = ObjectRegistry.getEmbeddingClasses();
2139
+ * // ['Article', 'Profile', 'Event']
2140
+ * ```
2141
+ */
2142
+ static getEmbeddingClasses() {
2143
+ return getEmbeddingClasses();
2144
+ }
2145
+ /**
2146
+ * Get project-level embedding configuration
2147
+ *
2148
+ * Returns the global embedding settings from smrt.config (or defaults).
2149
+ * These settings apply to all classes unless overridden at the class level.
2150
+ *
2151
+ * @returns Project embedding configuration with defaults applied
2152
+ * @example
2153
+ * ```typescript
2154
+ * const projectConfig = ObjectRegistry.getProjectEmbeddingConfig();
2155
+ * // {
2156
+ * // dimensions: 768,
2157
+ * // provider: 'local',
2158
+ * // localModel: 'Xenova/bge-base-en-v1.5',
2159
+ * // aiModel: 'text-embedding-3-small',
2160
+ * // fallbackToAI: false
2161
+ * // }
2162
+ * ```
2163
+ */
2164
+ static getProjectEmbeddingConfig() {
2165
+ return getProjectEmbeddingConfig();
2166
+ }
2167
+ /**
2168
+ * Resolve complete embedding configuration for a class
2169
+ *
2170
+ * Merges project-level config with class-level overrides.
2171
+ * Returns undefined if the class doesn't have embeddings enabled.
2172
+ *
2173
+ * @param className - Name of the class to resolve config for
2174
+ * @returns Fully resolved embedding config or undefined
2175
+ * @example
2176
+ * ```typescript
2177
+ * const config = ObjectRegistry.resolveEmbeddingConfig('Article');
2178
+ * // Merges project defaults with class-specific settings
2179
+ * // {
2180
+ * // fields: ['title', 'body'],
2181
+ * // dimensions: 768,
2182
+ * // provider: 'local',
2183
+ * // localModel: 'Xenova/bge-base-en-v1.5',
2184
+ * // autoGenerate: true,
2185
+ * // regenerateOnChange: true,
2186
+ * // ...
2187
+ * // }
2188
+ * ```
2189
+ */
2190
+ static resolveEmbeddingConfig(className) {
2191
+ return resolveEmbeddingConfig(className);
2192
+ }
2193
+ /**
2194
+ * Resolve the effective collection read-cache config for a class (issue #1498)
2195
+ *
2196
+ * Walks the inheritance chain nearest-first so an STI base class opt-in
2197
+ * covers its children, while a child can opt back out with `cache: false`.
2198
+ *
2199
+ * @param className - Simple or qualified class name
2200
+ * @returns Effective cache config, or undefined when caching is not opted in
2201
+ */
2202
+ static resolveCollectionCacheConfig(className) {
2203
+ return resolveCollectionCacheConfig(className);
2204
+ }
2205
+ }
2206
+ function smrt(config = {}) {
2207
+ return (ctor, decoratorContext) => {
2208
+ applyPendingDecoratorRegistrations(ctor, decoratorContext);
2209
+ const isCollection = ctor.prototype instanceof SmrtCollection;
2210
+ if (isCollection) {
2211
+ const itemClass = ctor._itemClass;
2212
+ if (itemClass) {
2213
+ let tableName = config.tableName;
2214
+ if (!tableName) {
2215
+ const itemClassName = itemClass.name;
2216
+ const itemReg = ObjectRegistry.getClassByConstructor(
2217
+ itemClass
2218
+ );
2219
+ const itemQualified = itemReg?.qualifiedName ?? itemClassName;
2220
+ const stiBase = ObjectRegistry.getSTIBase(itemQualified);
2221
+ if (stiBase && stiBase !== itemQualified) {
2222
+ const baseReg = ObjectRegistry.getClass(stiBase);
2223
+ tableName = baseReg?.schema?.tableName ?? classnameToTablename(baseReg?.name ?? stiBase);
2224
+ } else if (ObjectRegistry.getTableStrategy(itemQualified) === "sti") {
2225
+ tableName = classnameToTablename(itemClassName);
2226
+ } else {
2227
+ tableName = classnameToTablename(itemClassName);
2228
+ }
2229
+ }
2230
+ ObjectRegistry.register(itemClass, { ...config, tableName });
2231
+ const registeredItemClass = ObjectRegistry.getClass(itemClass.name);
2232
+ ObjectRegistry.registerCollection(itemClass.name, ctor);
2233
+ if (registeredItemClass?.qualifiedName) {
2234
+ ObjectRegistry.registerCollection(
2235
+ registeredItemClass.qualifiedName,
2236
+ ctor
2237
+ );
2238
+ }
2239
+ ObjectRegistry.registerCollection(tableName, ctor);
2240
+ ObjectRegistry.setCollectionTableName(ctor.name, tableName);
2241
+ }
2242
+ } else {
2243
+ let tableName = config.tableName;
2244
+ if (!tableName) {
2245
+ const manifestEntry = discoverCachedManifestSync(ctor.name);
2246
+ if (manifestEntry?.decoratorConfig?.tableName) {
2247
+ tableName = manifestEntry.decoratorConfig.tableName;
2248
+ } else if (config.tableStrategy === "sti") {
2249
+ let proto = Object.getPrototypeOf(ctor);
2250
+ let stiBaseName = null;
2251
+ while (proto?.name && proto.name !== "SmrtObject") {
2252
+ const protoReg = ObjectRegistry.getClassByConstructor(proto);
2253
+ const protoKey = protoReg?.qualifiedName ?? proto.name;
2254
+ if (ObjectRegistry.getTableStrategy(protoKey) === "sti") {
2255
+ stiBaseName = ObjectRegistry.getSTIBase(protoKey);
2256
+ break;
2257
+ }
2258
+ proto = Object.getPrototypeOf(proto);
2259
+ }
2260
+ if (stiBaseName) {
2261
+ const baseReg = ObjectRegistry.getClass(stiBaseName);
2262
+ tableName = baseReg?.schema?.tableName ?? classnameToTablename(baseReg?.name ?? stiBaseName);
2263
+ } else {
2264
+ tableName = classnameToTablename(ctor.name);
2265
+ }
2266
+ } else {
2267
+ let proto = Object.getPrototypeOf(ctor);
2268
+ let stiBaseName = null;
2269
+ while (proto?.name && proto.name !== "SmrtObject") {
2270
+ const protoReg = ObjectRegistry.getClassByConstructor(proto);
2271
+ const protoKey = protoReg?.qualifiedName ?? proto.name;
2272
+ if (ObjectRegistry.getTableStrategy(protoKey) === "sti") {
2273
+ stiBaseName = ObjectRegistry.getSTIBase(protoKey);
2274
+ break;
2275
+ }
2276
+ proto = Object.getPrototypeOf(proto);
2277
+ }
2278
+ if (stiBaseName) {
2279
+ const baseReg = ObjectRegistry.getClass(stiBaseName);
2280
+ tableName = baseReg?.schema?.tableName ?? classnameToTablename(baseReg?.name ?? stiBaseName);
2281
+ } else {
2282
+ tableName = classnameToTablename(ctor.name);
2283
+ }
2284
+ }
2285
+ }
2286
+ ObjectRegistry.register(ctor, { ...config, tableName });
2287
+ applyOneToManyChildAccessors(
2288
+ ctor,
2289
+ ObjectRegistry.getRelationships(ctor.name)
2290
+ );
2291
+ }
2292
+ return ctor;
2293
+ };
2294
+ }
2295
+ export {
2296
+ ObjectRegistry,
2297
+ SMRT_COLLECTION_BASE_NAMES,
2298
+ isSmrtCollectionExtendsName,
2299
+ smrt
2300
+ };
2301
+ //# sourceMappingURL=registry.js.map