@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
package/src/cli.ts CHANGED
@@ -5,6 +5,7 @@ import path from "path";
5
5
  import fs from "fs";
6
6
  import { execSync } from "child_process";
7
7
  import { fileURLToPath } from "url";
8
+ import { logger } from "@rebasepro/server-core";
8
9
 
9
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
11
 
@@ -40,7 +41,7 @@ export async function runPluginCommand(args: string[]) {
40
41
  } else if (domain === "doctor") {
41
42
  await doctorPluginCommand(args);
42
43
  } else {
43
- console.error(chalk.red(`Unknown domain command: ${domain}`));
44
+ logger.error(chalk.red(`Unknown domain command: ${domain}`));
44
45
  process.exit(1);
45
46
  }
46
47
  }
@@ -48,7 +49,7 @@ export async function runPluginCommand(args: string[]) {
48
49
  async function dbCommand(subcommand: string, rawArgs: string[]): Promise<void> {
49
50
  const VALID_ACTIONS = ["push", "generate", "migrate", "studio", "branch"];
50
51
  if (!subcommand || !VALID_ACTIONS.includes(subcommand)) {
51
- console.error(chalk.red(`Unknown db command. Valid: ${VALID_ACTIONS.join(", ")}`));
52
+ logger.error(chalk.red(`Unknown db command. Valid: ${VALID_ACTIONS.join(", ")}`));
52
53
  process.exit(1);
53
54
  }
54
55
 
@@ -58,44 +59,44 @@ async function dbCommand(subcommand: string, rawArgs: string[]): Promise<void> {
58
59
  }
59
60
 
60
61
  if (subcommand === "generate") {
61
- console.log("");
62
- console.log(chalk.bold(" 📦 Rebase DB Generate"));
63
- console.log(chalk.gray(" Step 1/2: Generating Drizzle schema from collections..."));
64
- console.log("");
62
+ logger.info("");
63
+ logger.info(chalk.bold(" 📦 Rebase DB Generate"));
64
+ logger.info(chalk.gray(" Step 1/2: Generating Drizzle schema from collections..."));
65
+ logger.info("");
65
66
  await schemaCommand("generate", rawArgs);
66
- console.log("");
67
- console.log(chalk.gray(" Step 2/2: Generating SQL migration files..."));
68
- console.log("");
67
+ logger.info("");
68
+ logger.info(chalk.gray(" Step 2/2: Generating SQL migration files..."));
69
+ logger.info("");
69
70
  await runDrizzleKit("generate", rawArgs);
70
71
  await fixMigrationStatementOrder();
71
- console.log("");
72
- console.log(` You can now run ${chalk.bold.green("rebase db migrate")} to apply the migrations to your database.`);
73
- console.log("");
72
+ logger.info("");
73
+ logger.info(` You can now run ${chalk.bold.green("rebase db migrate")} to apply the migrations to your database.`);
74
+ logger.info("");
74
75
  } else if (subcommand === "pull") {
75
- console.log("");
76
- console.log(chalk.yellow(" ⚠ \"rebase db pull\" has been removed."));
77
- console.log(chalk.gray(" Use \"rebase schema introspect\" instead."));
78
- console.log("");
76
+ logger.info("");
77
+ logger.info(chalk.yellow(" ⚠ \"rebase db pull\" has been removed."));
78
+ logger.info(chalk.gray(" Use \"rebase schema introspect\" instead."));
79
+ logger.info("");
79
80
  process.exit(1);
80
81
  } else {
81
- console.log("");
82
- console.log(chalk.bold(` 🗄️ Rebase DB ${subcommand.charAt(0).toUpperCase() + subcommand.slice(1)}`));
83
- console.log("");
82
+ logger.info("");
83
+ logger.info(chalk.bold(` 🗄️ Rebase DB ${subcommand.charAt(0).toUpperCase() + subcommand.slice(1)}`));
84
+ logger.info("");
84
85
 
85
86
  if (subcommand === "push") {
86
- console.log(chalk.gray(" Step 1/2: Generating Drizzle schema from collections..."));
87
- console.log("");
87
+ logger.info(chalk.gray(" Step 1/2: Generating Drizzle schema from collections..."));
88
+ logger.info("");
88
89
  await schemaCommand("generate", rawArgs);
89
- console.log("");
90
- console.log(chalk.gray(" Step 2/2: Pushing schema to database..."));
91
- console.log("");
90
+ logger.info("");
91
+ logger.info(chalk.gray(" Step 2/2: Pushing schema to database..."));
92
+ logger.info("");
92
93
  await runDrizzleKit("push", rawArgs);
93
94
  } else if (subcommand === "migrate") {
94
95
  await runDrizzleKit("migrate", rawArgs);
95
96
  } else if (subcommand === "studio") {
96
97
  const schemaPath = path.join(process.cwd(), "src", "schema.generated.ts");
97
98
  if (!fs.existsSync(schemaPath)) {
98
- console.log(chalk.yellow(" ⚠ schema.generated.ts not found. Generating schema first..."));
99
+ logger.info(chalk.yellow(" ⚠ schema.generated.ts not found. Generating schema first..."));
99
100
  await schemaCommand("generate", rawArgs);
100
101
  }
101
102
  await runDrizzleKit("studio", rawArgs);
@@ -103,9 +104,9 @@ async function dbCommand(subcommand: string, rawArgs: string[]): Promise<void> {
103
104
  await runDrizzleKit(subcommand, rawArgs);
104
105
  }
105
106
 
106
- console.log("");
107
- console.log(chalk.green(` ✓ rebase db ${subcommand} completed successfully.`));
108
- console.log("");
107
+ logger.info("");
108
+ logger.info(chalk.green(` ✓ rebase db ${subcommand} completed successfully.`));
109
+ logger.info("");
109
110
  }
110
111
  }
111
112
 
@@ -132,7 +133,7 @@ async function branchCommand(rawArgs: string[]): Promise<void> {
132
133
 
133
134
  const databaseUrl = process.env.DATABASE_URL || process.env.ADMIN_CONNECTION_STRING;
134
135
  if (!databaseUrl) {
135
- console.error(chalk.red("✗ DATABASE_URL is not set. Make sure your .env file is configured."));
136
+ logger.error(chalk.red("✗ DATABASE_URL is not set. Make sure your .env file is configured."));
136
137
  process.exit(1);
137
138
  }
138
139
 
@@ -156,8 +157,8 @@ max: 3 });
156
157
  case "create": {
157
158
  const name = rawArgs[3];
158
159
  if (!name) {
159
- console.error(chalk.red("✗ Branch name is required."));
160
- console.log(chalk.gray(" Usage: rebase db branch create <name> [--from <source>]"));
160
+ logger.error(chalk.red("✗ Branch name is required."));
161
+ logger.info(chalk.gray(" Usage: rebase db branch create <name> [--from <source>]"));
161
162
  process.exit(1);
162
163
  }
163
164
  let source: string | undefined;
@@ -165,81 +166,81 @@ max: 3 });
165
166
  if (fromIdx !== -1 && rawArgs[fromIdx + 1]) {
166
167
  source = rawArgs[fromIdx + 1];
167
168
  }
168
- console.log("");
169
- console.log(chalk.bold(" 🌿 Creating database branch..."));
170
- console.log(chalk.gray(` Name: ${name}`));
171
- if (source) console.log(chalk.gray(` Source: ${source}`));
172
- console.log("");
169
+ logger.info("");
170
+ logger.info(chalk.bold(" 🌿 Creating database branch..."));
171
+ logger.info(chalk.gray(` Name: ${name}`));
172
+ if (source) logger.info(chalk.gray(` Source: ${source}`));
173
+ logger.info("");
173
174
  const branch = await branchService.createBranch(name, source ? { source } : undefined);
174
- console.log(chalk.green(` ✓ Branch "${branch.name}" created successfully.`));
175
- console.log(chalk.gray(` Database: rb_${branch.name}`));
176
- console.log(chalk.gray(` Parent: ${branch.parentDatabase}`));
177
- console.log("");
175
+ logger.info(chalk.green(` ✓ Branch "${branch.name}" created successfully.`));
176
+ logger.info(chalk.gray(` Database: rb_${branch.name}`));
177
+ logger.info(chalk.gray(` Parent: ${branch.parentDatabase}`));
178
+ logger.info("");
178
179
  break;
179
180
  }
180
181
 
181
182
  case "list": {
182
183
  const branches = await branchService.listBranches();
183
- console.log("");
184
+ logger.info("");
184
185
  if (branches.length === 0) {
185
- console.log(chalk.gray(" No branches found. Create one with: rebase db branch create <name>"));
186
+ logger.info(chalk.gray(" No branches found. Create one with: rebase db branch create <name>"));
186
187
  } else {
187
- console.log(chalk.bold(` 🌿 ${branches.length} branch(es):`));
188
- console.log("");
188
+ logger.info(chalk.bold(` 🌿 ${branches.length} branch(es):`));
189
+ logger.info("");
189
190
  for (const b of branches) {
190
191
  const size = b.sizeBytes != null
191
192
  ? chalk.gray(` (${formatBytes(b.sizeBytes)})`)
192
193
  : "";
193
194
  const age = chalk.gray(` — created ${timeAgo(b.createdAt)}`);
194
- console.log(` ${chalk.green("●")} ${chalk.bold(b.name)}${size}${age}`);
195
- console.log(chalk.gray(` from ${b.parentDatabase}`));
195
+ logger.info(` ${chalk.green("●")} ${chalk.bold(b.name)}${size}${age}`);
196
+ logger.info(chalk.gray(` from ${b.parentDatabase}`));
196
197
  }
197
198
  }
198
- console.log("");
199
+ logger.info("");
199
200
  break;
200
201
  }
201
202
 
202
203
  case "delete": {
203
204
  const name = rawArgs[3];
204
205
  if (!name) {
205
- console.error(chalk.red("✗ Branch name is required."));
206
- console.log(chalk.gray(" Usage: rebase db branch delete <name>"));
206
+ logger.error(chalk.red("✗ Branch name is required."));
207
+ logger.info(chalk.gray(" Usage: rebase db branch delete <name>"));
207
208
  process.exit(1);
208
209
  }
209
- console.log("");
210
- console.log(chalk.bold(` 🗑️ Deleting branch "${name}"...`));
210
+ logger.info("");
211
+ logger.info(chalk.bold(` 🗑️ Deleting branch "${name}"...`));
211
212
  await branchService.deleteBranch(name);
212
- console.log(chalk.green(` ✓ Branch "${name}" deleted.`));
213
- console.log("");
213
+ logger.info(chalk.green(` ✓ Branch "${name}" deleted.`));
214
+ logger.info("");
214
215
  break;
215
216
  }
216
217
 
217
218
  case "info": {
218
219
  const name = rawArgs[3];
219
220
  if (!name) {
220
- console.error(chalk.red("✗ Branch name is required."));
221
- console.log(chalk.gray(" Usage: rebase db branch info <name>"));
221
+ logger.error(chalk.red("✗ Branch name is required."));
222
+ logger.info(chalk.gray(" Usage: rebase db branch info <name>"));
222
223
  process.exit(1);
223
224
  }
224
225
  const info = await branchService.getBranchInfo(name);
225
- console.log("");
226
+ logger.info("");
226
227
  if (!info) {
227
- console.error(chalk.red(` ✗ Branch "${name}" not found.`));
228
+ logger.error(chalk.red(` ✗ Branch "${name}" not found.`));
228
229
  } else {
229
- console.log(chalk.bold(` 🌿 Branch: ${info.name}`));
230
- console.log(chalk.gray(` Database: rb_${info.name}`));
231
- console.log(chalk.gray(` Parent: ${info.parentDatabase}`));
232
- console.log(chalk.gray(` Created: ${info.createdAt.toISOString()}`));
230
+ logger.info(chalk.bold(` 🌿 Branch: ${info.name}`));
231
+ logger.info(chalk.gray(` Database: rb_${info.name}`));
232
+ logger.info(chalk.gray(` Parent: ${info.parentDatabase}`));
233
+ logger.info(chalk.gray(` Created: ${info.createdAt.toISOString()}`));
233
234
  if (info.sizeBytes != null) {
234
- console.log(chalk.gray(` Size: ${formatBytes(info.sizeBytes)}`));
235
+ logger.info(chalk.gray(` Size: ${formatBytes(info.sizeBytes)}`));
235
236
  }
236
237
  }
237
- console.log("");
238
+ logger.info("");
238
239
  break;
239
240
  }
240
241
 
241
242
  default:
242
- console.error(chalk.red(`Unknown branch action: "${branchAction}".`));
243
+ logger.error(chalk.red(`Unknown branch action: "${branchAction}".`));
243
244
  printBranchHelp();
244
245
  process.exit(1);
245
246
  }
@@ -250,7 +251,7 @@ max: 3 });
250
251
  }
251
252
 
252
253
  function printBranchHelp() {
253
- console.log(`
254
+ logger.info(`
254
255
  ${chalk.bold("rebase db branch")} — Database branching commands
255
256
 
256
257
  ${chalk.green.bold("Usage")}
@@ -398,14 +399,16 @@ idx }));
398
399
  const reordered = stmtEntries.map(e => e.stmt).join(DELIMITER);
399
400
  fs.writeFileSync(latestFile, reordered, "utf-8");
400
401
 
401
- console.log(chalk.yellow(` \u26A0 Reordered migration statements in ${sqlFiles[0].name} (DROP POLICY before ALTER COLUMN)`));
402
+ logger.info(chalk.yellow(` \u26A0 Reordered migration statements in ${sqlFiles[0].name} (DROP POLICY before ALTER COLUMN)`));
402
403
  }
403
404
 
404
405
  async function runDrizzleKit(action: string, _rawArgs: string[]): Promise<void> {
405
406
  const drizzleKitBin = resolveLocalBin("drizzle-kit");
406
407
  if (!drizzleKitBin) {
407
- console.error(chalk.red("✗ Could not find drizzle-kit binary."));
408
- console.error(chalk.gray(" Install it with: pnpm add -D drizzle-kit"));
408
+ logger.error(chalk.red("✗ Could not find drizzle-kit binary."));
409
+ const isNpm = (process.env.npm_config_user_agent ?? "").startsWith("npm/") || fs.existsSync(path.join(process.cwd(), "package-lock.json"));
410
+ const installCmd = isNpm ? "npm install -D drizzle-kit" : "pnpm add -D drizzle-kit";
411
+ logger.error(chalk.gray(` Install it with: ${installCmd}`));
409
412
  process.exit(1);
410
413
  }
411
414
 
@@ -436,15 +439,28 @@ async function runDrizzleKit(action: string, _rawArgs: string[]): Promise<void>
436
439
  // dotenv may not be available — fall through
437
440
  }
438
441
 
439
- const interactive = ["generate", "push"].includes(action);
442
+ const interactive = ["generate", "push"].includes(action) && Boolean(process.stdout.isTTY);
440
443
 
441
444
  // For push: always use --strict (prompts before destructive ops) and --verbose
442
445
  // (shows all SQL). This ensures unmapped tables are never silently dropped.
443
446
  const drizzleKitArgs = [action];
444
447
  if (action === "push") {
445
448
  drizzleKitArgs.push("--strict", "--verbose");
446
- if (_rawArgs.includes("--force")) {
447
- drizzleKitArgs.push("--force");
449
+ }
450
+
451
+ // Forward any additional arguments, excluding schema-generator-specific options
452
+ const excludedFlags = ["--collections", "-c", "--output", "-o", "--watch", "-w"];
453
+ for (let i = 2; i < _rawArgs.length; i++) {
454
+ const arg = _rawArgs[i];
455
+ if (excludedFlags.includes(arg)) {
456
+ // Skip this flag and its value if it takes a parameter
457
+ if (["--collections", "-c", "--output", "-o"].includes(arg)) {
458
+ i++; // Skip the next arg (the value)
459
+ }
460
+ continue;
461
+ }
462
+ if (!drizzleKitArgs.includes(arg)) {
463
+ drizzleKitArgs.push(arg);
448
464
  }
449
465
  }
450
466
 
@@ -456,7 +472,7 @@ async function runDrizzleKit(action: string, _rawArgs: string[]): Promise<void>
456
472
  env
457
473
  });
458
474
  } else {
459
- const child = execa(drizzleKitBin, [action], {
475
+ const child = execa(drizzleKitBin, drizzleKitArgs, {
460
476
  cwd: process.cwd(),
461
477
  env,
462
478
  reject: false
@@ -473,23 +489,31 @@ async function runDrizzleKit(action: string, _rawArgs: string[]): Promise<void>
473
489
  const stdout = stripAnsi(result.stdout || "").trim();
474
490
  const stderr = stripAnsi(result.stderr || "").trim();
475
491
 
476
- if (result.exitCode !== 0) {
477
- console.error(chalk.red(`\n✗ drizzle-kit ${action} failed.\n`));
478
- const errorOutput = stderr || stdout;
479
- if (errorOutput) {
480
- const lines = errorOutput.split("\n").filter((l: string) => l.trim());
481
- let printedCount = 0;
482
- for (const line of lines) {
483
- if (line.toLowerCase().includes("error") || line.includes("cannot") || line.includes("already exists") || line.includes("does not exist") || line.includes("violates") || line.includes("permission denied")) {
484
- console.error(chalk.red(` ${line.trim()}`));
485
- printedCount++;
492
+ const hasTtyError = stdout.includes("Interactive prompts require a TTY terminal") ||
493
+ stderr.includes("Interactive prompts require a TTY terminal");
494
+
495
+ if (result.exitCode !== 0 || hasTtyError) {
496
+ logger.error(chalk.red(`\n✗ drizzle-kit ${action} failed.\n`));
497
+ if (hasTtyError) {
498
+ logger.error(chalk.red(" Error: Interactive prompts require a TTY terminal."));
499
+ logger.error(chalk.gray(" Please run with --force to skip interactive prompts or run in an interactive terminal."));
500
+ } else {
501
+ const errorOutput = stderr || stdout;
502
+ if (errorOutput) {
503
+ const lines = errorOutput.split("\n").filter((l: string) => l.trim());
504
+ let printedCount = 0;
505
+ for (const line of lines) {
506
+ if (line.toLowerCase().includes("error") || line.includes("cannot") || line.includes("already exists") || line.includes("does not exist") || line.includes("violates") || line.includes("permission denied")) {
507
+ logger.error(chalk.red(` ${line.trim()}`));
508
+ printedCount++;
509
+ }
510
+ }
511
+ if (printedCount === 0) {
512
+ lines.slice(0, 10).forEach(line => logger.error(chalk.red(` ${line.trim()}`)));
486
513
  }
487
- }
488
- if (printedCount === 0) {
489
- lines.slice(0, 10).forEach(line => console.error(chalk.red(` ${line.trim()}`)));
490
514
  }
491
515
  }
492
- console.error("");
516
+ logger.error("");
493
517
  process.exit(1);
494
518
  }
495
519
  }
@@ -498,17 +522,23 @@ async function runDrizzleKit(action: string, _rawArgs: string[]): Promise<void>
498
522
  // eslint-disable-next-line no-control-regex
499
523
  const stripAnsi = (s: string) => s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\[?[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣷⣯⣟⡿⢿⣻⣽]+\]\s*/g, "");
500
524
  const cleaned = stripAnsi(msg).trim();
501
- console.error(chalk.red(`\n✗ drizzle-kit ${action} failed.\n`));
502
- const lines = cleaned.split("\n").filter((l: string) => l.trim());
503
- for (const line of lines) {
504
- if (line.toLowerCase().includes("error") || line.includes("cannot") || line.includes("already exists") || line.includes("does not exist") || line.includes("violates")) {
505
- console.error(chalk.red(` ${line.trim()}`));
525
+ const hasTtyError = cleaned.includes("Interactive prompts require a TTY terminal");
526
+ logger.error(chalk.red(`\n✗ drizzle-kit ${action} failed.\n`));
527
+ if (hasTtyError) {
528
+ logger.error(chalk.red(" Error: Interactive prompts require a TTY terminal."));
529
+ logger.error(chalk.gray(" Please run with --force to skip interactive prompts or run in an interactive terminal."));
530
+ } else {
531
+ const lines = cleaned.split("\n").filter((l: string) => l.trim());
532
+ for (const line of lines) {
533
+ if (line.toLowerCase().includes("error") || line.includes("cannot") || line.includes("already exists") || line.includes("does not exist") || line.includes("violates")) {
534
+ logger.error(chalk.red(` ${line.trim()}`));
535
+ }
536
+ }
537
+ if (lines.length === 0) {
538
+ logger.error(chalk.gray(` ${cleaned}`));
506
539
  }
507
540
  }
508
- if (lines.length === 0) {
509
- console.error(chalk.gray(` ${cleaned}`));
510
- }
511
- console.error("");
541
+ logger.error("");
512
542
  process.exit(1);
513
543
  }
514
544
  }
@@ -534,13 +564,13 @@ async function schemaCommand(subcommand: string, rawArgs: string[]): Promise<voi
534
564
  // If installed in node_modules, __dirname is node_modules/@rebasepro/server-postgresql/dist or src.
535
565
  const generatorScript = path.join(__dirname, "schema", "generate-drizzle-schema.ts");
536
566
  if (!fs.existsSync(generatorScript)) {
537
- console.error(chalk.red(`✗ Could not find generate-drizzle-schema.ts at ${generatorScript}`));
567
+ logger.error(chalk.red(`✗ Could not find generate-drizzle-schema.ts at ${generatorScript}`));
538
568
  process.exit(1);
539
569
  }
540
570
 
541
571
  const tsxBin = resolveLocalBin("tsx");
542
572
  if (!tsxBin) {
543
- console.error(chalk.red("✗ Could not find tsx binary."));
573
+ logger.error(chalk.red("✗ Could not find tsx binary."));
544
574
  process.exit(1);
545
575
  }
546
576
 
@@ -548,9 +578,9 @@ async function schemaCommand(subcommand: string, rawArgs: string[]): Promise<voi
548
578
  const outputPath = argsList["--output"] || path.join("src", "schema.generated.ts");
549
579
  const watch = argsList["--watch"] || false;
550
580
 
551
- console.log("");
552
- console.log(chalk.bold(" 🔧 Rebase Schema Generator"));
553
- console.log("");
581
+ logger.info("");
582
+ logger.info(chalk.bold(" 🔧 Rebase Schema Generator"));
583
+ logger.info("");
554
584
 
555
585
  const cmdParts = [
556
586
  tsxBin,
@@ -569,7 +599,7 @@ async function schemaCommand(subcommand: string, rawArgs: string[]): Promise<voi
569
599
  env: { ...process.env as Record<string, string> }
570
600
  });
571
601
  } catch (err: unknown) {
572
- console.error(chalk.red(`✗ Failed to run schema generator: ${err instanceof Error ? err.message : String(err)}`));
602
+ logger.error(chalk.red(`✗ Failed to run schema generator: ${err instanceof Error ? err.message : String(err)}`));
573
603
  process.exit(1);
574
604
  }
575
605
  } else if (subcommand === "introspect") {
@@ -591,21 +621,21 @@ async function schemaCommand(subcommand: string, rawArgs: string[]): Promise<voi
591
621
 
592
622
  const introspectScript = path.join(__dirname, "schema", "introspect-db.ts");
593
623
  if (!fs.existsSync(introspectScript)) {
594
- console.error(chalk.red(`✗ Could not find introspect-db.ts at ${introspectScript}`));
624
+ logger.error(chalk.red(`✗ Could not find introspect-db.ts at ${introspectScript}`));
595
625
  process.exit(1);
596
626
  }
597
627
 
598
628
  const tsxBin = resolveLocalBin("tsx");
599
629
  if (!tsxBin) {
600
- console.error(chalk.red("✗ Could not find tsx binary."));
630
+ logger.error(chalk.red("✗ Could not find tsx binary."));
601
631
  process.exit(1);
602
632
  }
603
633
 
604
634
  const outputPath = argsList["--output"] || argsList["--collections"] || path.join("..", "config", "collections");
605
635
 
606
- console.log("");
607
- console.log(chalk.bold(" 🔍 Rebase Schema Introspector"));
608
- console.log("");
636
+ logger.info("");
637
+ logger.info(chalk.bold(" 🔍 Rebase Schema Introspector"));
638
+ logger.info("");
609
639
 
610
640
  const cmdParts = [
611
641
  tsxBin,
@@ -622,11 +652,11 @@ async function schemaCommand(subcommand: string, rawArgs: string[]): Promise<voi
622
652
  env: { ...process.env as Record<string, string> }
623
653
  });
624
654
  } catch (err: unknown) {
625
- console.error(chalk.red(`✗ Failed to run schema introspector: ${err instanceof Error ? err.message : String(err)}`));
655
+ logger.error(chalk.red(`✗ Failed to run schema introspector: ${err instanceof Error ? err.message : String(err)}`));
626
656
  process.exit(1);
627
657
  }
628
658
  } else {
629
- console.error(chalk.red("Unknown schema command."));
659
+ logger.error(chalk.red("Unknown schema command."));
630
660
  process.exit(1);
631
661
  }
632
662
  }
@@ -649,13 +679,13 @@ async function doctorPluginCommand(rawArgs: string[]): Promise<void> {
649
679
 
650
680
  const doctorScript = path.join(__dirname, "schema", "doctor-cli.ts");
651
681
  if (!fs.existsSync(doctorScript)) {
652
- console.error(chalk.red(`✗ Could not find doctor.ts at ${doctorScript}`));
682
+ logger.error(chalk.red(`✗ Could not find doctor.ts at ${doctorScript}`));
653
683
  process.exit(1);
654
684
  }
655
685
 
656
686
  const tsxBin = resolveLocalBin("tsx");
657
687
  if (!tsxBin) {
658
- console.error(chalk.red("✗ Could not find tsx binary."));
688
+ logger.error(chalk.red("✗ Could not find tsx binary."));
659
689
  process.exit(1);
660
690
  }
661
691
 
@@ -32,6 +32,13 @@ export class PostgresCollectionRegistry extends CollectionRegistry implements Co
32
32
  return this.tables.has(tableName);
33
33
  }
34
34
 
35
+ /**
36
+ * Returns all registered table names.
37
+ */
38
+ getTableNames(): string[] {
39
+ return Array.from(this.tables.keys());
40
+ }
41
+
35
42
  /**
36
43
  * Finds collections assigned to a specific driver that do not have a registered table.
37
44
  */
package/src/connection.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Pool, PoolConfig } from "pg";
2
2
  import { drizzle } from "drizzle-orm/node-postgres";
3
+ import { logger } from "@rebasepro/server-core";
3
4
 
4
5
  /**
5
6
  * Configuration for the Postgres connection pool.
@@ -69,9 +70,9 @@ export function createPostgresDatabaseConnection(
69
70
  // (a separate package). The caller can replace these with the structured
70
71
  // logger if desired via pool.on() after creation.
71
72
  pool.on("error", (err) => {
72
- console.error("[pg-pool] Unexpected pool error:", err.message);
73
+ logger.error("[pg-pool] Unexpected pool error", { detail: err.message });
73
74
  if (err.message.includes("ETIMEDOUT")) {
74
- console.warn("[pg-pool] Connection timeout detected — pool will auto-retry");
75
+ logger.warn("[pg-pool] Connection timeout detected — pool will auto-retry");
75
76
  }
76
77
  });
77
78
 
@@ -115,12 +116,14 @@ export function createDirectDatabaseConnection(
115
116
  const pool = new Pool(pgPoolConfig);
116
117
 
117
118
  pool.on("error", (err) => {
118
- console.error("[pg-direct-pool] Unexpected pool error:", err.message);
119
+ logger.error("[pg-direct-pool] Unexpected pool error", { detail: err.message });
119
120
  });
120
121
 
121
122
  const db = schema ? drizzle(pool, { schema }) : drizzle(pool);
122
123
 
123
- return { db, pool, connectionString };
124
+ return { db,
125
+ pool,
126
+ connectionString };
124
127
  }
125
128
 
126
129
  /**
@@ -152,10 +155,12 @@ export function createReadReplicaConnection(
152
155
  const pool = new Pool(pgPoolConfig);
153
156
 
154
157
  pool.on("error", (err) => {
155
- console.error("[pg-replica-pool] Unexpected pool error:", err.message);
158
+ logger.error("[pg-replica-pool] Unexpected pool error", { detail: err.message });
156
159
  });
157
160
 
158
161
  const db = schema ? drizzle(pool, { schema }) : drizzle(pool);
159
162
 
160
- return { db, pool, connectionString };
163
+ return { db,
164
+ pool,
165
+ connectionString };
161
166
  }