@rebasepro/server-postgres 0.13.0 → 0.13.1-canary.g1822133

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 (117) hide show
  1. package/dist/PostgresBackendDriver.d.ts +48 -1
  2. package/dist/PostgresBootstrapper.d.ts +26 -0
  3. package/dist/auth/services.d.ts +21 -0
  4. package/dist/{src-DlPBctw_.js → auth-users-columns-BfQHf9JE.js} +1222 -86
  5. package/dist/auth-users-columns-BfQHf9JE.js.map +1 -0
  6. package/dist/{backup-service-CD8o_1Sl.js → backup-service-BH0Dzo_h.js} +2 -3
  7. package/dist/{backup-service-CD8o_1Sl.js.map → backup-service-BH0Dzo_h.js.map} +1 -1
  8. package/dist/cli-helpers.d.ts +57 -1
  9. package/dist/cli-output.d.ts +34 -0
  10. package/dist/data-transformer.d.ts +7 -2
  11. package/dist/data_driver-ULAyJEi9.js +193 -0
  12. package/dist/data_driver-ULAyJEi9.js.map +1 -0
  13. package/dist/ensure-collection-policies-8vuu-n4r.js +124 -0
  14. package/dist/ensure-collection-policies-8vuu-n4r.js.map +1 -0
  15. package/dist/{ensure-collection-tables-CBQdOETu.js → ensure-collection-tables-CbvaGuVn.js} +170 -20
  16. package/dist/ensure-collection-tables-CbvaGuVn.js.map +1 -0
  17. package/dist/index.es.js +1815 -1023
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/rls-bootstrap-sql-69hYT8nr.js +244 -0
  20. package/dist/rls-bootstrap-sql-69hYT8nr.js.map +1 -0
  21. package/dist/rls-enforcement-BJ_3wxwg.js +425 -0
  22. package/dist/rls-enforcement-BJ_3wxwg.js.map +1 -0
  23. package/dist/schema/auth-schema.d.ts +102 -0
  24. package/dist/schema/auth-users-columns.d.ts +97 -0
  25. package/dist/schema/doctor-policy-checks.d.ts +28 -0
  26. package/dist/schema/doctor.d.ts +41 -25
  27. package/dist/schema/ensure-collection-policies.d.ts +33 -9
  28. package/dist/schema/ensure-collection-tables.d.ts +61 -7
  29. package/dist/schema/generate-drizzle-schema-logic.d.ts +10 -2
  30. package/dist/schema/generate-postgres-ddl-logic.d.ts +53 -5
  31. package/dist/schema/generated-schema-staleness.d.ts +39 -0
  32. package/dist/schema/introspect-db-inference.d.ts +8 -1
  33. package/dist/schema/introspect-db-logic.d.ts +49 -0
  34. package/dist/schema/introspect-db-project.d.ts +21 -0
  35. package/dist/schema/rls-bootstrap-sql.d.ts +135 -0
  36. package/dist/schema/search-column.d.ts +248 -0
  37. package/dist/security/policy-drift.d.ts +34 -0
  38. package/dist/security/rls-enforcement.d.ts +61 -5
  39. package/dist/services/FetchService.d.ts +34 -7
  40. package/dist/services/PersistService.d.ts +21 -17
  41. package/dist/services/RelationService.d.ts +9 -57
  42. package/dist/services/RelationWriteService.d.ts +82 -0
  43. package/dist/services/collection-helpers.d.ts +42 -0
  44. package/dist/services/dataService.d.ts +5 -0
  45. package/dist/services/junction-writes.d.ts +82 -0
  46. package/dist/services/realtimeService.d.ts +164 -23
  47. package/dist/services/write-denial.d.ts +36 -0
  48. package/dist/{src-DoU9yPqq.js → src-DCdn3Val.js} +124 -3
  49. package/dist/src-DCdn3Val.js.map +1 -0
  50. package/dist/utils/drizzle-conditions.d.ts +124 -2
  51. package/dist/{websocket-B2LsrINK.js → websocket-C8ZqVBiV.js} +75 -18
  52. package/dist/websocket-C8ZqVBiV.js.map +1 -0
  53. package/package.json +9 -8
  54. package/src/PostgresBackendDriver.ts +172 -6
  55. package/src/PostgresBootstrapper.ts +136 -11
  56. package/src/auth/ensure-tables.ts +212 -91
  57. package/src/auth/services.ts +82 -5
  58. package/src/backup/backup-cli.ts +59 -57
  59. package/src/cli-errors.ts +6 -6
  60. package/src/cli-helpers.ts +132 -13
  61. package/src/cli-output.ts +43 -0
  62. package/src/cli.ts +371 -161
  63. package/src/collections/buildRegistry.ts +3 -1
  64. package/src/collections/validate-relations.ts +124 -17
  65. package/src/data-transformer.ts +142 -28
  66. package/src/history/ensure-history-table.ts +9 -2
  67. package/src/schema/auth-schema.ts +17 -1
  68. package/src/schema/auth-users-columns.ts +131 -0
  69. package/src/schema/doctor-cli.ts +14 -65
  70. package/src/schema/doctor-policy-checks.ts +105 -0
  71. package/src/schema/doctor.ts +156 -77
  72. package/src/schema/ensure-collection-policies.ts +99 -6
  73. package/src/schema/ensure-collection-tables.ts +374 -32
  74. package/src/schema/generate-drizzle-schema-logic.ts +152 -66
  75. package/src/schema/generate-drizzle-schema.ts +11 -10
  76. package/src/schema/generate-postgres-ddl-logic.ts +294 -16
  77. package/src/schema/generate-postgres-ddl.ts +38 -14
  78. package/src/schema/generated-schema-staleness.ts +171 -0
  79. package/src/schema/introspect-db-inference.ts +9 -2
  80. package/src/schema/introspect-db-logic.ts +251 -75
  81. package/src/schema/introspect-db-project.ts +78 -0
  82. package/src/schema/introspect-db.ts +42 -25
  83. package/src/schema/introspect-runtime.ts +14 -2
  84. package/src/schema/non-sql-collections.test.ts +131 -0
  85. package/src/schema/rls-bootstrap-sql.ts +288 -0
  86. package/src/schema/search-column.ts +643 -0
  87. package/src/security/anonymous-grants.test.ts +4 -2
  88. package/src/security/policy-drift.test.ts +104 -3
  89. package/src/security/policy-drift.ts +129 -7
  90. package/src/security/rls-enforcement.ts +150 -7
  91. package/src/services/BranchService.ts +5 -0
  92. package/src/services/FetchService.ts +253 -115
  93. package/src/services/PersistService.ts +82 -43
  94. package/src/services/RelationService.ts +37 -696
  95. package/src/services/RelationWriteService.ts +653 -0
  96. package/src/services/cdc/trigger-cdc.ts +5 -1
  97. package/src/services/channel-history.ts +14 -0
  98. package/src/services/channel-presence.ts +13 -0
  99. package/src/services/collection-helpers.ts +89 -4
  100. package/src/services/dataService.ts +5 -0
  101. package/src/services/junction-writes.ts +295 -0
  102. package/src/services/pg-notify-listener.ts +1 -1
  103. package/src/services/realtimeService.ts +382 -118
  104. package/src/services/write-denial.ts +55 -0
  105. package/src/utils/drizzle-conditions.ts +433 -35
  106. package/src/utils/pg-error-utils.ts +8 -3
  107. package/src/websocket.ts +113 -16
  108. package/dist/ensure-collection-policies-ViG8XiPn.js +0 -57
  109. package/dist/ensure-collection-policies-ViG8XiPn.js.map +0 -1
  110. package/dist/ensure-collection-tables-CBQdOETu.js.map +0 -1
  111. package/dist/policy-CeA1JcxP.js +0 -105
  112. package/dist/policy-CeA1JcxP.js.map +0 -1
  113. package/dist/schema/auth-bootstrap-sql.d.ts +0 -24
  114. package/dist/src-DlPBctw_.js.map +0 -1
  115. package/dist/src-DoU9yPqq.js.map +0 -1
  116. package/dist/websocket-B2LsrINK.js.map +0 -1
  117. package/src/schema/auth-bootstrap-sql.ts +0 -47
@@ -0,0 +1,171 @@
1
+ import { CollectionConfig } from "@rebasepro/types";
2
+ import { getTableName, resolveCollectionRelations, relationalCollections } from "@rebasepro/common";
3
+ import { generateForeignKeyName, legacyForeignKeyName } from "@rebasepro/utils";
4
+
5
+ /**
6
+ * Notice a generated Drizzle schema that a *library upgrade* invalidated.
7
+ *
8
+ * `rebase dev` already watches `config/collections` and warns when a collection
9
+ * file changes. That covers drift the developer caused. It cannot cover this one,
10
+ * because nothing the developer owns changed: 0.13 derives `category_id` where
11
+ * 0.12 derived `categorie_id`, from the same unedited collection. The watcher
12
+ * never fires, and `backend/src/schema.generated.ts` quietly stops describing the
13
+ * schema the runtime expects.
14
+ *
15
+ * The consequence is not cosmetic. Boot-ensure renames the column in the
16
+ * database, then relation validation reads the stale module and refuses to
17
+ * start — on that boot and every boot after it, because the rename is already
18
+ * applied and will not be attempted again.
19
+ *
20
+ * Deliberately narrow: this answers "does the generated schema name a foreign key
21
+ * the way the previous rule did", not "is this file what we would generate now".
22
+ * The wide question would report every whitespace change in the generator as a
23
+ * fatal staleness, and a check that cries wolf gets switched off.
24
+ */
25
+
26
+ /** One column the generated schema names under the pre-0.13 rule. */
27
+ export interface LegacyForeignKeyName {
28
+ /** Table whose column declaration is stale. */
29
+ table: string;
30
+ /** The name the generated schema declares. */
31
+ legacy: string;
32
+ /** The name this release derives, and which the database now carries. */
33
+ current: string;
34
+ /** `<collection>.<relation>` that derives it, for the message. */
35
+ relation: string;
36
+ }
37
+
38
+ /**
39
+ * The slice of the generated source declaring one table.
40
+ *
41
+ * Scoping matters: two junctions in one file can carry columns of the same name,
42
+ * and a whole-file match would attribute a stale column to whichever table the
43
+ * reader looks at first. Returns "" when the table is not in the file at all,
44
+ * which is not staleness — it is a table the generator has not been asked about.
45
+ */
46
+ function tableBlock(source: string, table: string): string {
47
+ const start = source.indexOf(`pgTable("${table}"`);
48
+ if (start === -1) return "";
49
+ // Generated files put every table in its own `export const`, so the next one
50
+ // is the end of this block. No brace counting, nothing to get wrong.
51
+ const next = source.indexOf("\nexport ", start);
52
+ return next === -1 ? source.slice(start) : source.slice(start, next);
53
+ }
54
+
55
+ /**
56
+ * Whether a block *declares* the column, rather than merely mentioning it.
57
+ *
58
+ * A comment explaining the rename, or a policy expression naming the old column,
59
+ * must not read as a declaration — otherwise regenerating the file would not
60
+ * clear the finding and the check would be permanently red.
61
+ */
62
+ function declaresColumn(block: string, column: string): boolean {
63
+ // `categorieId: integer("categorie_id")` — the Drizzle column shape. Only
64
+ // the string argument is the column; the key beside it is the *wire* name
65
+ // and no longer agrees with it (`authorId: integer("author_id")`). Matching
66
+ // both, as this did, made every camelCased key look like a column the
67
+ // generated file did not declare.
68
+ const literal = column.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
69
+ return new RegExp(`(^|[\\s,{])[\\w$"']+\\s*:\\s*\\w+\\(\\s*["']${literal}["']`, "m").test(block);
70
+ }
71
+
72
+ /**
73
+ * @param generatedSource contents of `backend/src/schema.generated.ts`
74
+ * @param collections the project's collections, as this release reads them
75
+ */
76
+ export function findLegacyForeignKeyNames(
77
+ generatedSource: string,
78
+ collections: CollectionConfig[]
79
+ ): LegacyForeignKeyName[] {
80
+ const found: LegacyForeignKeyName[] = [];
81
+ const seen = new Set<string>();
82
+
83
+ /**
84
+ * Report `wanted` as stale when the generated schema declares what the
85
+ * previous rule would have derived from `source` instead.
86
+ *
87
+ * The `wanted !== current` guard is what honours an explicitly named column.
88
+ * An author who pinned `categorie_id` has said so on the relation, so the
89
+ * generated file agreeing with them is correct, not stale — and the rename
90
+ * note documents exactly that opt-out.
91
+ */
92
+ const consider = (
93
+ table: string,
94
+ wanted: string,
95
+ sourceName: string | undefined,
96
+ relation: string
97
+ ): void => {
98
+ if (!table || !wanted || !sourceName) return;
99
+
100
+ const current = generateForeignKeyName(sourceName);
101
+ const legacy = legacyForeignKeyName(sourceName);
102
+ if (legacy === current) return; // this name never moved
103
+ if (wanted !== current) return; // pinned by the author, or unrelated
104
+
105
+ const block = tableBlock(generatedSource, table);
106
+ if (!block) return;
107
+ if (!declaresColumn(block, legacy)) return;
108
+ if (declaresColumn(block, current)) return; // already regenerated
109
+
110
+ const key = `${table}.${legacy}`;
111
+ if (seen.has(key)) return;
112
+ seen.add(key);
113
+ found.push({ table, legacy, current, relation });
114
+ };
115
+
116
+ // Same rule as the generator whose output this reads: a collection that
117
+ // gets no table cannot have named a column in it. Inert in practice today —
118
+ // the finding also requires the generated file to declare the table — but
119
+ // the guard is what keeps that true when a non-SQL collection's slug happens
120
+ // to match a SQL one's table.
121
+ for (const collection of relationalCollections(collections)) {
122
+ const sourceTable = getTableName(collection);
123
+
124
+ for (const [name, relation] of Object.entries(resolveCollectionRelations(collection))) {
125
+ const at = `${collection.slug}.${name}`;
126
+
127
+ let target: CollectionConfig | undefined;
128
+ try {
129
+ target = relation.target?.();
130
+ } catch {
131
+ // A throwing target thunk is its own defect, reported at boot by
132
+ // `validate-relations`. Nothing to say about its column names.
133
+ continue;
134
+ }
135
+
136
+ switch (relation.kind) {
137
+ case "belongsTo":
138
+ consider(sourceTable, relation.localKey, relation.relationName, at);
139
+ break;
140
+
141
+ case "hasOne":
142
+ case "hasMany":
143
+ if (target) {
144
+ consider(getTableName(target), relation.foreignKeyOnTarget, collection.slug, at);
145
+ }
146
+ break;
147
+
148
+ case "manyToMany":
149
+ consider(relation.through.table, relation.through.sourceColumn, collection.slug, at);
150
+ if (target) {
151
+ consider(relation.through.table, relation.through.targetColumn, target.slug, at);
152
+ }
153
+ break;
154
+
155
+ default:
156
+ // `via` joins are written by hand — there is no derived name
157
+ // for the rule change to have moved.
158
+ break;
159
+ }
160
+ }
161
+ }
162
+
163
+ return found;
164
+ }
165
+
166
+ /** One-line summary for a log or a CLI notice. */
167
+ export function describeLegacyForeignKeyNames(found: LegacyForeignKeyName[]): string {
168
+ return found
169
+ .map(f => ` • ${f.table}.${f.legacy} → ${f.current} (${f.relation})`)
170
+ .join("\n");
171
+ }
@@ -15,7 +15,14 @@ export function inferPropertyFromData(
15
15
  pgDataType: string,
16
16
  currentPropType: string,
17
17
  sampleValues: unknown[],
18
- isPk: boolean
18
+ isPk: boolean,
19
+ /**
20
+ * False when generating for a project without `@rebasepro/admin-types`, where
21
+ * `BaseProperty` declares no `admin` field and the block below would not
22
+ * compile. The type-level inferences (`propType`, `url`, `storage`) are
23
+ * unaffected — only the form-widget hints are dropped.
24
+ */
25
+ emitAdmin = true
19
26
  ): InferenceResult {
20
27
  const result: InferenceResult = {};
21
28
  const extraLines: string[] = [];
@@ -239,7 +246,7 @@ export function inferPropertyFromData(
239
246
  }
240
247
  }
241
248
 
242
- if (adminOptions.length > 0) {
249
+ if (emitAdmin && adminOptions.length > 0) {
243
250
  extraLines.push(` admin: {\n${adminOptions.map((o) => ` ${o}`).join(",\n")}\n }`);
244
251
  }
245
252