@rebasepro/server-postgres 0.11.1-canary.gfd39654 → 0.12.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 (30) hide show
  1. package/dist/PostgresBootstrapper.d.ts +8 -0
  2. package/dist/collections/buildRegistry.d.ts +1 -1
  3. package/dist/{ensure-collection-tables-DGMYK0fr.js → ensure-collection-tables-CNTcZGvn.js} +3 -3
  4. package/dist/{ensure-collection-tables-DGMYK0fr.js.map → ensure-collection-tables-CNTcZGvn.js.map} +1 -1
  5. package/dist/history/HistoryService.d.ts +9 -29
  6. package/dist/index.es.js +397 -53
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/schema/dynamic-tables.d.ts +1 -1
  9. package/dist/schema/introspect-runtime.d.ts +1 -1
  10. package/dist/services/FetchService.d.ts +36 -1
  11. package/dist/services/row-pipeline.d.ts +3 -1
  12. package/dist/{src-3VmUJ8Xn.js → src-BbFOPJ1S.js} +197 -18
  13. package/dist/src-BbFOPJ1S.js.map +1 -0
  14. package/dist/{src-D5xBTl32.js → src-Zqwaw3P5.js} +136 -90
  15. package/dist/src-Zqwaw3P5.js.map +1 -0
  16. package/dist/utils/drizzle-conditions.d.ts +157 -3
  17. package/dist/utils/pg-error-utils.d.ts +6 -3
  18. package/package.json +6 -6
  19. package/src/PostgresBootstrapper.ts +23 -6
  20. package/src/collections/buildRegistry.ts +1 -1
  21. package/src/history/HistoryService.ts +13 -31
  22. package/src/schema/dynamic-tables.ts +1 -1
  23. package/src/schema/generate-drizzle-schema-logic.ts +10 -2
  24. package/src/schema/introspect-runtime.ts +1 -1
  25. package/src/services/FetchService.ts +79 -11
  26. package/src/services/row-pipeline.ts +3 -1
  27. package/src/utils/drizzle-conditions.ts +509 -45
  28. package/src/utils/pg-error-utils.ts +52 -3
  29. package/dist/src-3VmUJ8Xn.js.map +0 -1
  30. package/dist/src-D5xBTl32.js.map +0 -1
@@ -9,6 +9,35 @@
9
9
 
10
10
  import { logger } from "@rebasepro/server";
11
11
 
12
+ /**
13
+ * Shape of a deliberate client-facing error — `ApiError` from
14
+ * `@rebasepro/server`, or anything else carrying a 4xx `statusCode`.
15
+ *
16
+ * Matched structurally rather than with `instanceof`: `@rebasepro/server` can
17
+ * be loaded twice (published dist vs. workspace source), which breaks class
18
+ * identity — `PersistService` hedges against the same thing by also accepting
19
+ * `name === "ApiError"`.
20
+ */
21
+ interface ClientFacingError extends Error {
22
+ statusCode?: number;
23
+ code?: string;
24
+ /** See `ApiError.expected` — routine outcomes log at debug, not warn. */
25
+ expected?: boolean;
26
+ }
27
+
28
+ /**
29
+ * Return the error when it is a deliberate 4xx, otherwise null.
30
+ *
31
+ * A thrown `ApiError` is a decision the server made about the request, not a
32
+ * database failure: its message and code are already written for the client.
33
+ */
34
+ function asClientFacingError(error: unknown): ClientFacingError | null {
35
+ if (!(error instanceof Error)) return null;
36
+ const e = error as ClientFacingError;
37
+ if (typeof e.statusCode !== "number" || e.statusCode < 400 || e.statusCode >= 500) return null;
38
+ return e;
39
+ }
40
+
12
41
  /** Shape of PostgreSQL errors with diagnostic metadata. */
13
42
  export interface PostgresError extends Error {
14
43
  code?: string;
@@ -180,14 +209,34 @@ export function pgErrorToFriendlyMessage(pgError: PostgresError, context: string
180
209
  /**
181
210
  * Sanitize any error into a message safe and helpful for the client.
182
211
  *
183
- * Extracts the PG error from the Drizzle cause chain when possible;
184
- * falls back to a generic message that doesn't leak SQL.
212
+ * A deliberate 4xx (`ApiError`) passes through untouched the server already
213
+ * decided what the client should read. Otherwise the PG error is extracted
214
+ * from the Drizzle cause chain, falling back to a generic message that
215
+ * doesn't leak SQL.
185
216
  *
186
217
  * @param error - The raw caught error
187
218
  * @param context - A human-readable context string (e.g. collection path)
188
- * @returns An object with `message` (user-friendly) and optional `code` (PG code).
219
+ * @returns An object with `message` (user-friendly) and optional `code`
220
+ * (the `ApiError` code, or the PG SQLSTATE).
189
221
  */
190
222
  export function sanitizeErrorForClient(error: unknown, context: string): { message: string; code?: string } {
223
+ // ── A deliberate 4xx is not a database failure ──────────────────
224
+ // Its message and code are written for the client; replacing them with
225
+ // "Check server logs" would discard the only diagnosis the caller gets
226
+ // (e.g. the offending filter field and the collection's valid ones).
227
+ // Log level follows the same convention as the HTTP error handler in
228
+ // @rebasepro/server: routine outcomes at debug, everything else at warn.
229
+ const clientError = asClientFacingError(error);
230
+ if (clientError) {
231
+ const line = `[API ${clientError.statusCode} ${clientError.code ?? "BAD_REQUEST"}] in "${context}": ${clientError.message}`;
232
+ if (clientError.expected) {
233
+ logger.debug(line);
234
+ } else {
235
+ logger.warn(`⚠️ ${line}`);
236
+ }
237
+ return { message: clientError.message, ...(clientError.code && { code: clientError.code }) };
238
+ }
239
+
191
240
  // ── Always log the full, unsanitized error server-side ──────────
192
241
  const pgError = extractPgError(error);
193
242