@rebasepro/server-postgresql 0.4.0 → 0.6.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 (168) hide show
  1. package/README.md +69 -89
  2. package/dist/{server-postgresql/src/PostgresAdapter.d.ts → PostgresAdapter.d.ts} +1 -1
  3. package/dist/{server-postgresql/src/PostgresBackendDriver.d.ts → PostgresBackendDriver.d.ts} +2 -2
  4. package/dist/{server-postgresql/src/PostgresBootstrapper.d.ts → PostgresBootstrapper.d.ts} +11 -1
  5. package/dist/{server-postgresql/src/auth → auth}/services.d.ts +11 -11
  6. package/dist/{server-postgresql/src/collections → collections}/PostgresCollectionRegistry.d.ts +4 -0
  7. package/dist/{server-postgresql/src/data-transformer.d.ts → data-transformer.d.ts} +0 -3
  8. package/dist/{server-postgresql/src/databasePoolManager.d.ts → databasePoolManager.d.ts} +1 -1
  9. package/dist/index.es.js +10174 -11184
  10. package/dist/index.es.js.map +1 -1
  11. package/dist/index.umd.js +10735 -11462
  12. package/dist/index.umd.js.map +1 -1
  13. package/dist/{server-postgresql/src/services → services}/EntityPersistService.d.ts +0 -14
  14. package/dist/types.d.ts +3 -0
  15. package/dist/utils/pg-error-utils.d.ts +55 -0
  16. package/dist/{server-postgresql/src/websocket.d.ts → websocket.d.ts} +8 -3
  17. package/package.json +24 -21
  18. package/src/PostgresAdapter.ts +9 -10
  19. package/src/PostgresBackendDriver.ts +135 -122
  20. package/src/PostgresBootstrapper.ts +90 -16
  21. package/src/auth/ensure-tables.ts +28 -5
  22. package/src/auth/services.ts +56 -45
  23. package/src/cli.ts +140 -110
  24. package/src/collections/PostgresCollectionRegistry.ts +7 -0
  25. package/src/connection.ts +11 -6
  26. package/src/data-transformer.ts +73 -109
  27. package/src/databasePoolManager.ts +5 -3
  28. package/src/history/HistoryService.ts +3 -2
  29. package/src/history/ensure-history-table.ts +5 -4
  30. package/src/schema/auth-schema.ts +1 -2
  31. package/src/schema/doctor-cli.ts +2 -1
  32. package/src/schema/doctor.ts +40 -37
  33. package/src/schema/generate-drizzle-schema-logic.ts +56 -18
  34. package/src/schema/generate-drizzle-schema.ts +11 -11
  35. package/src/schema/introspect-db-inference.ts +25 -25
  36. package/src/schema/introspect-db-logic.ts +38 -38
  37. package/src/schema/introspect-db.ts +28 -27
  38. package/src/services/BranchService.ts +14 -0
  39. package/src/services/EntityFetchService.ts +28 -25
  40. package/src/services/EntityPersistService.ts +11 -124
  41. package/src/services/RelationService.ts +57 -37
  42. package/src/services/entity-helpers.ts +6 -2
  43. package/src/services/realtimeService.ts +45 -32
  44. package/src/types.ts +4 -0
  45. package/src/utils/drizzle-conditions.ts +31 -15
  46. package/src/utils/pg-error-utils.ts +211 -0
  47. package/src/websocket.ts +51 -33
  48. package/test/auth-services.test.ts +36 -19
  49. package/test/batch-many-to-many-regression.test.ts +119 -39
  50. package/test/data-transformer-hardening.test.ts +67 -33
  51. package/test/data-transformer.test.ts +4 -2
  52. package/test/doctor.test.ts +10 -5
  53. package/test/drizzle-conditions.test.ts +59 -6
  54. package/test/generate-drizzle-schema.test.ts +65 -40
  55. package/test/introspect-db-generation.test.ts +179 -81
  56. package/test/introspect-db-utils.test.ts +92 -37
  57. package/test/mocks/chalk.cjs +7 -0
  58. package/test/pg-error-utils.test.ts +221 -0
  59. package/test/postgresDataDriver.test.ts +14 -5
  60. package/test/property-ordering.test.ts +126 -79
  61. package/test/realtimeService.test.ts +6 -2
  62. package/test/relation-pipeline-gaps.test.ts +84 -36
  63. package/test/relations.test.ts +247 -0
  64. package/test/unmapped-tables-safety.test.ts +14 -6
  65. package/test/websocket.test.ts +1 -1
  66. package/tsconfig.json +5 -0
  67. package/tsconfig.prod.json +3 -0
  68. package/vite.config.ts +5 -5
  69. package/dist/common/src/collections/CollectionRegistry.d.ts +0 -56
  70. package/dist/common/src/collections/default-collections.d.ts +0 -9
  71. package/dist/common/src/collections/index.d.ts +0 -2
  72. package/dist/common/src/data/buildRebaseData.d.ts +0 -14
  73. package/dist/common/src/data/query_builder.d.ts +0 -55
  74. package/dist/common/src/index.d.ts +0 -4
  75. package/dist/common/src/util/builders.d.ts +0 -57
  76. package/dist/common/src/util/callbacks.d.ts +0 -6
  77. package/dist/common/src/util/collections.d.ts +0 -11
  78. package/dist/common/src/util/common.d.ts +0 -2
  79. package/dist/common/src/util/conditions.d.ts +0 -26
  80. package/dist/common/src/util/entities.d.ts +0 -58
  81. package/dist/common/src/util/enums.d.ts +0 -3
  82. package/dist/common/src/util/index.d.ts +0 -16
  83. package/dist/common/src/util/navigation_from_path.d.ts +0 -34
  84. package/dist/common/src/util/navigation_utils.d.ts +0 -20
  85. package/dist/common/src/util/parent_references_from_path.d.ts +0 -6
  86. package/dist/common/src/util/paths.d.ts +0 -14
  87. package/dist/common/src/util/permissions.d.ts +0 -6
  88. package/dist/common/src/util/references.d.ts +0 -2
  89. package/dist/common/src/util/relations.d.ts +0 -22
  90. package/dist/common/src/util/resolutions.d.ts +0 -72
  91. package/dist/common/src/util/storage.d.ts +0 -24
  92. package/dist/types/src/controllers/analytics_controller.d.ts +0 -7
  93. package/dist/types/src/controllers/auth.d.ts +0 -104
  94. package/dist/types/src/controllers/client.d.ts +0 -168
  95. package/dist/types/src/controllers/collection_registry.d.ts +0 -46
  96. package/dist/types/src/controllers/customization_controller.d.ts +0 -60
  97. package/dist/types/src/controllers/data.d.ts +0 -207
  98. package/dist/types/src/controllers/data_driver.d.ts +0 -218
  99. package/dist/types/src/controllers/database_admin.d.ts +0 -11
  100. package/dist/types/src/controllers/dialogs_controller.d.ts +0 -36
  101. package/dist/types/src/controllers/effective_role.d.ts +0 -4
  102. package/dist/types/src/controllers/email.d.ts +0 -36
  103. package/dist/types/src/controllers/index.d.ts +0 -18
  104. package/dist/types/src/controllers/local_config_persistence.d.ts +0 -20
  105. package/dist/types/src/controllers/navigation.d.ts +0 -225
  106. package/dist/types/src/controllers/registry.d.ts +0 -63
  107. package/dist/types/src/controllers/side_dialogs_controller.d.ts +0 -67
  108. package/dist/types/src/controllers/side_entity_controller.d.ts +0 -97
  109. package/dist/types/src/controllers/snackbar.d.ts +0 -24
  110. package/dist/types/src/controllers/storage.d.ts +0 -171
  111. package/dist/types/src/index.d.ts +0 -4
  112. package/dist/types/src/rebase_context.d.ts +0 -122
  113. package/dist/types/src/types/auth_adapter.d.ts +0 -301
  114. package/dist/types/src/types/backend.d.ts +0 -536
  115. package/dist/types/src/types/backend_hooks.d.ts +0 -172
  116. package/dist/types/src/types/builders.d.ts +0 -15
  117. package/dist/types/src/types/chips.d.ts +0 -5
  118. package/dist/types/src/types/collections.d.ts +0 -941
  119. package/dist/types/src/types/component_ref.d.ts +0 -47
  120. package/dist/types/src/types/cron.d.ts +0 -102
  121. package/dist/types/src/types/data_source.d.ts +0 -64
  122. package/dist/types/src/types/database_adapter.d.ts +0 -94
  123. package/dist/types/src/types/entities.d.ts +0 -145
  124. package/dist/types/src/types/entity_actions.d.ts +0 -104
  125. package/dist/types/src/types/entity_callbacks.d.ts +0 -173
  126. package/dist/types/src/types/entity_link_builder.d.ts +0 -7
  127. package/dist/types/src/types/entity_overrides.d.ts +0 -10
  128. package/dist/types/src/types/entity_views.d.ts +0 -87
  129. package/dist/types/src/types/export_import.d.ts +0 -21
  130. package/dist/types/src/types/formex.d.ts +0 -40
  131. package/dist/types/src/types/index.d.ts +0 -28
  132. package/dist/types/src/types/locales.d.ts +0 -4
  133. package/dist/types/src/types/modify_collections.d.ts +0 -5
  134. package/dist/types/src/types/plugins.d.ts +0 -282
  135. package/dist/types/src/types/properties.d.ts +0 -1181
  136. package/dist/types/src/types/property_config.d.ts +0 -74
  137. package/dist/types/src/types/relations.d.ts +0 -336
  138. package/dist/types/src/types/slots.d.ts +0 -262
  139. package/dist/types/src/types/translations.d.ts +0 -900
  140. package/dist/types/src/types/user_management_delegate.d.ts +0 -86
  141. package/dist/types/src/types/websockets.d.ts +0 -78
  142. package/dist/types/src/users/index.d.ts +0 -1
  143. package/dist/types/src/users/user.d.ts +0 -50
  144. package/drizzle.test.config.ts +0 -10
  145. /package/dist/{server-postgresql/src/auth → auth}/ensure-tables.d.ts +0 -0
  146. /package/dist/{server-postgresql/src/cli.d.ts → cli.d.ts} +0 -0
  147. /package/dist/{server-postgresql/src/connection.d.ts → connection.d.ts} +0 -0
  148. /package/dist/{server-postgresql/src/history → history}/HistoryService.d.ts +0 -0
  149. /package/dist/{server-postgresql/src/history → history}/ensure-history-table.d.ts +0 -0
  150. /package/dist/{server-postgresql/src/index.d.ts → index.d.ts} +0 -0
  151. /package/dist/{server-postgresql/src/interfaces.d.ts → interfaces.d.ts} +0 -0
  152. /package/dist/{server-postgresql/src/schema → schema}/auth-schema.d.ts +0 -0
  153. /package/dist/{server-postgresql/src/schema → schema}/doctor-cli.d.ts +0 -0
  154. /package/dist/{server-postgresql/src/schema → schema}/doctor.d.ts +0 -0
  155. /package/dist/{server-postgresql/src/schema → schema}/generate-drizzle-schema-logic.d.ts +0 -0
  156. /package/dist/{server-postgresql/src/schema → schema}/generate-drizzle-schema.d.ts +0 -0
  157. /package/dist/{server-postgresql/src/schema → schema}/introspect-db-inference.d.ts +0 -0
  158. /package/dist/{server-postgresql/src/schema → schema}/introspect-db-logic.d.ts +0 -0
  159. /package/dist/{server-postgresql/src/schema → schema}/introspect-db.d.ts +0 -0
  160. /package/dist/{server-postgresql/src/schema → schema}/test-schema.d.ts +0 -0
  161. /package/dist/{server-postgresql/src/services → services}/BranchService.d.ts +0 -0
  162. /package/dist/{server-postgresql/src/services → services}/EntityFetchService.d.ts +0 -0
  163. /package/dist/{server-postgresql/src/services → services}/RelationService.d.ts +0 -0
  164. /package/dist/{server-postgresql/src/services → services}/entity-helpers.d.ts +0 -0
  165. /package/dist/{server-postgresql/src/services → services}/entityService.d.ts +0 -0
  166. /package/dist/{server-postgresql/src/services → services}/index.d.ts +0 -0
  167. /package/dist/{server-postgresql/src/services → services}/realtimeService.d.ts +0 -0
  168. /package/dist/{server-postgresql/src/utils → utils}/drizzle-conditions.d.ts +0 -0
@@ -1113,3 +1113,250 @@ relationName: "recipient" }
1113
1113
  expect(namesInMessages[0]).not.toBe(namesInMessages[1]);
1114
1114
  });
1115
1115
  });
1116
+
1117
+ describe("columnName vs property key deduplication regression", () => {
1118
+ const extractRelationNames = (schema: string): string[] => {
1119
+ const matches = schema.match(/relationName:\s*"([^"]+)"/g) ?? [];
1120
+ return matches.map(m => m.replace(/relationName:\s*"/, "").replace(/"$/, ""));
1121
+ };
1122
+
1123
+ it("should not emit a synthetic duplicate when property uses columnName different from property key", async () => {
1124
+ // Scenario: engagements.clientId has columnName: "client_id"
1125
+ // The explicit owning relation uses localKey: "clientId" (property key).
1126
+ // The inverse relation on clients uses foreignKeyOnTarget: "client_id" (raw column).
1127
+ // Without the fix, the synthetic loop would emit a broken second relation
1128
+ // using engagements.client_id (which doesn't exist as a Drizzle property).
1129
+ const clientsCollection: EntityCollection = {
1130
+ slug: "clients",
1131
+ table: "clients",
1132
+ name: "Clients",
1133
+ properties: {
1134
+ id: { type: "string" },
1135
+ name: { type: "string" }
1136
+ },
1137
+ relations: [
1138
+ {
1139
+ relationName: "engagements",
1140
+ target: () => engagementsCollection,
1141
+ cardinality: "many",
1142
+ direction: "inverse",
1143
+ foreignKeyOnTarget: "client_id"
1144
+ }
1145
+ ]
1146
+ };
1147
+
1148
+ const engagementsCollection: EntityCollection = {
1149
+ slug: "engagements",
1150
+ table: "engagements",
1151
+ name: "Engagements",
1152
+ properties: {
1153
+ id: { type: "string" },
1154
+ clientId: {
1155
+ type: "relation",
1156
+ columnName: "client_id",
1157
+ target: () => clientsCollection,
1158
+ cardinality: "one",
1159
+ direction: "owning",
1160
+ localKey: "clientId",
1161
+ relationName: "client"
1162
+ } as any,
1163
+ title: { type: "string" }
1164
+ },
1165
+ relations: [
1166
+ {
1167
+ relationName: "client",
1168
+ target: () => clientsCollection,
1169
+ cardinality: "one",
1170
+ direction: "owning",
1171
+ localKey: "clientId"
1172
+ }
1173
+ ]
1174
+ };
1175
+
1176
+ const result = await generateSchema([clientsCollection, engagementsCollection]);
1177
+
1178
+ // engagements should have exactly ONE one() entry for clientId
1179
+ const engagementsRelBlock = result.match(/export const engagementsRelations[\s\S]*?\}\)\);/)?.[0] ?? "";
1180
+ const oneEntries = (engagementsRelBlock.match(/:\s*one\(/g) ?? []).length;
1181
+ expect(oneEntries).toBe(1);
1182
+
1183
+ // The one() entry must reference engagements.clientId (property key), NOT engagements.client_id
1184
+ expect(engagementsRelBlock).toContain("engagements.clientId");
1185
+ expect(engagementsRelBlock).not.toContain("engagements.client_id");
1186
+
1187
+ // No _synth_ entry should appear
1188
+ expect(engagementsRelBlock).not.toContain("_synth_");
1189
+ });
1190
+
1191
+ it("should produce matching relation names on both sides when columnName differs from property key", async () => {
1192
+ const clientsCollection: EntityCollection = {
1193
+ slug: "clients",
1194
+ table: "clients",
1195
+ name: "Clients",
1196
+ properties: {
1197
+ id: { type: "string" },
1198
+ name: { type: "string" }
1199
+ },
1200
+ relations: [
1201
+ {
1202
+ relationName: "engagements",
1203
+ target: () => engagementsCollection,
1204
+ cardinality: "many",
1205
+ direction: "inverse",
1206
+ foreignKeyOnTarget: "client_id"
1207
+ }
1208
+ ]
1209
+ };
1210
+
1211
+ const engagementsCollection: EntityCollection = {
1212
+ slug: "engagements",
1213
+ table: "engagements",
1214
+ name: "Engagements",
1215
+ properties: {
1216
+ id: { type: "string" },
1217
+ clientId: {
1218
+ type: "relation",
1219
+ columnName: "client_id",
1220
+ target: () => clientsCollection,
1221
+ cardinality: "one",
1222
+ direction: "owning",
1223
+ localKey: "clientId",
1224
+ relationName: "client"
1225
+ } as any,
1226
+ title: { type: "string" }
1227
+ },
1228
+ relations: [
1229
+ {
1230
+ relationName: "client",
1231
+ target: () => clientsCollection,
1232
+ cardinality: "one",
1233
+ direction: "owning",
1234
+ localKey: "clientId"
1235
+ }
1236
+ ]
1237
+ };
1238
+
1239
+ const result = await generateSchema([clientsCollection, engagementsCollection]);
1240
+
1241
+ // Extract relation names from both sides
1242
+ const engagementsRelBlock = result.match(/export const engagementsRelations[\s\S]*?\}\)\);/)?.[0] ?? "";
1243
+ const clientsRelBlock = result.match(/export const clientsRelations[\s\S]*?\}\)\);/)?.[0] ?? "";
1244
+
1245
+ const engagementsRelNames = extractRelationNames(engagementsRelBlock);
1246
+ const clientsRelNames = extractRelationNames(clientsRelBlock);
1247
+
1248
+ // Both sides must share the same relation name
1249
+ expect(engagementsRelNames.length).toBeGreaterThanOrEqual(1);
1250
+ expect(clientsRelNames.length).toBeGreaterThanOrEqual(1);
1251
+
1252
+ // The owning side's relation name should appear in the inverse side too
1253
+ const sharedName = engagementsRelNames[0];
1254
+ expect(clientsRelNames).toContain(sharedName);
1255
+ });
1256
+
1257
+ it("should correctly handle inverse one-to-one with columnName on target", async () => {
1258
+ // One-to-one: user has a profile, profile has userId with columnName: "user_id"
1259
+ const usersCollection: EntityCollection = {
1260
+ slug: "users",
1261
+ table: "users",
1262
+ name: "Users",
1263
+ properties: {
1264
+ id: { type: "string" },
1265
+ name: { type: "string" }
1266
+ },
1267
+ relations: [
1268
+ {
1269
+ relationName: "profile",
1270
+ target: () => profilesCollection,
1271
+ cardinality: "one",
1272
+ direction: "inverse",
1273
+ foreignKeyOnTarget: "user_id"
1274
+ }
1275
+ ]
1276
+ };
1277
+
1278
+ const profilesCollection: EntityCollection = {
1279
+ slug: "profiles",
1280
+ table: "profiles",
1281
+ name: "Profiles",
1282
+ properties: {
1283
+ id: { type: "string" },
1284
+ userId: {
1285
+ type: "relation",
1286
+ columnName: "user_id",
1287
+ target: () => usersCollection,
1288
+ cardinality: "one",
1289
+ direction: "owning",
1290
+ localKey: "userId",
1291
+ relationName: "user"
1292
+ } as any,
1293
+ bio: { type: "string" }
1294
+ },
1295
+ relations: [
1296
+ {
1297
+ relationName: "user",
1298
+ target: () => usersCollection,
1299
+ cardinality: "one",
1300
+ direction: "owning",
1301
+ localKey: "userId"
1302
+ }
1303
+ ]
1304
+ };
1305
+
1306
+ const result = await generateSchema([usersCollection, profilesCollection]);
1307
+
1308
+ // profiles should have exactly ONE one() entry
1309
+ const profilesRelBlock = result.match(/export const profilesRelations[\s\S]*?\}\)\);/)?.[0] ?? "";
1310
+ const oneEntries = (profilesRelBlock.match(/:\s*one\(/g) ?? []).length;
1311
+ expect(oneEntries).toBe(1);
1312
+
1313
+ // Must reference profiles.userId (property key), NOT profiles.user_id
1314
+ expect(profilesRelBlock).toContain("profiles.userId");
1315
+ expect(profilesRelBlock).not.toContain("profiles.user_id");
1316
+
1317
+ // No _synth_ entry
1318
+ expect(profilesRelBlock).not.toContain("_synth_");
1319
+ });
1320
+
1321
+ it("should still emit synthetic relations when no explicit owning relation exists", async () => {
1322
+ // When a collection has a FK column but no explicit owning relation defined,
1323
+ // the synthetic loop should still create the missing relation.
1324
+ const categoriesCollection: EntityCollection = {
1325
+ slug: "categories",
1326
+ table: "categories",
1327
+ name: "Categories",
1328
+ properties: {
1329
+ id: { type: "string" },
1330
+ name: { type: "string" }
1331
+ },
1332
+ relations: [
1333
+ {
1334
+ relationName: "products",
1335
+ target: () => productsCollection,
1336
+ cardinality: "many",
1337
+ direction: "inverse",
1338
+ foreignKeyOnTarget: "category_id"
1339
+ }
1340
+ ]
1341
+ };
1342
+
1343
+ const productsCollection: EntityCollection = {
1344
+ slug: "products",
1345
+ table: "products",
1346
+ name: "Products",
1347
+ properties: {
1348
+ id: { type: "string" },
1349
+ name: { type: "string" },
1350
+ category_id: { type: "string" }
1351
+ // NOTE: no type: "relation" and no explicit relations[]
1352
+ }
1353
+ };
1354
+
1355
+ const result = await generateSchema([categoriesCollection, productsCollection]);
1356
+
1357
+ // products should get a synthetic one() for category_id
1358
+ const productsRelBlock = result.match(/export const productsRelations[\s\S]*?\}\)\);/)?.[0] ?? "";
1359
+ expect(productsRelBlock).toContain("one(categories");
1360
+ expect(productsRelBlock).toContain("products.category_id");
1361
+ });
1362
+ });
@@ -49,7 +49,9 @@ function buildPrevSnapshot(tables: Record<string, any>, enums: Record<string, an
49
49
  roles: {},
50
50
  policies: {},
51
51
  views: {},
52
- _meta: { schemas: {}, tables: {}, columns: {} }
52
+ _meta: { schemas: {},
53
+ tables: {},
54
+ columns: {} }
53
55
  };
54
56
  }
55
57
 
@@ -82,7 +84,9 @@ function snapshotColumn(name: string, type: string, opts: {
82
84
  }
83
85
 
84
86
  function snapshotEnum(name: string, schema: string, values: string[]) {
85
- return { name, schema, values };
87
+ return { name,
88
+ schema,
89
+ values };
86
90
  }
87
91
 
88
92
  // ── Drizzle schema objects (the "managed" schema) ───────────────────────
@@ -106,7 +110,8 @@ describe("Unmapped tables safety", () => {
106
110
  describe("tablesFilter scoping", () => {
107
111
 
108
112
  it("should extract only managed table names from the tables export", () => {
109
- const tables = { managedUsers, managedPosts };
113
+ const tables = { managedUsers,
114
+ managedPosts };
110
115
  const tableNames = Object.values(tables).map(t => getTableName(t as Table));
111
116
 
112
117
  expect(tableNames).toEqual(["users", "posts"]);
@@ -115,7 +120,8 @@ describe("Unmapped tables safety", () => {
115
120
  });
116
121
 
117
122
  it("should produce a tablesFilter that excludes unmapped tables", () => {
118
- const tables = { managedUsers, managedPosts };
123
+ const tables = { managedUsers,
124
+ managedPosts };
119
125
  const tablesFilter = Object.values(tables).map(t => getTableName(t as Table));
120
126
 
121
127
  const unmappedTables = [
@@ -209,7 +215,8 @@ describe("Unmapped tables safety", () => {
209
215
  })
210
216
  });
211
217
 
212
- const curJson = generateDrizzleJson({ managedUsers, managedPosts });
218
+ const curJson = generateDrizzleJson({ managedUsers,
219
+ managedPosts });
213
220
  const statements = await generateMigration(prevOnlyManaged as any, curJson as any);
214
221
 
215
222
  // No changes needed — managed schema is identical
@@ -276,7 +283,8 @@ describe("Unmapped tables safety", () => {
276
283
  name: "Posts",
277
284
  properties: {
278
285
  title: { type: "string" },
279
- tags: { type: "relation", relationName: "tags" }
286
+ tags: { type: "relation",
287
+ relationName: "tags" }
280
288
  },
281
289
  relations: [{
282
290
  relationName: "tags",
@@ -61,7 +61,7 @@ describe("WebSocket Server SQL error handling", () => {
61
61
  it("should handle EXECUTE_SQL errors cleanly and return ERROR message without throwing", async () => {
62
62
  expect(mockWssInstance).toBeDefined();
63
63
  expect(mockWssInstance.on).toHaveBeenCalledWith("connection", expect.any(Function));
64
-
64
+
65
65
  const connectionCallback = mockWssInstance.on.mock.calls.find(
66
66
  (call: any[]) => call[0] === "connection"
67
67
  )[1];
package/tsconfig.json CHANGED
@@ -1,5 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "ignoreDeprecations": "6.0",
4
+ "rootDir": ".",
3
5
  "outDir": "dist",
4
6
  "module": "ESNEXT",
5
7
  "target": "ESNEXT",
@@ -35,6 +37,9 @@
35
37
  ],
36
38
  "@rebasepro/common": [
37
39
  "../common/src"
40
+ ],
41
+ "@rebasepro/server-core": [
42
+ "../server-core/src"
38
43
  ]
39
44
  }
40
45
  },
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
+ "ignoreDeprecations": "6.0",
5
+ "rootDir": "./src",
6
+ "paths": {},
4
7
  "noEmit": false,
5
8
  "declaration": true,
6
9
  "emitDeclarationOnly": true,
package/vite.config.ts CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-ignore
2
1
  import path from "path";
3
2
 
4
3
  import { defineConfig } from "vite";
@@ -10,8 +9,8 @@ const ReactCompilerConfig = {
10
9
 
11
10
  /**
12
11
  * Only externalize dependencies that the consumer app installs directly.
13
- * Everything else (transitive deps like jsonwebtoken, ws, zod, etc.)
14
- * gets inlined so linked consumers work without installing them.
12
+ * Everything else gets inlined so linked consumers work without installing them.
13
+ * The createRequire banner in output config provides require() for inlined CJS deps.
15
14
  */
16
15
  const CONSUMER_EXTERNALS = [
17
16
  "hono",
@@ -33,8 +32,8 @@ const isExternal = (id: string) => {
33
32
  // Externalize only deps the consumer app explicitly installs
34
33
  if (CONSUMER_EXTERNALS.some(ext => id === ext || id.startsWith(ext + "/"))) return true;
35
34
  // Externalize Node built-ins
36
- if (["fs", "path", "url", "util", "crypto", "http", "https", "net", "tls", "stream", "events", "os", "child_process", "buffer", "assert", "dns", "zlib", "querystring", "node:"].some(b => id === b || id.startsWith("node:") || id.startsWith(b + "/"))) return true;
37
- // Inline everything else (jsonwebtoken, ws, zod, etc.)
35
+ if (["fs", "path", "url", "util", "crypto", "http", "https", "net", "tls", "stream", "events", "os", "child_process", "buffer", "assert", "dns", "zlib", "querystring", "process", "module", "worker_threads", "v8", "vm", "string_decoder", "node:"].some(b => id === b || id.startsWith("node:") || id.startsWith(b + "/"))) return true;
36
+ // Inline everything else — createRequire banner handles require() for CJS deps
38
37
  return false;
39
38
  };
40
39
 
@@ -54,6 +53,7 @@ export default defineConfig(() => ({
54
53
  rollupOptions: {
55
54
  external: isExternal,
56
55
  output: {
56
+ banner: 'import { createRequire as __createRequire } from "module"; import process from "process"; const require = __createRequire(import.meta.url);',
57
57
  globals: {
58
58
  "json-logic-js": "jsonLogic",
59
59
  "fast-equals": "fastEquals",
@@ -1,56 +0,0 @@
1
- import { EntityCollection } from "@rebasepro/types";
2
- export declare class CollectionRegistry {
3
- private collectionsByTableName;
4
- private collectionsBySlug;
5
- private rootCollections;
6
- private cachedCollectionsList;
7
- private rawCollectionsByTableName;
8
- private rawCollectionsBySlug;
9
- private rawRootCollections;
10
- private cachedRawCollectionsList;
11
- private lastRawInputSnapshot;
12
- constructor(collections?: EntityCollection[]);
13
- reset(): void;
14
- /**
15
- * Registers a collection and its subcollections recursively.
16
- * Returns true if the collections have changed, false otherwise.
17
- *
18
- * Idempotent: compares the raw input (before normalization) against a stored
19
- * snapshot. Only re-normalizes and re-registers when the raw input actually changed.
20
- * @param collections
21
- */
22
- registerMultiple(collections: EntityCollection[]): boolean;
23
- register(collection: EntityCollection, rawCollection?: EntityCollection): void;
24
- private _registerRecursively;
25
- normalizeCollection(collection: EntityCollection): EntityCollection;
26
- /**
27
- * Extract Relation[] from properties that have inline relation config (i.e. `target` is set).
28
- * This allows developers to define relations directly on properties without a separate
29
- * `relations[]` entry on the collection.
30
- */
31
- private extractRelationsFromProperties;
32
- private normalizeProperties;
33
- private normalizeProperty;
34
- get(path: string): EntityCollection | undefined;
35
- /**
36
- * Gets the pristine, un-normalized collection exactly as it was provided.
37
- * Useful for the AST editor so it doesn't accidentally serialize injected metadata back to disk.
38
- */
39
- getRaw(path: string): EntityCollection | undefined;
40
- /**
41
- * Get collection by resolving multi-segment paths through relations
42
- * e.g., "authors/70/posts" resolves to the posts collection
43
- */
44
- getCollectionByPath(collectionPath: string): EntityCollection | undefined;
45
- getCollections(): EntityCollection[];
46
- getRawCollections(): EntityCollection[];
47
- /**
48
- * Resolves a multi-segment path like "products/123/locales" and returns
49
- * information about the collections and entity IDs along the path
50
- */
51
- resolvePathToCollections(path: string): {
52
- collections: EntityCollection[];
53
- entityIds: (string | number)[];
54
- finalCollection: EntityCollection;
55
- };
56
- }
@@ -1,9 +0,0 @@
1
- import type { PostgresCollection } from "@rebasepro/types";
2
- /**
3
- * Default users collection.
4
- *
5
- * Prepended to the developer's collections array by the admin and server.
6
- * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers
7
- * override by defining their own collection with `slug: "users"`.
8
- */
9
- export declare const defaultUsersCollection: PostgresCollection;
@@ -1,2 +0,0 @@
1
- export * from "./CollectionRegistry";
2
- export * from "./default-collections";
@@ -1,14 +0,0 @@
1
- import { DataDriver, RebaseData } from "@rebasepro/types";
2
- /**
3
- * Build a `RebaseData` object from a `DataDriver` using JavaScript Proxy.
4
- *
5
- * This is the key bridge: any property access like `data.products` returns
6
- * a `CollectionAccessor` backed by the underlying DataDriver, without
7
- * needing per-collection code generation.
8
- *
9
- * @example
10
- * const data = buildRebaseData(driver);
11
- * await data.products.create({ name: "Camera", price: 299 });
12
- * const { data: items } = await data.products.find({ where: { status: "eq.published" } });
13
- */
14
- export declare function buildRebaseData(driver: DataDriver): RebaseData;
@@ -1,55 +0,0 @@
1
- import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator, LogicalCondition, WhereValue, FilterCondition } from "@rebasepro/types";
2
- export declare function or(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
3
- export declare function and(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
4
- export declare function cond(column: string, operator: FilterOperator, value: unknown): FilterCondition;
5
- export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {
6
- private collection;
7
- private params;
8
- constructor(collection: CollectionAccessor<M>);
9
- /**
10
- * Add a filter condition to your query.
11
- * @example
12
- * client.collection('users').where('age', '>=', 18).find()
13
- */
14
- where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;
15
- where(logicalCondition: LogicalCondition): this;
16
- /**
17
- * Order the results by a specific column.
18
- * @example
19
- * client.collection('users').orderBy('createdAt', 'desc').find()
20
- */
21
- orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
22
- /**
23
- * Limit the number of results returned.
24
- */
25
- limit(count: number): this;
26
- /**
27
- * Skip the first N results.
28
- */
29
- offset(count: number): this;
30
- /**
31
- * Set a free-text search string if supported by the backend.
32
- */
33
- search(searchString: string): this;
34
- /**
35
- * Include related entities in the response.
36
- * Relations will be populated with full entity data instead of just IDs.
37
- *
38
- * @param relations - Relation names to include, or "*" for all.
39
- * @example
40
- * // Include specific relations
41
- * client.data.posts.include("tags", "author").find()
42
- *
43
- * // Include all relations
44
- * client.data.posts.include("*").find()
45
- */
46
- include(...relations: string[]): this;
47
- /**
48
- * Execute the find query and return the results.
49
- */
50
- find(): Promise<FindResponse<M>>;
51
- /**
52
- * Listen to realtime updates matching this query.
53
- */
54
- listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
55
- }
@@ -1,4 +0,0 @@
1
- export * from "./util";
2
- export * from "./collections";
3
- export * from "./data/buildRebaseData";
4
- export * from "./data/query_builder";
@@ -1,57 +0,0 @@
1
- import { AdditionalFieldDelegate, ArrayProperty, BooleanProperty, DateProperty, EntityCallbacks, EntityCollection, EnumValueConfig, EnumValues, GeopointProperty, MapProperty, NumberProperty, Properties, Property, ReferenceProperty, StringProperty, User } from "@rebasepro/types";
2
- /**
3
- * Identity function we use to defeat the type system of Typescript and build
4
- * collection views with all its properties
5
- * @param collection
6
- * @group Builder
7
- */
8
- export declare function buildCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(collection: EntityCollection<M, USER>): EntityCollection<M, USER>;
9
- /**
10
- * Identity function we use to defeat the type system of Typescript and preserve
11
- * the property keys.
12
- * @param property
13
- * @group Builder
14
- */
15
- export declare function buildProperty<T, P extends Property = Property>(property: P): P extends StringProperty ? StringProperty : P extends NumberProperty ? NumberProperty : P extends BooleanProperty ? BooleanProperty : P extends DateProperty ? DateProperty : P extends GeopointProperty ? GeopointProperty : P extends ReferenceProperty ? ReferenceProperty : P extends ArrayProperty ? ArrayProperty : P extends MapProperty ? MapProperty : never;
16
- /**
17
- * Identity function we use to defeat the type system of Typescript and preserve
18
- * the properties keys.
19
- * @param properties
20
- * @group Builder
21
- */
22
- export declare function buildProperties<M extends Record<string, unknown>>(properties: Properties): Properties;
23
- /**
24
- * Identity function we use to defeat the type system of Typescript and preserve
25
- * the properties keys.
26
- * @param propertiesOrBuilder
27
- * @group Builder
28
- */
29
- export declare function buildPropertiesOrBuilder<M extends Record<string, unknown>>(propertiesOrBuilder: Properties): Properties;
30
- /**
31
- * Identity function we use to defeat the type system of Typescript and preserve
32
- * the properties keys.
33
- * @param enumValues
34
- * @group Builder
35
- */
36
- export declare function buildEnum(enumValues: EnumValues): EnumValues;
37
- /**
38
- * Identity function we use to defeat the type system of Typescript and preserve
39
- * the properties keys.
40
- * @param enumValueConfig
41
- * @group Builder
42
- */
43
- export declare function buildEnumValueConfig(enumValueConfig: EnumValueConfig): EnumValueConfig;
44
- /**
45
- * Identity function we use to defeat the type system of Typescript and preserve
46
- * the properties keys.
47
- * @param callbacks
48
- * @group Builder
49
- */
50
- export declare function buildEntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>>(callbacks: EntityCallbacks<M>): EntityCallbacks<M>;
51
- /**
52
- * Identity function we use to defeat the type system of Typescript and build
53
- * additional field delegates views with all its properties
54
- * @param additionalFieldDelegate
55
- * @group Builder
56
- */
57
- export declare function buildAdditionalFieldDelegate<M extends Record<string, unknown>, USER extends User = User>(additionalFieldDelegate: AdditionalFieldDelegate<M, USER>): AdditionalFieldDelegate<M, USER>;
@@ -1,6 +0,0 @@
1
- import { EntityCallbacks, Properties } from "@rebasepro/types";
2
- /**
3
- * Helper function to extract field-level PropertyCallbacks from a properties schema
4
- * and wrap them into an EntityCallbacks object recursively.
5
- */
6
- export declare const buildPropertyCallbacks: (properties: Properties) => EntityCallbacks | undefined;
@@ -1,11 +0,0 @@
1
- import { DefaultSelectedViewBuilder, DefaultSelectedViewParams, EntityCollection, Properties } from "@rebasepro/types";
2
- export declare function sortProperties<M extends Record<string, unknown>>(properties: Properties, propertiesOrder?: string[]): Properties;
3
- export declare function resolveDefaultSelectedView(defaultSelectedView: string | DefaultSelectedViewBuilder | undefined, params: DefaultSelectedViewParams): string | undefined;
4
- export declare function getLocalChangesBackup(collection: EntityCollection): "manual_apply" | "auto_apply";
5
- /**
6
- * Returns the primary keys for an entity collection by inspecting the properties
7
- * and finding any properties with `isId`.
8
- * Fallbacks to `["id"]` if no properties are marked as `isId: true`.
9
- * @param collection
10
- */
11
- export declare function getPrimaryKeys<M extends Record<string, unknown>>(collection: EntityCollection<M>): Extract<keyof M, string>[];
@@ -1,2 +0,0 @@
1
- export declare const DEFAULT_ONE_OF_TYPE = "type";
2
- export declare const DEFAULT_ONE_OF_VALUE = "value";
@@ -1,26 +0,0 @@
1
- import { AuthController, ConditionContext, JsonLogicRule, Property } from "@rebasepro/types";
2
- /**
3
- * Register custom JSON Logic operations for Rebase.
4
- * Call this once at app initialization.
5
- */
6
- export declare function registerConditionOperations(): void;
7
- /**
8
- * Evaluate a JSON Logic rule against the given context.
9
- */
10
- export declare function evaluateCondition(rule: JsonLogicRule, context: ConditionContext): unknown;
11
- /**
12
- * Build a ConditionContext from the current property resolution context.
13
- */
14
- export declare function buildConditionContext(params: {
15
- propertyKey?: string;
16
- values?: Record<string, unknown>;
17
- previousValues?: Record<string, unknown>;
18
- path: string;
19
- entityId?: string;
20
- index?: number;
21
- authController: AuthController;
22
- }): ConditionContext;
23
- /**
24
- * Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
25
- */
26
- export declare function applyPropertyConditions(property: Property, context: ConditionContext): Property;