@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.
- package/dist/PostgresBackendDriver.d.ts +48 -1
- package/dist/PostgresBootstrapper.d.ts +26 -0
- package/dist/auth/services.d.ts +21 -0
- package/dist/{src-DlPBctw_.js → auth-users-columns-BfQHf9JE.js} +1222 -86
- package/dist/auth-users-columns-BfQHf9JE.js.map +1 -0
- package/dist/{backup-service-CD8o_1Sl.js → backup-service-BH0Dzo_h.js} +2 -3
- package/dist/{backup-service-CD8o_1Sl.js.map → backup-service-BH0Dzo_h.js.map} +1 -1
- package/dist/cli-helpers.d.ts +57 -1
- package/dist/cli-output.d.ts +34 -0
- package/dist/data-transformer.d.ts +7 -2
- package/dist/data_driver-ULAyJEi9.js +193 -0
- package/dist/data_driver-ULAyJEi9.js.map +1 -0
- package/dist/ensure-collection-policies-8vuu-n4r.js +124 -0
- package/dist/ensure-collection-policies-8vuu-n4r.js.map +1 -0
- package/dist/{ensure-collection-tables-CBQdOETu.js → ensure-collection-tables-CbvaGuVn.js} +170 -20
- package/dist/ensure-collection-tables-CbvaGuVn.js.map +1 -0
- package/dist/index.es.js +1815 -1023
- package/dist/index.es.js.map +1 -1
- package/dist/rls-bootstrap-sql-69hYT8nr.js +244 -0
- package/dist/rls-bootstrap-sql-69hYT8nr.js.map +1 -0
- package/dist/rls-enforcement-BJ_3wxwg.js +425 -0
- package/dist/rls-enforcement-BJ_3wxwg.js.map +1 -0
- package/dist/schema/auth-schema.d.ts +102 -0
- package/dist/schema/auth-users-columns.d.ts +97 -0
- package/dist/schema/doctor-policy-checks.d.ts +28 -0
- package/dist/schema/doctor.d.ts +41 -25
- package/dist/schema/ensure-collection-policies.d.ts +33 -9
- package/dist/schema/ensure-collection-tables.d.ts +61 -7
- package/dist/schema/generate-drizzle-schema-logic.d.ts +10 -2
- package/dist/schema/generate-postgres-ddl-logic.d.ts +53 -5
- package/dist/schema/generated-schema-staleness.d.ts +39 -0
- package/dist/schema/introspect-db-inference.d.ts +8 -1
- package/dist/schema/introspect-db-logic.d.ts +49 -0
- package/dist/schema/introspect-db-project.d.ts +21 -0
- package/dist/schema/rls-bootstrap-sql.d.ts +135 -0
- package/dist/schema/search-column.d.ts +248 -0
- package/dist/security/policy-drift.d.ts +34 -0
- package/dist/security/rls-enforcement.d.ts +61 -5
- package/dist/services/FetchService.d.ts +34 -7
- package/dist/services/PersistService.d.ts +21 -17
- package/dist/services/RelationService.d.ts +9 -57
- package/dist/services/RelationWriteService.d.ts +82 -0
- package/dist/services/collection-helpers.d.ts +42 -0
- package/dist/services/dataService.d.ts +5 -0
- package/dist/services/junction-writes.d.ts +82 -0
- package/dist/services/realtimeService.d.ts +164 -23
- package/dist/services/write-denial.d.ts +36 -0
- package/dist/{src-DoU9yPqq.js → src-DCdn3Val.js} +124 -3
- package/dist/src-DCdn3Val.js.map +1 -0
- package/dist/utils/drizzle-conditions.d.ts +124 -2
- package/dist/{websocket-B2LsrINK.js → websocket-C8ZqVBiV.js} +75 -18
- package/dist/websocket-C8ZqVBiV.js.map +1 -0
- package/package.json +9 -8
- package/src/PostgresBackendDriver.ts +172 -6
- package/src/PostgresBootstrapper.ts +136 -11
- package/src/auth/ensure-tables.ts +212 -91
- package/src/auth/services.ts +82 -5
- package/src/backup/backup-cli.ts +59 -57
- package/src/cli-errors.ts +6 -6
- package/src/cli-helpers.ts +132 -13
- package/src/cli-output.ts +43 -0
- package/src/cli.ts +371 -161
- package/src/collections/buildRegistry.ts +3 -1
- package/src/collections/validate-relations.ts +124 -17
- package/src/data-transformer.ts +142 -28
- package/src/history/ensure-history-table.ts +9 -2
- package/src/schema/auth-schema.ts +17 -1
- package/src/schema/auth-users-columns.ts +131 -0
- package/src/schema/doctor-cli.ts +14 -65
- package/src/schema/doctor-policy-checks.ts +105 -0
- package/src/schema/doctor.ts +156 -77
- package/src/schema/ensure-collection-policies.ts +99 -6
- package/src/schema/ensure-collection-tables.ts +374 -32
- package/src/schema/generate-drizzle-schema-logic.ts +152 -66
- package/src/schema/generate-drizzle-schema.ts +11 -10
- package/src/schema/generate-postgres-ddl-logic.ts +294 -16
- package/src/schema/generate-postgres-ddl.ts +38 -14
- package/src/schema/generated-schema-staleness.ts +171 -0
- package/src/schema/introspect-db-inference.ts +9 -2
- package/src/schema/introspect-db-logic.ts +251 -75
- package/src/schema/introspect-db-project.ts +78 -0
- package/src/schema/introspect-db.ts +42 -25
- package/src/schema/introspect-runtime.ts +14 -2
- package/src/schema/non-sql-collections.test.ts +131 -0
- package/src/schema/rls-bootstrap-sql.ts +288 -0
- package/src/schema/search-column.ts +643 -0
- package/src/security/anonymous-grants.test.ts +4 -2
- package/src/security/policy-drift.test.ts +104 -3
- package/src/security/policy-drift.ts +129 -7
- package/src/security/rls-enforcement.ts +150 -7
- package/src/services/BranchService.ts +5 -0
- package/src/services/FetchService.ts +253 -115
- package/src/services/PersistService.ts +82 -43
- package/src/services/RelationService.ts +37 -696
- package/src/services/RelationWriteService.ts +653 -0
- package/src/services/cdc/trigger-cdc.ts +5 -1
- package/src/services/channel-history.ts +14 -0
- package/src/services/channel-presence.ts +13 -0
- package/src/services/collection-helpers.ts +89 -4
- package/src/services/dataService.ts +5 -0
- package/src/services/junction-writes.ts +295 -0
- package/src/services/pg-notify-listener.ts +1 -1
- package/src/services/realtimeService.ts +382 -118
- package/src/services/write-denial.ts +55 -0
- package/src/utils/drizzle-conditions.ts +433 -35
- package/src/utils/pg-error-utils.ts +8 -3
- package/src/websocket.ts +113 -16
- package/dist/ensure-collection-policies-ViG8XiPn.js +0 -57
- package/dist/ensure-collection-policies-ViG8XiPn.js.map +0 -1
- package/dist/ensure-collection-tables-CBQdOETu.js.map +0 -1
- package/dist/policy-CeA1JcxP.js +0 -105
- package/dist/policy-CeA1JcxP.js.map +0 -1
- package/dist/schema/auth-bootstrap-sql.d.ts +0 -24
- package/dist/src-DlPBctw_.js.map +0 -1
- package/dist/src-DoU9yPqq.js.map +0 -1
- package/dist/websocket-B2LsrINK.js.map +0 -1
- 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
|
|