@happyvertical/smrt-core 0.40.69 → 0.41.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 (237) hide show
  1. package/AGENTS.md +29 -4
  2. package/README.md +20 -1
  3. package/agents/change-feed.md +1 -1
  4. package/agents/query-bounds.md +45 -0
  5. package/agents/schema-paths.md +786 -0
  6. package/dist/browser.d.ts +1 -0
  7. package/dist/browser.d.ts.map +1 -1
  8. package/dist/browser.js +5 -3
  9. package/dist/cascade.d.ts +120 -0
  10. package/dist/cascade.d.ts.map +1 -0
  11. package/dist/cascade.js +430 -0
  12. package/dist/cascade.js.map +1 -0
  13. package/dist/change-feed.d.ts +34 -2
  14. package/dist/change-feed.d.ts.map +1 -1
  15. package/dist/change-feed.js +52 -11
  16. package/dist/change-feed.js.map +1 -1
  17. package/dist/class.d.ts +36 -3
  18. package/dist/class.d.ts.map +1 -1
  19. package/dist/class.js +87 -9
  20. package/dist/class.js.map +1 -1
  21. package/dist/collection-cache.js +0 -0
  22. package/dist/collection-cache.js.map +1 -1
  23. package/dist/collection.d.ts +130 -2
  24. package/dist/collection.d.ts.map +1 -1
  25. package/dist/collection.js +290 -57
  26. package/dist/collection.js.map +1 -1
  27. package/dist/config.d.ts +10 -0
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js.map +1 -1
  30. package/dist/database.d.ts +8 -0
  31. package/dist/database.d.ts.map +1 -1
  32. package/dist/database.js +16 -8
  33. package/dist/database.js.map +1 -1
  34. package/dist/db-errors.d.ts +105 -0
  35. package/dist/db-errors.d.ts.map +1 -0
  36. package/dist/db-errors.js +382 -0
  37. package/dist/db-errors.js.map +1 -0
  38. package/dist/decorators/index.d.ts +80 -6
  39. package/dist/decorators/index.d.ts.map +1 -1
  40. package/dist/decorators/index.js +102 -12
  41. package/dist/decorators/index.js.map +1 -1
  42. package/dist/dispatch/bus.d.ts.map +1 -1
  43. package/dist/dispatch/bus.js +4 -3
  44. package/dist/dispatch/bus.js.map +1 -1
  45. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -1
  46. package/dist/dispatch/collections/Dispatches.js +19 -4
  47. package/dist/dispatch/collections/Dispatches.js.map +1 -1
  48. package/dist/dispatch/types.d.ts +5 -0
  49. package/dist/dispatch/types.d.ts.map +1 -1
  50. package/dist/embedded-write-queue.d.ts +46 -0
  51. package/dist/embedded-write-queue.d.ts.map +1 -0
  52. package/dist/embedded-write-queue.js +66 -0
  53. package/dist/embedded-write-queue.js.map +1 -0
  54. package/dist/embeddings/storage.d.ts +7 -0
  55. package/dist/embeddings/storage.d.ts.map +1 -1
  56. package/dist/embeddings/storage.js +29 -12
  57. package/dist/embeddings/storage.js.map +1 -1
  58. package/dist/errors.d.ts +31 -3
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +34 -2
  61. package/dist/errors.js.map +1 -1
  62. package/dist/generators/changes-route.d.ts.map +1 -1
  63. package/dist/generators/changes-route.js +6 -3
  64. package/dist/generators/changes-route.js.map +1 -1
  65. package/dist/generators/mcp-runtime-template.d.ts +8 -0
  66. package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
  67. package/dist/generators/mcp-runtime-template.js +38 -4
  68. package/dist/generators/mcp-runtime-template.js.map +1 -1
  69. package/dist/generators/mcp.d.ts +16 -0
  70. package/dist/generators/mcp.d.ts.map +1 -1
  71. package/dist/generators/mcp.js +41 -3
  72. package/dist/generators/mcp.js.map +1 -1
  73. package/dist/generators/rest.d.ts +22 -0
  74. package/dist/generators/rest.d.ts.map +1 -1
  75. package/dist/generators/rest.js +34 -3
  76. package/dist/generators/rest.js.map +1 -1
  77. package/dist/hierarchical.js +1 -1
  78. package/dist/index.d.ts +7 -1
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +12 -5
  81. package/dist/interceptors.d.ts +21 -0
  82. package/dist/interceptors.d.ts.map +1 -1
  83. package/dist/interceptors.js +27 -1
  84. package/dist/interceptors.js.map +1 -1
  85. package/dist/manifest/generator.d.ts.map +1 -1
  86. package/dist/manifest/generator.js +4 -7
  87. package/dist/manifest/generator.js.map +1 -1
  88. package/dist/manifest/static-manifest.js +10 -10
  89. package/dist/manifest/static-manifest.js.map +1 -1
  90. package/dist/manifest/store.js +1 -1
  91. package/dist/manifest/store.js.map +1 -1
  92. package/dist/manifest.json +19 -19
  93. package/dist/migrations/differ.d.ts +211 -9
  94. package/dist/migrations/differ.d.ts.map +1 -1
  95. package/dist/migrations/differ.js +613 -50
  96. package/dist/migrations/differ.js.map +1 -1
  97. package/dist/migrations/generator.d.ts +31 -4
  98. package/dist/migrations/generator.d.ts.map +1 -1
  99. package/dist/migrations/generator.js +49 -5
  100. package/dist/migrations/generator.js.map +1 -1
  101. package/dist/migrations/index.d.ts +4 -2
  102. package/dist/migrations/index.d.ts.map +1 -1
  103. package/dist/migrations/index.js +6 -3
  104. package/dist/migrations/minor-units.d.ts +162 -0
  105. package/dist/migrations/minor-units.d.ts.map +1 -0
  106. package/dist/migrations/minor-units.js +381 -0
  107. package/dist/migrations/minor-units.js.map +1 -0
  108. package/dist/migrations/orchestrate.js +35 -6
  109. package/dist/migrations/orchestrate.js.map +1 -1
  110. package/dist/migrations/sqlite-rebuild.d.ts +142 -0
  111. package/dist/migrations/sqlite-rebuild.d.ts.map +1 -0
  112. package/dist/migrations/sqlite-rebuild.js +514 -0
  113. package/dist/migrations/sqlite-rebuild.js.map +1 -0
  114. package/dist/migrations/tracker.d.ts +114 -1
  115. package/dist/migrations/tracker.d.ts.map +1 -1
  116. package/dist/migrations/tracker.js +331 -16
  117. package/dist/migrations/tracker.js.map +1 -1
  118. package/dist/migrations/types.d.ts +19 -4
  119. package/dist/migrations/types.d.ts.map +1 -1
  120. package/dist/migrations.js +6 -3
  121. package/dist/object.d.ts +142 -10
  122. package/dist/object.d.ts.map +1 -1
  123. package/dist/object.js +196 -41
  124. package/dist/object.js.map +1 -1
  125. package/dist/postgres-timeouts.d.ts +240 -0
  126. package/dist/postgres-timeouts.d.ts.map +1 -0
  127. package/dist/postgres-timeouts.js +204 -0
  128. package/dist/postgres-timeouts.js.map +1 -0
  129. package/dist/query-bounds.d.ts +101 -0
  130. package/dist/query-bounds.d.ts.map +1 -0
  131. package/dist/query-bounds.js +177 -0
  132. package/dist/query-bounds.js.map +1 -0
  133. package/dist/registry/class-registration.d.ts.map +1 -1
  134. package/dist/registry/class-registration.js +3 -1
  135. package/dist/registry/class-registration.js.map +1 -1
  136. package/dist/registry/manifest-field-merge.d.ts +12 -0
  137. package/dist/registry/manifest-field-merge.d.ts.map +1 -1
  138. package/dist/registry/manifest-field-merge.js +14 -2
  139. package/dist/registry/manifest-field-merge.js.map +1 -1
  140. package/dist/registry/schema-builder.d.ts +22 -1
  141. package/dist/registry/schema-builder.d.ts.map +1 -1
  142. package/dist/registry/schema-builder.js +205 -165
  143. package/dist/registry/schema-builder.js.map +1 -1
  144. package/dist/registry/types.d.ts +35 -3
  145. package/dist/registry/types.d.ts.map +1 -1
  146. package/dist/registry.d.ts +41 -46
  147. package/dist/registry.d.ts.map +1 -1
  148. package/dist/registry.js +61 -83
  149. package/dist/registry.js.map +1 -1
  150. package/dist/scanner/manifest-generator.d.ts +45 -0
  151. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  152. package/dist/scanner/manifest-generator.js +92 -28
  153. package/dist/scanner/manifest-generator.js.map +1 -1
  154. package/dist/scanner/types.d.ts +5 -0
  155. package/dist/scanner/types.d.ts.map +1 -1
  156. package/dist/scanner/types.js.map +1 -1
  157. package/dist/schema/conflict-target.d.ts +104 -0
  158. package/dist/schema/conflict-target.d.ts.map +1 -0
  159. package/dist/schema/conflict-target.js +129 -0
  160. package/dist/schema/conflict-target.js.map +1 -0
  161. package/dist/schema/ddl/base-strategy.d.ts.map +1 -1
  162. package/dist/schema/ddl/base-strategy.js +2 -2
  163. package/dist/schema/ddl/base-strategy.js.map +1 -1
  164. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -1
  165. package/dist/schema/ddl/duckdb-strategy.js +2 -1
  166. package/dist/schema/ddl/duckdb-strategy.js.map +1 -1
  167. package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -1
  168. package/dist/schema/ddl/postgres-strategy.js +12 -1
  169. package/dist/schema/ddl/postgres-strategy.js.map +1 -1
  170. package/dist/schema/generator.d.ts +307 -6
  171. package/dist/schema/generator.d.ts.map +1 -1
  172. package/dist/schema/generator.js +510 -87
  173. package/dist/schema/generator.js.map +1 -1
  174. package/dist/schema/index-utils.d.ts +120 -0
  175. package/dist/schema/index-utils.d.ts.map +1 -1
  176. package/dist/schema/index-utils.js +242 -1
  177. package/dist/schema/index-utils.js.map +1 -1
  178. package/dist/schema/index.d.ts +3 -0
  179. package/dist/schema/index.d.ts.map +1 -1
  180. package/dist/schema/index.js +4 -1
  181. package/dist/schema/live-parity.d.ts +90 -0
  182. package/dist/schema/live-parity.d.ts.map +1 -0
  183. package/dist/schema/live-parity.js +602 -0
  184. package/dist/schema/live-parity.js.map +1 -0
  185. package/dist/schema/manifest-schema.d.ts +121 -0
  186. package/dist/schema/manifest-schema.d.ts.map +1 -0
  187. package/dist/schema/manifest-schema.js +267 -0
  188. package/dist/schema/manifest-schema.js.map +1 -0
  189. package/dist/schema/schema-aggregator.d.ts +24 -10
  190. package/dist/schema/schema-aggregator.d.ts.map +1 -1
  191. package/dist/schema/schema-aggregator.js +35 -90
  192. package/dist/schema/schema-aggregator.js.map +1 -1
  193. package/dist/schema/system-table-shapes.d.ts +65 -0
  194. package/dist/schema/system-table-shapes.d.ts.map +1 -0
  195. package/dist/schema/system-table-shapes.js +187 -0
  196. package/dist/schema/system-table-shapes.js.map +1 -0
  197. package/dist/schema/types.d.ts +103 -4
  198. package/dist/schema/types.d.ts.map +1 -1
  199. package/dist/schema/utils.d.ts +2 -1
  200. package/dist/schema/utils.d.ts.map +1 -1
  201. package/dist/schema/utils.js +5 -3
  202. package/dist/schema/utils.js.map +1 -1
  203. package/dist/schema.js +4 -1
  204. package/dist/smrt-knowledge.json +20 -8
  205. package/dist/sync/apply.d.ts.map +1 -1
  206. package/dist/sync/apply.js +9 -16
  207. package/dist/sync/apply.js.map +1 -1
  208. package/dist/system/compatibility.d.ts +42 -0
  209. package/dist/system/compatibility.d.ts.map +1 -1
  210. package/dist/system/compatibility.js +182 -9
  211. package/dist/system/compatibility.js.map +1 -1
  212. package/dist/system/index.d.ts +1 -0
  213. package/dist/system/index.d.ts.map +1 -1
  214. package/dist/system/index.js +3 -2
  215. package/dist/system/retention.d.ts +237 -0
  216. package/dist/system/retention.d.ts.map +1 -0
  217. package/dist/system/retention.js +497 -0
  218. package/dist/system/retention.js.map +1 -0
  219. package/dist/system/schema.d.ts +100 -15
  220. package/dist/system/schema.d.ts.map +1 -1
  221. package/dist/system/schema.js +81 -45
  222. package/dist/system/schema.js.map +1 -1
  223. package/dist/system/types.d.ts +0 -2
  224. package/dist/system/types.d.ts.map +1 -1
  225. package/dist/testing/database.d.ts.map +1 -1
  226. package/dist/testing/database.js +1 -0
  227. package/dist/testing/database.js.map +1 -1
  228. package/dist/vite-plugin/index.d.ts.map +1 -1
  229. package/dist/vite-plugin/index.js +4 -9
  230. package/dist/vite-plugin/index.js.map +1 -1
  231. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  232. package/dist/vite-plugin/sveltekit-generator.js +71 -5
  233. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  234. package/dist/vite-plugin/web-collections.d.ts.map +1 -1
  235. package/dist/vite-plugin/web-collections.js +6 -4
  236. package/dist/vite-plugin/web-collections.js.map +1 -1
  237. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"schema-builder.d.ts","sourceRoot":"","sources":["../../src/registry/schema-builder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAK7D,OAAO,KAAK,EACV,gBAAgB,EAEhB,gBAAgB,EAChB,WAAW,EACZ,MAAM,oBAAoB,CAAC;AA6I5B;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAIpE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,cAAc,GACtB,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAkB7D;AAyCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,MAAM,CAAC,EAAE,cAAc,GACtB,MAAM,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA+OxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CA2K7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACzC,KAAK,UAAQ,EACb,MAAM,CAAC,EAAE,cAAc,GACtB,MAAM,CAwDR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GACnC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAgFlC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC,GACjC,WAAW,CAqBb"}
1
+ {"version":3,"file":"schema-builder.d.ts","sourceRoot":"","sources":["../../src/registry/schema-builder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAM7D,OAAO,KAAK,EACV,gBAAgB,EAEhB,gBAAgB,EAChB,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAmL5B;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAIpE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,cAAc,GACtB,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAkB7D;AAwTD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,MAAM,CAAC,EAAE,cAAc,GACtB,MAAM,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAmFxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAsC7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACzC,KAAK,UAAQ,EACb,MAAM,CAAC,EAAE,cAAc,GACtB,MAAM,CAwDR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACpC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAwFlC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC,GACjC,WAAW,CAqBb"}
@@ -1,9 +1,12 @@
1
+ import { classnameToTablename, toSnakeCase } from "../utils/naming.js";
1
2
  import { formatDefaultValue as formatDefaultValue$1, quoteIdentifier } from "../schema/sql-identifiers.js";
3
+ import { shortenIdentifier } from "../schema/index-utils.js";
2
4
  import { getDDLStrategy } from "../schema/ddl/index.js";
3
5
  import { getClasses, getCollectionTableNames } from "./shared-state.js";
4
6
  import { findClass } from "./name-resolver.js";
5
- import { classnameToTablename, toSnakeCase } from "../utils/naming.js";
7
+ import { conflictIndexName } from "../schema/conflict-target.js";
6
8
  import "../utils.js";
9
+ import { readFieldAttribute } from "./manifest-field-merge.js";
7
10
  import { isCollectionRegistration } from "./collection-resolution.js";
8
11
  import { ObjectRegistry } from "../registry.js";
9
12
  //#region src/registry/schema-builder.ts
@@ -34,10 +37,10 @@ function applyDecoratorSqlTypeOverrides(className, columns) {
34
37
  }
35
38
  return columns;
36
39
  }
37
- function mergeRuntimeFieldColumns(className, schemaColumns, fields) {
40
+ function mergeRuntimeFieldColumns(className, schemaColumns, fields, options) {
38
41
  const columnsToUse = { ...schemaColumns || {} };
39
42
  if (fields.size > 0) {
40
- const fieldColumns = fieldsToColumns(fields);
43
+ const fieldColumns = fieldsToColumns(fields, options);
41
44
  for (const [columnName, columnDef] of Object.entries(fieldColumns)) if (!columnsToUse[columnName]) columnsToUse[columnName] = columnDef;
42
45
  for (const [fieldName, fieldDef] of fields) {
43
46
  const columnName = toSnakeCase(fieldName);
@@ -60,24 +63,58 @@ function getReferenceKind(fieldDef) {
60
63
  if (fieldDef.type === "foreignKey") return "foreignKey";
61
64
  if (fieldDef.type === "crossPackageRef") return "crossPackageRef";
62
65
  }
63
- function shouldEmitDefault(fieldDef, sqlType) {
64
- return !(getReferenceKind(fieldDef) === "tenantId" && sqlType === "UUID" && fieldDef.default === "");
66
+ function shouldEmitDefault(fieldDef, sqlType, defaultValue) {
67
+ return !(getReferenceKind(fieldDef) === "tenantId" && sqlType === "UUID" && defaultValue === "");
65
68
  }
66
- function createBaseColumns(registered) {
67
- return {
69
+ /**
70
+ * Fallback base columns for a table whose contributing class carries no
71
+ * manifest columns.
72
+ *
73
+ * These mirror what the manifest schema generators emit for the same table
74
+ * (`generateSchemaFromManifest` / `generateSTISchemaFromManifest`), so a table
75
+ * assembled from runtime field metadata alone has the same NOT NULL and
76
+ * DEFAULT shape as one assembled from a manifest. Divergence here is what made
77
+ * the merged table shape depend on which class registered first (#2372).
78
+ */
79
+ function createBaseColumns(registered, isSTI) {
80
+ const baseColumns = {
68
81
  id: {
69
82
  type: registered.config?.idType === "text" ? "TEXT" : "UUID",
70
83
  primaryKey: true,
84
+ notNull: true,
71
85
  referenceKind: "id"
72
86
  },
73
87
  slug: {
74
88
  type: "TEXT",
75
89
  notNull: true
76
90
  },
77
- context: { type: "TEXT" },
78
- created_at: { type: "TIMESTAMP" },
79
- updated_at: { type: "TIMESTAMP" }
91
+ context: {
92
+ type: "TEXT",
93
+ notNull: true,
94
+ defaultValue: ""
95
+ },
96
+ created_at: {
97
+ type: "TIMESTAMP",
98
+ notNull: true,
99
+ defaultValue: "current_timestamp"
100
+ },
101
+ updated_at: {
102
+ type: "TIMESTAMP",
103
+ notNull: true,
104
+ defaultValue: "current_timestamp"
105
+ }
80
106
  };
107
+ if (isSTI) {
108
+ baseColumns._meta_type = {
109
+ type: "TEXT",
110
+ notNull: true
111
+ };
112
+ baseColumns._meta_data = {
113
+ type: "JSON",
114
+ notNull: false
115
+ };
116
+ }
117
+ return baseColumns;
81
118
  }
82
119
  /**
83
120
  * Get cached schema definition for a registered class
@@ -139,14 +176,151 @@ function getTableName(name) {
139
176
  }
140
177
  function withConflictIndex(tableName, columns, indexes, conflictColumns) {
141
178
  if (conflictColumns.length === 0 || !conflictColumns.every((column) => columns[column])) return indexes;
179
+ const primaryKeyColumns = Object.entries(columns).filter(([, column]) => column.primaryKey === true).map(([name]) => name);
180
+ if (primaryKeyColumns.length > 0 && primaryKeyColumns.length === conflictColumns.length && primaryKeyColumns.every((column) => conflictColumns.includes(column))) return indexes;
142
181
  if (indexes.some((index) => index.unique === true && !index.where && !index.jsonPath && index.columns.length === conflictColumns.length && index.columns.every((column) => conflictColumns.includes(column)))) return indexes;
143
- const preferredName = `${tableName}_${(conflictColumns.length > 2 ? conflictColumns.slice(0, 2) : conflictColumns).join("_")}_idx`;
144
- const name = indexes.some((index) => index.name === preferredName) ? `${preferredName}_unique` : preferredName;
145
- return [...indexes, {
182
+ const tenantColumn = Object.entries(columns).find(([, column]) => column.referenceKind === "tenantId")?.[0];
183
+ const name = shortenIdentifier(conflictIndexName(tableName, conflictColumns, tenantColumn));
184
+ const conflictIndex = {
146
185
  name,
147
186
  columns: conflictColumns,
148
187
  unique: true
149
- }];
188
+ };
189
+ if (indexes.some((index) => index.name === name)) return indexes.map((index) => index.name === name ? conflictIndex : index);
190
+ return [...indexes, conflictIndex];
191
+ }
192
+ /**
193
+ * Resolve the physical table a registered class writes to.
194
+ *
195
+ * STI subclasses are folded onto their base's table. Returns `undefined` when
196
+ * the class has no table (for example an unresolvable manifest stub).
197
+ *
198
+ * R5-canon: STI lookups use the qualified key so a colliding simple name in
199
+ * another package cannot yield the wrong table strategy or STI base and move
200
+ * this class's columns under that other package's table.
201
+ */
202
+ function resolveContributorTable(registered, fallbackName) {
203
+ const simpleName = registered.name || fallbackName;
204
+ const qualifiedName = registered.qualifiedName ?? simpleName;
205
+ if (!registered.schema?.tableName && registered.extends) {
206
+ if (ObjectRegistry.getTableStrategy(qualifiedName) === "sti") {
207
+ const stiBaseName = ObjectRegistry.getSTIBase(qualifiedName);
208
+ if (stiBaseName && stiBaseName !== qualifiedName) {
209
+ const stiBaseClass = findClass(stiBaseName);
210
+ if (stiBaseClass?.schema?.tableName) {
211
+ if (!registered.schema) registered.schema = {
212
+ tableName: "",
213
+ ddl: "",
214
+ columns: {},
215
+ indexes: [],
216
+ triggers: [],
217
+ foreignKeys: [],
218
+ dependencies: [],
219
+ version: ""
220
+ };
221
+ registered.schema.tableName = stiBaseClass.schema.tableName;
222
+ }
223
+ }
224
+ }
225
+ }
226
+ if (!registered.schema?.tableName) return;
227
+ let tableName = registered.schema.tableName;
228
+ const isSTI = ObjectRegistry.getTableStrategy(qualifiedName) === "sti";
229
+ let isSTIBase = isSTI;
230
+ let conflictKey = qualifiedName;
231
+ if (isSTI) {
232
+ const stiBaseName = ObjectRegistry.getSTIBase(qualifiedName);
233
+ if (stiBaseName) {
234
+ conflictKey = stiBaseName;
235
+ if (stiBaseName !== qualifiedName) {
236
+ isSTIBase = false;
237
+ const stiBaseClass = findClass(stiBaseName);
238
+ if (stiBaseClass?.schema?.tableName) tableName = stiBaseClass.schema.tableName;
239
+ }
240
+ }
241
+ }
242
+ return {
243
+ tableName,
244
+ contributor: {
245
+ registered,
246
+ simpleName,
247
+ qualifiedName,
248
+ isSTI,
249
+ isSTIBase,
250
+ depth: ObjectRegistry.getInheritanceChain(qualifiedName).length,
251
+ conflictKey
252
+ }
253
+ };
254
+ }
255
+ /**
256
+ * Order the classes that share one table deterministically.
257
+ *
258
+ * The first contributor seeds the table: it supplies the base columns, the
259
+ * `idType`, the conflict columns and the cached DDL, and its columns win every
260
+ * merge conflict. Registration order must not decide that, or the same
261
+ * hierarchy yields a different table shape depending on which class a manifest
262
+ * happens to list first — child-first dropped NOT NULL and DEFAULT from the
263
+ * base columns (#2372).
264
+ *
265
+ * Order: the STI base first, then ancestors before descendants, then by
266
+ * qualified name so the result is a total order.
267
+ */
268
+ function sortTableContributors(contributors) {
269
+ return [...contributors].sort((a, b) => {
270
+ if (a.isSTIBase !== b.isSTIBase) return a.isSTIBase ? -1 : 1;
271
+ if (a.depth !== b.depth) return a.depth - b.depth;
272
+ return a.qualifiedName.localeCompare(b.qualifiedName);
273
+ });
274
+ }
275
+ /**
276
+ * Assemble every physical table from the classes that contribute to it.
277
+ *
278
+ * Shared by {@link getAllSchemas} and {@link getAllSchemasAsDefinitions} so
279
+ * both produce the same merged shape. The result depends only on what is
280
+ * registered, never on the order it was registered in.
281
+ */
282
+ function buildMergedTableSchemas() {
283
+ const contributorsByTable = /* @__PURE__ */ new Map();
284
+ for (const [className, registered] of getClasses()) {
285
+ if (isCollectionRegistration(className, registered, collectionRegistrationLookup)) continue;
286
+ const resolved = resolveContributorTable(registered, className);
287
+ if (!resolved) continue;
288
+ const existing = contributorsByTable.get(resolved.tableName);
289
+ if (existing) existing.push(resolved.contributor);
290
+ else contributorsByTable.set(resolved.tableName, [resolved.contributor]);
291
+ }
292
+ const tableSchemas = {};
293
+ for (const [tableName, contributors] of contributorsByTable) for (const contributor of sortTableContributors(contributors)) {
294
+ const { registered, simpleName, isSTI } = contributor;
295
+ const columnsToUse = mergeRuntimeFieldColumns(simpleName, registered.schema?.columns, registered.fields, { stiUnionColumns: isSTI });
296
+ let tableSchema = tableSchemas[tableName];
297
+ if (!tableSchema) {
298
+ tableSchema = {
299
+ tableName,
300
+ columns: {
301
+ ...createBaseColumns(registered, isSTI),
302
+ ...columnsToUse
303
+ },
304
+ indexes: [],
305
+ ddl: registered.schema?.ddl || "",
306
+ isSTI,
307
+ conflictColumns: ObjectRegistry.getConflictColumns(contributor.conflictKey)
308
+ };
309
+ tableSchemas[tableName] = tableSchema;
310
+ } else for (const [colName, colDef] of Object.entries(columnsToUse)) if (!tableSchema.columns[colName]) tableSchema.columns[colName] = colDef;
311
+ const schemaIndexes = registered.schema?.indexes;
312
+ if (schemaIndexes && schemaIndexes.length > 0) {
313
+ const existingNames = new Set(tableSchema.indexes.map((index) => index.name));
314
+ for (const index of schemaIndexes) {
315
+ if (typeof index === "string") continue;
316
+ if (!existingNames.has(index.name)) {
317
+ tableSchema.indexes.push(index);
318
+ existingNames.add(index.name);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ return tableSchemas;
150
324
  }
151
325
  /**
152
326
  * Get all pre-generated schemas for explicit adapter bootstrap paths.
@@ -164,81 +338,7 @@ function withConflictIndex(tableName, columns, indexes, conflictColumns) {
164
338
  * ```
165
339
  */
166
340
  function getAllSchemas(engine) {
167
- const tableSchemas = {};
168
- for (const [_className, registered] of getClasses()) {
169
- if (isCollectionRegistration(_className, registered, collectionRegistrationLookup)) continue;
170
- const simpleName = registered.name || _className;
171
- if (!registered.schema?.tableName && registered.extends) {
172
- const qualifiedName = registered.qualifiedName ?? simpleName;
173
- const lookupKey = qualifiedName;
174
- if (ObjectRegistry.getTableStrategy(lookupKey) === "sti") {
175
- const stiBaseName = ObjectRegistry.getSTIBase(lookupKey);
176
- if (stiBaseName && stiBaseName !== qualifiedName) {
177
- const stiBaseClass = findClass(stiBaseName);
178
- if (stiBaseClass?.schema?.tableName) {
179
- if (!registered.schema) registered.schema = {
180
- tableName: "",
181
- ddl: "",
182
- columns: {},
183
- indexes: [],
184
- triggers: [],
185
- foreignKeys: [],
186
- dependencies: [],
187
- version: ""
188
- };
189
- registered.schema.tableName = stiBaseClass.schema.tableName;
190
- }
191
- }
192
- }
193
- }
194
- if (registered.schema?.tableName) {
195
- let tableName = registered.schema.tableName;
196
- const qualifiedName = registered.qualifiedName ?? simpleName;
197
- const lookupKey = qualifiedName;
198
- const tableStrategy = ObjectRegistry.getTableStrategy(lookupKey);
199
- if (tableStrategy === "sti") {
200
- const stiBaseName = ObjectRegistry.getSTIBase(lookupKey);
201
- if (stiBaseName && stiBaseName !== qualifiedName) {
202
- const stiBaseClass = findClass(stiBaseName);
203
- if (stiBaseClass?.schema?.tableName) tableName = stiBaseClass.schema.tableName;
204
- }
205
- }
206
- const columnsToUse = mergeRuntimeFieldColumns(simpleName, registered.schema.columns, registered.fields);
207
- if (!tableSchemas[tableName]) {
208
- const baseColumns = createBaseColumns(registered);
209
- const isSTI = tableStrategy === "sti";
210
- if (isSTI) {
211
- baseColumns._meta_type = {
212
- type: "TEXT",
213
- notNull: true,
214
- defaultValue: ""
215
- };
216
- baseColumns._meta_data = { type: "JSON" };
217
- }
218
- tableSchemas[tableName] = {
219
- tableName,
220
- columns: {
221
- ...baseColumns,
222
- ...columnsToUse
223
- },
224
- indexes: [],
225
- ddl: registered.schema.ddl || "",
226
- isSTI,
227
- conflictColumns: ObjectRegistry.getConflictColumns(isSTI ? ObjectRegistry.getSTIBase(lookupKey) || lookupKey : lookupKey)
228
- };
229
- } else for (const [colName, colDef] of Object.entries(columnsToUse)) if (!tableSchemas[tableName].columns[colName]) tableSchemas[tableName].columns[colName] = colDef;
230
- if (registered.schema.indexes && registered.schema.indexes.length > 0) {
231
- const existingNames = new Set(tableSchemas[tableName].indexes.map((idx) => typeof idx === "string" ? idx : idx.name));
232
- for (const idx of registered.schema.indexes) {
233
- const indexName = typeof idx === "string" ? idx : idx.name;
234
- if (!existingNames.has(indexName)) if (typeof idx === "string") {} else {
235
- tableSchemas[tableName].indexes.push(idx);
236
- existingNames.add(idx.name);
237
- }
238
- }
239
- }
240
- }
241
- }
341
+ const tableSchemas = buildMergedTableSchemas();
242
342
  const schemas = {};
243
343
  for (const [tableName, tableSchema] of Object.entries(tableSchemas)) {
244
344
  const engineIndexes = engine ? withConflictIndex(tableName, tableSchema.columns, tableSchema.indexes, tableSchema.conflictColumns) : tableSchema.indexes;
@@ -285,77 +385,7 @@ function getAllSchemas(engine) {
285
385
  * @returns Map of tableName to SchemaDefinition
286
386
  */
287
387
  function getAllSchemasAsDefinitions() {
288
- const tableSchemas = {};
289
- for (const [_className, registered] of getClasses()) {
290
- if (isCollectionRegistration(_className, registered, collectionRegistrationLookup)) continue;
291
- const simpleName = registered.name || _className;
292
- if (!registered.schema?.tableName && registered.extends) {
293
- const qualifiedName = registered.qualifiedName ?? simpleName;
294
- const lookupKey = qualifiedName;
295
- if (ObjectRegistry.getTableStrategy(lookupKey) === "sti") {
296
- const stiBaseName = ObjectRegistry.getSTIBase(lookupKey);
297
- if (stiBaseName && stiBaseName !== qualifiedName) {
298
- const stiBaseClass = findClass(stiBaseName);
299
- if (stiBaseClass?.schema?.tableName) {
300
- if (!registered.schema) registered.schema = {
301
- tableName: "",
302
- ddl: "",
303
- columns: {},
304
- indexes: [],
305
- triggers: [],
306
- foreignKeys: [],
307
- dependencies: [],
308
- version: ""
309
- };
310
- registered.schema.tableName = stiBaseClass.schema.tableName;
311
- }
312
- }
313
- }
314
- }
315
- if (registered.schema?.tableName) {
316
- let tableName = registered.schema.tableName;
317
- const qualifiedName = registered.qualifiedName ?? simpleName;
318
- const lookupKey = qualifiedName;
319
- const tableStrategy = ObjectRegistry.getTableStrategy(lookupKey);
320
- if (tableStrategy === "sti") {
321
- const stiBaseName = ObjectRegistry.getSTIBase(lookupKey);
322
- if (stiBaseName && stiBaseName !== qualifiedName) {
323
- const stiBaseClass = findClass(stiBaseName);
324
- if (stiBaseClass?.schema?.tableName) tableName = stiBaseClass.schema.tableName;
325
- }
326
- }
327
- const columnsToUse = mergeRuntimeFieldColumns(simpleName, registered.schema.columns, registered.fields);
328
- if (!tableSchemas[tableName]) {
329
- const baseColumns = createBaseColumns(registered);
330
- const isSTI = tableStrategy === "sti";
331
- if (isSTI) {
332
- baseColumns._meta_type = {
333
- type: "TEXT",
334
- notNull: true,
335
- defaultValue: ""
336
- };
337
- baseColumns._meta_data = { type: "JSON" };
338
- }
339
- tableSchemas[tableName] = {
340
- tableName,
341
- columns: {
342
- ...baseColumns,
343
- ...columnsToUse
344
- },
345
- indexes: [],
346
- isSTI,
347
- conflictColumns: ObjectRegistry.getConflictColumns(isSTI ? ObjectRegistry.getSTIBase(lookupKey) || lookupKey : lookupKey)
348
- };
349
- } else for (const [colName, colDef] of Object.entries(columnsToUse)) if (!tableSchemas[tableName].columns[colName]) tableSchemas[tableName].columns[colName] = colDef;
350
- if (registered.schema.indexes && registered.schema.indexes.length > 0) {
351
- const existingNames = new Set(tableSchemas[tableName].indexes.map((idx) => idx.name));
352
- for (const idx of registered.schema.indexes) if (!existingNames.has(idx.name)) {
353
- tableSchemas[tableName].indexes.push(idx);
354
- existingNames.add(idx.name);
355
- }
356
- }
357
- }
358
- }
388
+ const tableSchemas = buildMergedTableSchemas();
359
389
  const schemas = {};
360
390
  for (const [tableName, tableSchema] of Object.entries(tableSchemas)) {
361
391
  if (Object.keys(tableSchema.columns).length === 0) continue;
@@ -427,11 +457,17 @@ function formatDefaultValue(value, type) {
427
457
  * Used by getAllSchemas() to generate columns from fields when a class
428
458
  * has no pre-generated schema (e.g., STI subclasses registered from manifest).
429
459
  *
460
+ * `required`, `default`, and `description` are read from either the top level
461
+ * or `_meta`: registry-sourced fields normalize them into `_meta`, so reading
462
+ * only the top level dropped NOT NULL and DEFAULT for every such field
463
+ * (#2372).
464
+ *
430
465
  * @param fields - Map of field name to field definition
466
+ * @param options - Table-shape options (see {@link FieldsToColumnsOptions})
431
467
  * @returns Record of column name to column definition
432
468
  * @private
433
469
  */
434
- function fieldsToColumns(fields) {
470
+ function fieldsToColumns(fields, options) {
435
471
  const columns = {};
436
472
  for (const [fieldName, fieldDef] of fields) {
437
473
  if (fieldName === "id" || fieldName === "created_at" || fieldName === "updated_at" || fieldName === "slug" || fieldName === "context") continue;
@@ -440,14 +476,18 @@ function fieldsToColumns(fields) {
440
476
  if (fieldDef.type === "meta") continue;
441
477
  const sqlType = fieldDef._meta?.sqlType || (fieldDef.type === "crossPackageRef" && (fieldDef._meta?.idType === "text" || fieldDef.idType === "text") ? "TEXT" : mapFieldTypeToSQL(fieldDef.type));
442
478
  const normalizedSqlType = String(sqlType).toUpperCase();
479
+ const referenceKind = getReferenceKind(fieldDef);
480
+ const required = readFieldAttribute(fieldDef, "required");
481
+ const defaultValue = readFieldAttribute(fieldDef, "default");
482
+ const description = readFieldAttribute(fieldDef, "description");
443
483
  const column = {
444
484
  type: normalizedSqlType,
445
- referenceKind: getReferenceKind(fieldDef),
446
- notNull: fieldDef._meta?.nullable ? false : fieldDef.required || false,
485
+ referenceKind,
486
+ notNull: options?.stiUnionColumns ? false : fieldDef._meta?.nullable ? false : Boolean(required),
447
487
  unique: fieldDef._meta?.unique || false,
448
- description: fieldDef.description
488
+ description
449
489
  };
450
- if (fieldDef.default !== void 0 && shouldEmitDefault(fieldDef, normalizedSqlType)) column.defaultValue = fieldDef.default;
490
+ if (defaultValue !== void 0 && shouldEmitDefault(fieldDef, normalizedSqlType, defaultValue)) column.defaultValue = defaultValue;
451
491
  if (fieldDef.type === "foreignKey" && fieldDef.related) {
452
492
  const [table, columnName = "id"] = fieldDef.related.split(".");
453
493
  const fieldMeta = fieldDef._meta;