@rebasepro/server-postgres 0.17.3-canary.gdd23447 → 0.18.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 (149) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +31 -0
  3. package/dist/backup-argv.d.ts +19 -0
  4. package/dist/branch-argv.d.ts +28 -0
  5. package/dist/branch-prune.d.ts +77 -0
  6. package/dist/cli-collections-path.d.ts +31 -0
  7. package/dist/cli-errors.d.ts +123 -0
  8. package/dist/cli-flags.d.ts +101 -0
  9. package/dist/cli-helpers.d.ts +94 -10
  10. package/dist/collection-index-C7LopMyX.js +247 -0
  11. package/dist/collection-index-C7LopMyX.js.map +1 -0
  12. package/dist/databasePoolManager.d.ts +27 -0
  13. package/dist/{ensure-collection-policies-UCqgv_8c.js → ensure-collection-policies-CagOzEPS.js} +6 -6
  14. package/dist/{ensure-collection-policies-UCqgv_8c.js.map → ensure-collection-policies-CagOzEPS.js.map} +1 -1
  15. package/dist/{ensure-collection-tables-DgVixhX3.js → ensure-collection-tables-DbAhrjnG.js} +614 -52
  16. package/dist/ensure-collection-tables-DbAhrjnG.js.map +1 -0
  17. package/dist/index.d.ts +12 -0
  18. package/dist/index.es.js +19307 -3059
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/{rls-enforcement-DvAbL9YJ.js → rls-enforcement-ClJoTboT.js} +53 -189
  21. package/dist/rls-enforcement-ClJoTboT.js.map +1 -0
  22. package/dist/schema/column-type-drift.d.ts +79 -0
  23. package/dist/schema/doctor.d.ts +42 -0
  24. package/dist/schema/ensure-collection-tables.d.ts +90 -0
  25. package/dist/schema/generate-next-step.d.ts +30 -0
  26. package/dist/schema/generate-postgres-ddl-logic.d.ts +28 -0
  27. package/dist/schema/generated-schema-staleness.d.ts +37 -0
  28. package/dist/schema/introspect-db-queries.d.ts +34 -0
  29. package/dist/security/rls-enforcement.d.ts +63 -2
  30. package/dist/services/BranchService.d.ts +86 -1
  31. package/dist/services/collection-helpers.d.ts +1 -1
  32. package/dist/services/realtimeService.d.ts +30 -2
  33. package/dist/services/row-pipeline.d.ts +12 -1
  34. package/dist/utils/pg-error-utils.d.ts +3 -1
  35. package/dist/utils/pg-numeric-number-patch.d.ts +31 -0
  36. package/package.json +32 -27
  37. package/dist/backup-service-DCk7KhhL.js +0 -9044
  38. package/dist/backup-service-DCk7KhhL.js.map +0 -1
  39. package/dist/collection-index-BRUg10H5.js +0 -5690
  40. package/dist/collection-index-BRUg10H5.js.map +0 -1
  41. package/dist/connection-GOKU3Hu5.js +0 -277
  42. package/dist/connection-GOKU3Hu5.js.map +0 -1
  43. package/dist/ensure-collection-tables-DgVixhX3.js.map +0 -1
  44. package/dist/rls-bootstrap-sql-B5C9LoJ6.js +0 -244
  45. package/dist/rls-bootstrap-sql-B5C9LoJ6.js.map +0 -1
  46. package/dist/rls-enforcement-DvAbL9YJ.js.map +0 -1
  47. package/dist/src-DiB5RP2Z.js +0 -541
  48. package/dist/src-DiB5RP2Z.js.map +0 -1
  49. package/dist/websocket-BZ4H5wUz.js +0 -8198
  50. package/dist/websocket-BZ4H5wUz.js.map +0 -1
  51. package/src/PostgresAdapter.ts +0 -91
  52. package/src/PostgresBackendDriver.ts +0 -1857
  53. package/src/PostgresBootstrapper.ts +0 -1157
  54. package/src/auth/ensure-tables.ts +0 -896
  55. package/src/auth/schema-version.ts +0 -260
  56. package/src/auth/services.ts +0 -1610
  57. package/src/backup/backup-cli.ts +0 -520
  58. package/src/backup/backup-cron.ts +0 -212
  59. package/src/backup/backup-logic.ts +0 -93
  60. package/src/backup/backup-service.ts +0 -485
  61. package/src/backup/index.ts +0 -12
  62. package/src/backup/pg-tools.ts +0 -403
  63. package/src/backup/retention.ts +0 -86
  64. package/src/cli-errors.ts +0 -265
  65. package/src/cli-helpers.ts +0 -569
  66. package/src/cli-output.ts +0 -43
  67. package/src/cli.ts +0 -1339
  68. package/src/collections/PostgresCollectionRegistry.ts +0 -108
  69. package/src/collections/buildRegistry.ts +0 -68
  70. package/src/collections/validate-relations.ts +0 -402
  71. package/src/connection.ts +0 -333
  72. package/src/data-transformer.ts +0 -845
  73. package/src/databasePoolManager.ts +0 -95
  74. package/src/history/HistoryService.ts +0 -254
  75. package/src/history/ensure-history-table.ts +0 -53
  76. package/src/index.ts +0 -19
  77. package/src/interfaces.ts +0 -60
  78. package/src/module-dir.ts +0 -7
  79. package/src/schema/atlas-argv.ts +0 -94
  80. package/src/schema/auth-schema.ts +0 -298
  81. package/src/schema/auth-users-columns.ts +0 -131
  82. package/src/schema/carved-out-migration.ts +0 -404
  83. package/src/schema/classify-change.ts +0 -436
  84. package/src/schema/collection-index.ts +0 -427
  85. package/src/schema/collections-schema-version.ts +0 -103
  86. package/src/schema/destructive-sql.ts +0 -94
  87. package/src/schema/doctor-cli.ts +0 -66
  88. package/src/schema/doctor-policy-checks.ts +0 -105
  89. package/src/schema/doctor.ts +0 -837
  90. package/src/schema/drizzle-ddl.ts +0 -33
  91. package/src/schema/dynamic-tables.test.ts +0 -302
  92. package/src/schema/dynamic-tables.ts +0 -293
  93. package/src/schema/ensure-collection-policies.ts +0 -198
  94. package/src/schema/ensure-collection-tables.test.ts +0 -518
  95. package/src/schema/ensure-collection-tables.ts +0 -1267
  96. package/src/schema/generate-drizzle-schema-logic.ts +0 -957
  97. package/src/schema/generate-drizzle-schema.ts +0 -143
  98. package/src/schema/generate-postgres-ddl-logic.ts +0 -1339
  99. package/src/schema/generate-postgres-ddl.ts +0 -180
  100. package/src/schema/generate-schema-commit.ts +0 -267
  101. package/src/schema/generated-schema-staleness.ts +0 -284
  102. package/src/schema/introspect-db-constraints.ts +0 -385
  103. package/src/schema/introspect-db-inference.ts +0 -255
  104. package/src/schema/introspect-db-logic.ts +0 -1387
  105. package/src/schema/introspect-db-naming.ts +0 -15
  106. package/src/schema/introspect-db-project.ts +0 -78
  107. package/src/schema/introspect-db-queries.ts +0 -326
  108. package/src/schema/introspect-db-structure.ts +0 -670
  109. package/src/schema/introspect-db-types.ts +0 -56
  110. package/src/schema/introspect-db.ts +0 -257
  111. package/src/schema/introspect-runtime.test.ts +0 -260
  112. package/src/schema/introspect-runtime.ts +0 -327
  113. package/src/schema/non-sql-collections.test.ts +0 -131
  114. package/src/schema/rls-bootstrap-sql.ts +0 -288
  115. package/src/schema/search-column.ts +0 -643
  116. package/src/schema/test-schema.ts +0 -11
  117. package/src/schema/vector-index.ts +0 -491
  118. package/src/security/anonymous-grants.test.ts +0 -73
  119. package/src/security/policy-drift.test.ts +0 -435
  120. package/src/security/policy-drift.ts +0 -473
  121. package/src/security/rls-enforcement.ts +0 -505
  122. package/src/services/BranchService.ts +0 -326
  123. package/src/services/FetchService.ts +0 -2115
  124. package/src/services/PersistService.ts +0 -557
  125. package/src/services/RelationService.ts +0 -978
  126. package/src/services/RelationWriteService.ts +0 -653
  127. package/src/services/cdc/CdcListener.ts +0 -103
  128. package/src/services/cdc/junction-tables.ts +0 -91
  129. package/src/services/cdc/trigger-cdc.ts +0 -173
  130. package/src/services/channel-bus/ChannelBus.ts +0 -44
  131. package/src/services/channel-bus/PostgresChannelBus.ts +0 -299
  132. package/src/services/channel-bus/index.ts +0 -114
  133. package/src/services/channel-history.ts +0 -424
  134. package/src/services/channel-presence.ts +0 -185
  135. package/src/services/collection-helpers.ts +0 -420
  136. package/src/services/dataService.ts +0 -256
  137. package/src/services/index.ts +0 -14
  138. package/src/services/junction-writes.ts +0 -295
  139. package/src/services/nested-path.ts +0 -145
  140. package/src/services/pg-notify-listener.ts +0 -151
  141. package/src/services/realtimeService.ts +0 -2545
  142. package/src/services/row-pipeline.ts +0 -240
  143. package/src/services/write-denial.ts +0 -55
  144. package/src/types.ts +0 -4
  145. package/src/utils/connection-string.ts +0 -58
  146. package/src/utils/drizzle-conditions.ts +0 -2743
  147. package/src/utils/pg-array-null-patch.ts +0 -42
  148. package/src/utils/pg-error-utils.ts +0 -391
  149. package/src/websocket.ts +0 -855
@@ -1,198 +0,0 @@
1
- /**
2
- * Applying a bundle's RLS policies to a database at boot, idempotently.
3
- *
4
- * ## Why this exists
5
- *
6
- * {@link ensureCollectionTables} creates the collection *tables* a managed
7
- * runtime boots against, but a table with row-level security disabled and no
8
- * policies is not servable: authenticated requests run as the restricted
9
- * `rebase_user` role, so a read with no `SELECT` policy returns nothing (a
10
- * public collection answered 401) and a write with no `INSERT`/`UPDATE` policy
11
- * is denied. The policies live in the collections' `securityRules`; nothing at
12
- * boot applied them. `rebase db push` does — but it drives Atlas against a
13
- * local `DATABASE_URL`, and a managed tenant's database is reachable only from
14
- * inside the cluster, by the runtime that is already connected to it. So the
15
- * runtime is the only thing that *can* apply them, and this is where it does.
16
- *
17
- * ## Why this is safe to run on every boot
18
- *
19
- * Every statement is idempotent: `ENABLE ROW LEVEL SECURITY` is a no-op once
20
- * enabled, and each policy is a `DROP POLICY IF EXISTS` immediately followed by
21
- * a `CREATE POLICY`, so re-applying asserts exactly the declared state. It adds
22
- * and replaces; it never drops data. (It does not *reconcile* — a policy a
23
- * previous push left behind under an old name is not removed here; that stays a
24
- * `db push` / `db migrate` concern, alongside destructive schema changes.)
25
- *
26
- * Unlike table creation, a failure here is not fatal: RLS stays enabled, so a
27
- * table whose policies could not be applied fails **closed** (denies) rather
28
- * than leaking rows. One collection's policy failing (e.g. a rule that
29
- * references a table a real migration has not created yet) must not crash-loop
30
- * the whole deployment and take the other collections' working routes down with
31
- * it. Failures are reported loudly and per-table so the operator can see
32
- * exactly which collection is not yet servable and why.
33
- */
34
- import { type CollectionConfig } from "@rebasepro/types";
35
- import { planCollectionPolicies, type CollectionPolicyPlan } from "./generate-postgres-ddl-logic";
36
- import { isGeneratedPolicyName } from "../security/policy-drift";
37
- import { readExistingSchema, type Queryable } from "./ensure-collection-tables";
38
- import { REBASE_USER_ROLE } from "../security/rls-enforcement";
39
-
40
- export interface PolicyEnsureResult {
41
- /** `CREATE POLICY` statements that ran successfully. */
42
- policiesApplied: number;
43
- /** Tables that had RLS enabled. */
44
- tablesSecured: number;
45
- /** Declared tables absent from the database — left to a real migration. */
46
- skipped: { table: string; reason: string }[];
47
- /**
48
- * Tables that have RLS on but did not get every policy. They deny — RLS
49
- * with no matching policy is deny-all — so they are safe but not servable.
50
- */
51
- failures: { table: string; error: string }[];
52
- /**
53
- * Tables RLS could not be enabled on, whose DML grant was withdrawn instead.
54
- *
55
- * This state had no name, and that was the bug: `ENABLE ROW LEVEL SECURITY`
56
- * failing was recorded as a `failure` and reported with the same "it stays
57
- * locked (denies)" wording as a failed policy — but the two are opposites.
58
- * A policy statement failing leaves RLS on and the table denying. `enableRls`
59
- * failing leaves RLS *off*, and the schema-wide grant to the user role has
60
- * already been made by `ensureRlsEnforcement`, so the table is readable and
61
- * writable by every authenticated request with no row filtering at all.
62
- */
63
- unsecured: { table: string; error: string; grantWithdrawn: boolean }[];
64
- /**
65
- * Generated policies removed because no current rule produces them.
66
- *
67
- * A policy's name embeds a hash of the rule's semantics, so editing a rule
68
- * does not update a policy — it creates a new one and abandons the old.
69
- * Postgres ORs permissive policies, so the abandoned one keeps granting:
70
- * a `USING (true)` tightened to an owner check went on admitting everyone,
71
- * forever, while the deploy logged success.
72
- *
73
- * `db push` reconciles this, and cannot reach a managed tenant's in-cluster
74
- * database — which is the reason this module exists. So boot has to do it.
75
- */
76
- orphansDropped: number;
77
- }
78
-
79
- const isCreatePolicy = (statement: string): boolean => /^\s*CREATE POLICY/i.test(statement);
80
-
81
- /**
82
- * Bring the declared collections' RLS policies up to date. Returns what it did.
83
- *
84
- * Only tables that already exist are touched: the boot-time table creator runs
85
- * first, so anything still missing is a table this additive path is not allowed
86
- * to create (a junction, or a relation left to a migration). Enabling RLS on a
87
- * non-existent table would error, so those are recorded as skipped, not failed.
88
- */
89
-
90
- /**
91
- * Remove generated policies on this table that the current plan does not
92
- * produce.
93
- *
94
- * Scoped hard, because dropping a policy is destructive: only this one table,
95
- * only names matching the generated `<table>_<op>_<sha1>` shape, and only names
96
- * absent from the statements just applied. A hand-written policy, or one
97
- * belonging to another table, is never touched — `isGeneratedPolicyName` is the
98
- * same predicate `db push` uses to draw that line.
99
- */
100
- async function dropOrphanedPoliciesOn(client: Queryable, plan: CollectionPolicyPlan): Promise<number> {
101
- const expected = new Set<string>();
102
- for (const statement of plan.policyStatements) {
103
- const match = /^\s*CREATE POLICY\s+"([^"]+)"/i.exec(statement);
104
- if (match) expected.add(match[1]);
105
- }
106
-
107
- const existing = await client.query<{ policyname: string }>(
108
- `SELECT policyname FROM pg_policies WHERE schemaname = '${plan.schema.replace(/'/g, "''")}' ` +
109
- `AND tablename = '${plan.table.replace(/'/g, "''")}'`
110
- );
111
-
112
- let dropped = 0;
113
- for (const row of existing.rows) {
114
- const name = row.policyname;
115
- if (expected.has(name)) continue;
116
- if (!isGeneratedPolicyName(name, plan.table)) continue;
117
- await client.query(`DROP POLICY IF EXISTS "${name}" ON "${plan.schema}"."${plan.table}"`);
118
- dropped++;
119
- }
120
- return dropped;
121
- }
122
-
123
- export async function ensureCollectionPolicies(
124
- client: Queryable,
125
- collections: CollectionConfig[],
126
- log?: (message: string) => void
127
- ): Promise<PolicyEnsureResult> {
128
- const result: PolicyEnsureResult = { policiesApplied: 0, tablesSecured: 0, skipped: [], failures: [], unsecured: [], orphansDropped: 0 };
129
-
130
- const plans = planCollectionPolicies(collections);
131
- if (plans.length === 0) return result;
132
-
133
- const schemas = Array.from(new Set(plans.map(p => p.schema)));
134
- const existing = await readExistingSchema(client, schemas);
135
-
136
- for (const plan of plans) {
137
- if (!existing.tables.has(plan.qualified)) {
138
- result.skipped.push({
139
- table: plan.qualified,
140
- reason: "table is not present in the database; create it with `rebase db push` / `rebase db migrate`"
141
- });
142
- continue;
143
- }
144
-
145
- // Enabling RLS is its own step, because its failure is the opposite of
146
- // every other failure here. Once RLS is on, anything that goes wrong
147
- // afterwards leaves the table denying; while it is off, the grant made
148
- // earlier in boot leaves the table wide open. Sharing one `try` meant
149
- // the dangerous case was reported in the safe case's words.
150
- try {
151
- await client.query(plan.enableRls);
152
- result.tablesSecured++;
153
- } catch (err) {
154
- const error = err instanceof Error ? err.message : String(err);
155
- // Take the privilege back rather than serve an unprotected table.
156
- // This is the fail-closed step the old code assumed it already had:
157
- // per-table, so one collection cannot take the rest of the
158
- // deployment down, but leaving nothing readable without RLS.
159
- let grantWithdrawn = false;
160
- try {
161
- await client.query(`REVOKE ALL PRIVILEGES ON ${plan.qualified} FROM ${REBASE_USER_ROLE}`);
162
- grantWithdrawn = true;
163
- } catch {
164
- // Fall through: reported below with `grantWithdrawn: false`,
165
- // which the caller escalates. There is nothing else this
166
- // function can do to make the table safe.
167
- }
168
- result.unsecured.push({ table: plan.qualified,
169
- error,
170
- grantWithdrawn });
171
- continue;
172
- }
173
-
174
- try {
175
- let created = 0;
176
- for (const statement of plan.policyStatements) {
177
- await client.query(statement);
178
- if (isCreatePolicy(statement)) {
179
- result.policiesApplied++;
180
- created++;
181
- }
182
- }
183
-
184
- const orphans = await dropOrphanedPoliciesOn(client, plan);
185
- result.orphansDropped += orphans;
186
-
187
- log?.(`${plan.qualified}: RLS enabled, ${created} policy(ies) applied` +
188
- (orphans > 0 ? `, ${orphans} orphan(s) dropped` : ""));
189
- } catch (err) {
190
- result.failures.push({
191
- table: plan.qualified,
192
- error: err instanceof Error ? err.message : String(err)
193
- });
194
- }
195
- }
196
-
197
- return result;
198
- }