@rebasepro/server-postgres 0.12.1-canary.gf5f1d39 → 0.13.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 (92) hide show
  1. package/dist/PostgresBackendDriver.d.ts +1 -1
  2. package/dist/PostgresBootstrapper.d.ts +25 -1
  3. package/dist/auth/services.d.ts +21 -0
  4. package/dist/backup/backup-service.d.ts +10 -1
  5. package/dist/backup/pg-tools.d.ts +47 -0
  6. package/dist/backup-service-CD8o_1Sl.js +8999 -0
  7. package/dist/backup-service-CD8o_1Sl.js.map +1 -0
  8. package/dist/cli-helpers.d.ts +39 -0
  9. package/dist/connection-BuZ97wsr.js +250 -0
  10. package/dist/connection-BuZ97wsr.js.map +1 -0
  11. package/dist/connection.d.ts +42 -0
  12. package/dist/ensure-collection-policies-ViG8XiPn.js +57 -0
  13. package/dist/ensure-collection-policies-ViG8XiPn.js.map +1 -0
  14. package/dist/ensure-collection-tables-CBQdOETu.js +650 -0
  15. package/dist/ensure-collection-tables-CBQdOETu.js.map +1 -0
  16. package/dist/index.es.js +1231 -10031
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/policy-CeA1JcxP.js +105 -0
  19. package/dist/policy-CeA1JcxP.js.map +1 -0
  20. package/dist/schema/auth-schema.d.ts +83 -144
  21. package/dist/schema/ensure-collection-policies.d.ts +60 -0
  22. package/dist/schema/ensure-collection-tables.d.ts +44 -2
  23. package/dist/schema/generate-postgres-ddl-logic.d.ts +135 -1
  24. package/dist/schema/introspect-db-constraints.d.ts +57 -0
  25. package/dist/schema/introspect-db-logic.d.ts +94 -5
  26. package/dist/schema/introspect-db-queries.d.ts +119 -0
  27. package/dist/schema/introspect-db-structure.d.ts +263 -0
  28. package/dist/schema/introspect-db-types.d.ts +11 -0
  29. package/dist/services/FetchService.d.ts +4 -1
  30. package/dist/services/RelationService.d.ts +24 -1
  31. package/dist/services/channel-bus/index.d.ts +1 -7
  32. package/dist/services/collection-helpers.d.ts +36 -2
  33. package/dist/services/dataService.d.ts +3 -1
  34. package/dist/services/row-pipeline.d.ts +1 -1
  35. package/dist/{src-BbFOPJ1S.js → src-DlPBctw_.js} +299 -173
  36. package/dist/src-DlPBctw_.js.map +1 -0
  37. package/dist/{src-Zqwaw3P5.js → src-DoU9yPqq.js} +3 -159
  38. package/dist/src-DoU9yPqq.js.map +1 -0
  39. package/dist/utils/connection-string.d.ts +29 -0
  40. package/dist/utils/drizzle-conditions.d.ts +5 -4
  41. package/dist/utils/pg-error-utils.d.ts +35 -0
  42. package/dist/websocket-B2LsrINK.js +530 -0
  43. package/dist/websocket-B2LsrINK.js.map +1 -0
  44. package/package.json +14 -14
  45. package/src/PostgresAdapter.ts +21 -2
  46. package/src/PostgresBackendDriver.ts +4 -0
  47. package/src/PostgresBootstrapper.ts +192 -33
  48. package/src/auth/ensure-tables.ts +164 -9
  49. package/src/auth/services.ts +24 -2
  50. package/src/backup/backup-cli.ts +41 -2
  51. package/src/backup/backup-service.ts +38 -5
  52. package/src/backup/pg-tools.ts +96 -3
  53. package/src/cli-helpers.ts +70 -0
  54. package/src/cli.ts +44 -26
  55. package/src/collections/validate-relations.ts +15 -0
  56. package/src/connection.ts +73 -0
  57. package/src/data-transformer.ts +9 -3
  58. package/src/databasePoolManager.ts +5 -2
  59. package/src/schema/auth-schema.ts +30 -19
  60. package/src/schema/ensure-collection-policies.ts +105 -0
  61. package/src/schema/ensure-collection-tables.test.ts +105 -9
  62. package/src/schema/ensure-collection-tables.ts +220 -32
  63. package/src/schema/generate-drizzle-schema-logic.ts +42 -6
  64. package/src/schema/generate-postgres-ddl-logic.ts +382 -19
  65. package/src/schema/introspect-db-constraints.ts +385 -0
  66. package/src/schema/introspect-db-inference.ts +18 -8
  67. package/src/schema/introspect-db-logic.ts +385 -71
  68. package/src/schema/introspect-db-queries.ts +326 -0
  69. package/src/schema/introspect-db-structure.ts +670 -0
  70. package/src/schema/introspect-db-types.ts +56 -0
  71. package/src/schema/introspect-db.ts +37 -80
  72. package/src/schema/introspect-runtime.test.ts +56 -8
  73. package/src/schema/introspect-runtime.ts +31 -9
  74. package/src/security/policy-drift.test.ts +11 -3
  75. package/src/services/BranchService.ts +66 -28
  76. package/src/services/FetchService.ts +90 -14
  77. package/src/services/PersistService.ts +20 -6
  78. package/src/services/RelationService.ts +249 -48
  79. package/src/services/channel-bus/index.ts +0 -9
  80. package/src/services/collection-helpers.ts +69 -3
  81. package/src/services/dataService.ts +3 -1
  82. package/src/services/realtimeService.ts +3 -3
  83. package/src/services/row-pipeline.ts +1 -1
  84. package/src/utils/connection-string.ts +58 -0
  85. package/src/utils/drizzle-conditions.ts +31 -6
  86. package/src/utils/pg-error-utils.ts +65 -0
  87. package/src/websocket.ts +18 -9
  88. package/dist/chunk-DSJWtz9O.js +0 -40
  89. package/dist/ensure-collection-tables-CNTcZGvn.js +0 -304
  90. package/dist/ensure-collection-tables-CNTcZGvn.js.map +0 -1
  91. package/dist/src-BbFOPJ1S.js.map +0 -1
  92. package/dist/src-Zqwaw3P5.js.map +0 -1
@@ -105,7 +105,7 @@ export declare class PostgresBackendDriver implements DataDriver {
105
105
  delete<M extends Record<string, unknown>>({ row, collection }: DeleteProps<M>): Promise<void>;
106
106
  deleteAll(path: string): Promise<void>;
107
107
  checkUniqueField(path: string, name: string, value: unknown, id?: string, collection?: CollectionConfig): Promise<boolean>;
108
- count<M extends Record<string, unknown>>({ path, collection, filter, searchString }: FetchCollectionProps<M>): Promise<number>;
108
+ count<M extends Record<string, unknown>>({ path, collection, filter, logical, searchString }: FetchCollectionProps<M>): Promise<number>;
109
109
  private getTargetDb;
110
110
  executeSql(sqlText: string, options?: {
111
111
  database?: string;
@@ -4,7 +4,7 @@
4
4
  * Implements the `BackendBootstrapper` interface for PostgreSQL.
5
5
  */
6
6
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
7
- import { BackendBootstrapper, type RealtimeChannelsConfig } from "@rebasepro/types";
7
+ import { BackendBootstrapper, CollectionConfig, type RealtimeChannelsConfig } from "@rebasepro/types";
8
8
  import { PostgresBackendDriver } from "./PostgresBackendDriver";
9
9
  import { RealtimeService } from "./services/realtimeService";
10
10
  import { DatabasePoolManager } from "./databasePoolManager";
@@ -65,6 +65,30 @@ export interface PostgresDriverInternals {
65
65
  */
66
66
  provisionCdcForTables?: (tables: CdcTableRef[]) => Promise<void>;
67
67
  }
68
+ /**
69
+ * Which table name the boot-time drift check should look for, for one collection.
70
+ *
71
+ * A declared `table` IS the table name, not a hint to be second-guessed. This
72
+ * used to ask the registry whether it had indexed the declared name and fall
73
+ * back to the SLUG when it had not — but "the registry does not know this table"
74
+ * is exactly the condition the drift check exists to report, so the fallback
75
+ * fired precisely when it was most harmful.
76
+ *
77
+ * A collection with `slug: "usage-daily", table: "usage_daily"` was reported as
78
+ * missing table `usage-daily`: a name that does not exist, should never exist,
79
+ * and that nobody can find by looking. Worse, the remediation the caller prints
80
+ * says to run `rebase db push` — which would then CREATE that invented table
81
+ * beside the correct one, the same "second copy" hazard the misplaced-schema
82
+ * branch further down exists to prevent. Seen in production, where a correctly
83
+ * migrated database reported drift on every boot.
84
+ *
85
+ * The slug is used only when nothing was declared, which is the config shape
86
+ * where the slug genuinely is the table name.
87
+ *
88
+ * Exported for its own test: the caller needs a live pool and a real database,
89
+ * and this is the part that was wrong.
90
+ */
91
+ export declare function resolveDriftCheckName(col: CollectionConfig, registeredTableNames: string[]): string;
68
92
  /**
69
93
  * Default PostgreSQL bootstrapper.
70
94
  *
@@ -9,6 +9,27 @@ export interface AuthSchemaTables {
9
9
  appConfig: RebasePgTable;
10
10
  userIdentities: RebasePgTable;
11
11
  }
12
+ /**
13
+ * The single definition of what an email address looks like in storage.
14
+ *
15
+ * Reads have always folded case; writes did not, and normalising was left to
16
+ * each caller. That asymmetry is only ever one forgotten `.toLowerCase()` away
17
+ * from a row no lookup can find — the account exists, every sign-in path
18
+ * reports no such user, and the byte-exact UNIQUE on the column does not stop a
19
+ * duplicate differing only in case. Applied on both sides here so the guarantee
20
+ * belongs to the repository rather than to its callers' discipline; the
21
+ * `lower(email)` unique index added in `ensureAuthTablesExist` is the database
22
+ * half of the same rule.
23
+ *
24
+ * Whitespace goes too: a trailing space survives the fold and reproduces the
25
+ * problem exactly.
26
+ *
27
+ * Re-exported rather than defined here: `@rebasepro/server` and
28
+ * `@rebasepro/server-mongo` write this column too, and a second copy of this
29
+ * rule is the defect it exists to prevent.
30
+ */
31
+ import { normalizeEmail } from "@rebasepro/common";
32
+ export { normalizeEmail };
12
33
  /**
13
34
  * PostgreSQL implementation of UserRepository.
14
35
  * Handles all user-related database operations using Drizzle ORM.
@@ -1,5 +1,5 @@
1
1
  import type { StorageController } from "@rebasepro/server";
2
- import { BackupDestination, VersionCompatibility } from "./pg-tools";
2
+ import { BackupDestination, type RowSecurityIdentity, VersionCompatibility } from "./pg-tools";
3
3
  import { BackupObject, RetentionOptions } from "./retention";
4
4
  export declare class BackupToolError extends Error {
5
5
  readonly hint?: string | undefined;
@@ -54,6 +54,15 @@ export declare function createDump(opts: {
54
54
  inheritStdio?: boolean;
55
55
  includeGlobals?: boolean;
56
56
  env?: Record<string, string | undefined>;
57
+ /**
58
+ * Dump with row security left on, reading as this identity.
59
+ *
60
+ * The escape hatch for a managed Postgres, where the dumping role owns
61
+ * nothing and has no `BYPASSRLS`. Off by default, and deliberately so: with
62
+ * row security on, `pg_dump` stops erroring on rows it cannot see and
63
+ * simply omits them. See {@link RowSecurityIdentity}.
64
+ */
65
+ rowSecurity?: RowSecurityIdentity;
57
66
  }): Promise<BackupResult>;
58
67
  /**
59
68
  * Cheap integrity check on a freshly written dump: it must be non-empty and
@@ -79,6 +79,36 @@ export declare function parseBackupDestination(out: string): BackupDestination;
79
79
  * doubled slash.
80
80
  */
81
81
  export declare function joinStorageKey(prefix: string, fileName: string): string;
82
+ /**
83
+ * The identity `pg_dump` reads rows as, when row security is left on.
84
+ *
85
+ * Not optional, and that is the whole design. `pg_dump --enable-row-security`
86
+ * on its own is the dangerous command in this file: it turns the "query would
87
+ * be affected by row-level security policy" *error* into a dump that exits 0
88
+ * and is silently missing every row the dumping role's policies exclude. A
89
+ * backup that looks fine and restores most of your data is worse than one that
90
+ * refused to run.
91
+ *
92
+ * So the flag is unreachable without a subject to evaluate the policies
93
+ * against. Rebase's generated policies read `app.uid` and `app.user_roles`;
94
+ * supplying an admin role satisfies the `admin_full_access` rule and the dump
95
+ * sees everything that rule sees.
96
+ */
97
+ export interface RowSecurityIdentity {
98
+ /** Written to `app.uid`. Any non-empty value — it is only an audit trail. */
99
+ uid: string;
100
+ /** Written to `app.user_roles`. Must include a role the policies admit. */
101
+ roles: string[];
102
+ }
103
+ /**
104
+ * `PGOPTIONS` carrying an identity, for a libpq tool that has no other way to
105
+ * set a GUC.
106
+ *
107
+ * A backslash escape rather than quoting, which is what libpq's `-c` parsing
108
+ * takes: a space inside a value ends the option otherwise, so a role list is
109
+ * comma-joined and never spaced.
110
+ */
111
+ export declare function buildRowSecurityPgOptions(identity: RowSecurityIdentity): string;
82
112
  /**
83
113
  * Assemble the `pg_dump` argument vector. Uses the custom format (`-Fc`),
84
114
  * which is compressed and restorable selectively via `pg_restore`.
@@ -90,7 +120,24 @@ export declare function buildPgDumpArgs(opts: {
90
120
  excludeSchemas?: string[];
91
121
  /** Number of parallel jobs (directory format only; ignored for -Fc). */
92
122
  noOwner?: boolean;
123
+ /**
124
+ * Dump with row security on, as this identity. Omit — which is the default
125
+ * — and `pg_dump` errors rather than skipping rows it cannot see.
126
+ */
127
+ rowSecurity?: RowSecurityIdentity;
93
128
  }): string[];
129
+ /**
130
+ * Whether a `pg_dump` failure is the row-security one, and what to do about it.
131
+ *
132
+ * The error text names the table and nothing else, so the first read of it is
133
+ * "why would a backup be affected by RLS at all?" — the answer being that the
134
+ * dumping role is not the tables' owner and has no `BYPASSRLS`, which is the
135
+ * normal state of the `postgres` user on Cloud SQL, RDS and every other managed
136
+ * Postgres. Nothing about that is visible from the message.
137
+ *
138
+ * Returns `null` for any other failure, so the caller reports it unchanged.
139
+ */
140
+ export declare function diagnoseRowSecurityDumpFailure(error: unknown): string | null;
94
141
  /**
95
142
  * Assemble the `pg_restore` argument vector for a custom-format dump.
96
143
  */