@rebasepro/server-postgres 0.15.0 → 0.16.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 (45) hide show
  1. package/dist/PostgresBackendDriver.d.ts +1 -1
  2. package/dist/PostgresBootstrapper.d.ts +0 -11
  3. package/dist/auth/services.d.ts +2 -2
  4. package/dist/{auth-users-columns-JJ8ngvy5.js → auth-users-columns-CgyPWQ18.js} +3 -3
  5. package/dist/auth-users-columns-CgyPWQ18.js.map +1 -0
  6. package/dist/backup/backup-logic.d.ts +20 -0
  7. package/dist/backup/backup-service.d.ts +6 -0
  8. package/dist/backup/retention.d.ts +11 -0
  9. package/dist/{backup-service-czK-OAuG.js → backup-service-BZoixhVl.js} +56 -11
  10. package/dist/backup-service-BZoixhVl.js.map +1 -0
  11. package/dist/collections-schema-version-BMeu3cgv.js +81 -0
  12. package/dist/collections-schema-version-BMeu3cgv.js.map +1 -0
  13. package/dist/{ensure-collection-policies-D5PtQLyR.js → ensure-collection-policies-BVFb2olB.js} +4 -3
  14. package/dist/ensure-collection-policies-BVFb2olB.js.map +1 -0
  15. package/dist/{ensure-collection-tables-BHUjQ-z4.js → ensure-collection-tables-BY1pHRD_.js} +2 -2
  16. package/dist/{ensure-collection-tables-BHUjQ-z4.js.map → ensure-collection-tables-BY1pHRD_.js.map} +1 -1
  17. package/dist/index.es.js +65 -21
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/{rls-enforcement-BDBfuTD4.js → rls-enforcement-Ch0T6OwW.js} +7 -7
  20. package/dist/rls-enforcement-Ch0T6OwW.js.map +1 -0
  21. package/dist/schema/collections-schema-version.d.ts +32 -0
  22. package/dist/security/policy-drift.d.ts +2 -2
  23. package/dist/security/rls-enforcement.d.ts +6 -6
  24. package/dist/services/realtimeService.d.ts +3 -1
  25. package/dist/src-BBFsDaeA.js.map +1 -1
  26. package/dist/websocket-BVgDVO-V.js.map +1 -1
  27. package/package.json +6 -6
  28. package/src/PostgresAdapter.ts +14 -0
  29. package/src/PostgresBackendDriver.ts +3 -3
  30. package/src/PostgresBootstrapper.ts +82 -12
  31. package/src/auth/services.ts +2 -2
  32. package/src/backup/backup-cli.ts +49 -12
  33. package/src/backup/backup-logic.ts +31 -0
  34. package/src/backup/backup-service.ts +42 -8
  35. package/src/backup/pg-tools.ts +12 -1
  36. package/src/backup/retention.ts +11 -0
  37. package/src/schema/collections-schema-version.ts +103 -0
  38. package/src/security/policy-drift.test.ts +25 -6
  39. package/src/security/policy-drift.ts +14 -6
  40. package/src/security/rls-enforcement.ts +7 -7
  41. package/src/services/realtimeService.ts +9 -1
  42. package/dist/auth-users-columns-JJ8ngvy5.js.map +0 -1
  43. package/dist/backup-service-czK-OAuG.js.map +0 -1
  44. package/dist/ensure-collection-policies-D5PtQLyR.js.map +0 -1
  45. package/dist/rls-enforcement-BDBfuTD4.js.map +0 -1
@@ -30,7 +30,7 @@ import { logger } from "@rebasepro/server";
30
30
  * that driver with `withAuth(SERVICE_IDENTITY)`, so it arrives as user
31
31
  * context above — `rebase_user`, `app.uid = 'service'`, policies evaluated —
32
32
  * and clears the default policies through their admin arm rather than the
33
- * `auth.uid() IS NULL` one.
33
+ * `rebase.uid() IS NULL` one.
34
34
  *
35
35
  * This module provides the three pieces:
36
36
  *
@@ -40,7 +40,7 @@ import { logger } from "@rebasepro/server";
40
40
  * SELECT/INSERT/UPDATE/DELETE grants (+ default privileges so future
41
41
  * tables stay covered).
42
42
  * 3. {@link applyAuthContext} — per-transaction: set the `app.*` GUCs the
43
- * policies read (`auth.uid()` etc.) and `SET LOCAL ROLE rebase_user` so
43
+ * policies read (`rebase.uid()` etc.) and `SET LOCAL ROLE rebase_user` so
44
44
  * RLS binds. Transaction-scoped, so it composes with poolers.
45
45
  *
46
46
  * Provisioning runs from the framework's own bootstrap/migrate (which already
@@ -271,7 +271,7 @@ export async function ensureAppRole(run: RawSqlRunner, schemas: string[]): Promi
271
271
 
272
272
  /**
273
273
  * Apply the authenticated context to a transaction: the `app.*` GUCs that RLS
274
- * policies read via `auth.uid()` / `auth.roles()` / `auth.jwt()`, and — when
274
+ * policies read via `rebase.uid()` / `rebase.roles()` / `rebase.jwt()`, and — when
275
275
  * `userRole` is set — `SET LOCAL ROLE` so RLS binds every statement in this
276
276
  * transaction (reads *and* writes).
277
277
  *
@@ -283,13 +283,13 @@ export async function ensureAppRole(run: RawSqlRunner, schemas: string[]): Promi
283
283
  *
284
284
  * SECURITY: this function is only ever called on the **user** path (the server
285
285
  * context uses the base/owner driver and never calls it). The default policies
286
- * treat `auth.uid() IS NULL` as the trusted server context, and `auth.uid()`
286
+ * treat `rebase.uid() IS NULL` as the trusted server context, and `rebase.uid()`
287
287
  * is `NULLIF(current_setting('app.uid'), '')` — so an EMPTY user id would
288
288
  * be read as NULL and silently escalate a user request to server privileges.
289
289
  * Coerce empty/blank ids to `ANONYMOUS_USER_ID` here, at the single chokepoint,
290
290
  * rather than trusting every caller (e.g. realtime subscription auth) to do it.
291
291
  * That sentinel is exported from `@rebasepro/types` because it leaks into rule
292
- * semantics: it is why `auth.uid() IS NOT NULL` is true for anonymous requests.
292
+ * semantics: it is why `rebase.uid() IS NOT NULL` is true for anonymous requests.
293
293
  */
294
294
  export async function applyAuthContext(tx: SqlTx, auth: AuthContext, userRole?: string): Promise<void> {
295
295
  const uid = typeof auth.uid === "string" && auth.uid.trim() !== "" ? auth.uid : ANONYMOUS_USER_ID;
@@ -322,7 +322,7 @@ const FOREIGN_CONVENTION_ROLES: Record<string, string> = {
322
322
 
323
323
  /**
324
324
  * Warn about rules that read as "signed-in users only" but admit anonymous
325
- * callers — `auth.uid() IS NOT NULL`, or a comparison against another
325
+ * callers — `rebase.uid() IS NOT NULL`, or a comparison against another
326
326
  * platform's magic user id such as `'anon'`.
327
327
  *
328
328
  * The sibling of {@link validatePolicyPgRoles}, for the more dangerous spelling
@@ -486,7 +486,7 @@ export async function validatePolicyPgRoles(
486
486
  : "no such role exists in this database";
487
487
  const platform = FOREIGN_CONVENTION_ROLES[role];
488
488
  const hint = platform
489
- ? `"${role}" is a ${platform} convention, not a PostgreSQL role. Application roles belong in \`roles: ["${role === "service_role" ? "admin" : role}"]\`, which is checked inside the policy via auth.roles().`
489
+ ? `"${role}" is a ${platform} convention, not a PostgreSQL role. Application roles belong in \`roles: ["${role === "service_role" ? "admin" : role}"]\`, which is checked inside the policy via rebase.roles().`
490
490
  : `Either grant it (GRANT ${role} TO ${requestRole}) or drop \`pgRoles\` so the policy targets \`public\`.`;
491
491
 
492
492
  problems.push(
@@ -1782,9 +1782,17 @@ roles: activeAuth.roles },
1782
1782
  * inert, no schema is created, and broadcast keeps its original
1783
1783
  * fire-and-forget path.
1784
1784
  */
1785
- async configureChannelHistory(rules: ChannelRetentionRule[] | undefined): Promise<void> {
1785
+ async configureChannelHistory(
1786
+ rules: ChannelRetentionRule[] | undefined,
1787
+ options?: { provision?: boolean }
1788
+ ): Promise<void> {
1789
+ // The store is built in every process, whether or not this one creates
1790
+ // the tables: retaining a message is what a process does when it
1791
+ // *publishes* to a retained channel, and a function handler publishes as
1792
+ // readily as a websocket client does. Only the DDL is owned.
1786
1793
  this.channelHistory = new ChannelHistoryStore(this.db, rules ?? []);
1787
1794
  if (!this.channelHistory.enabled) return;
1795
+ if (options?.provision === false) return;
1788
1796
  await this.channelHistory.ensureTables();
1789
1797
  }
1790
1798