@rebasepro/server-postgres 0.17.3 → 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,255 +0,0 @@
1
- import { humanize } from "./introspect-db-naming";
2
-
3
- export interface InferenceResult {
4
- propType?: string; // If the inference changes the base type
5
- extra?: string; // String to append to the property definition
6
- }
7
-
8
- const ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
9
- const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10
- const CUID_REGEX = /^c[^\s-]{7,}$/i; // Basic CUID check
11
- const COLOR_HEX_REGEX = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
12
-
13
- export function inferPropertyFromData(
14
- columnName: string,
15
- pgDataType: string,
16
- currentPropType: string,
17
- sampleValues: unknown[],
18
- isPk: boolean,
19
- /**
20
- * False when generating for a project without `@rebasepro/cms-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
26
- ): InferenceResult {
27
- const result: InferenceResult = {};
28
- const extraLines: string[] = [];
29
- // Collected separately and emitted as one block at the end. Pushed inline,
30
- // two admin-owned options from different branches produced two `admin: {`
31
- // blocks in one property — a duplicate key, which is also a compile error.
32
- const adminOptions: string[] = [];
33
-
34
- // Filter out null/undefined for analysis
35
- const validValues = sampleValues.filter(v => v !== null && v !== undefined && v !== "");
36
-
37
- if (validValues.length === 0) {
38
- return result; // Not enough data
39
- }
40
-
41
- const colNameLower = columnName.toLowerCase();
42
-
43
- // ── Number Analysis ──────────────────────────────────────────────────
44
- if (currentPropType === "number") {
45
- // Boolean stored as int
46
- const allZeroOrOne = validValues.every(v => v === 0 || v === 1 || v === "0" || v === "1");
47
- if (allZeroOrOne) {
48
- result.propType = "boolean";
49
- return result; // Don't do min/max if boolean
50
- }
51
-
52
- // Min / Max constraints
53
- const numValues = validValues.map(v => Number(v)).filter(v => !isNaN(v));
54
- if (numValues.length === validValues.length) {
55
- const min = Math.min(...numValues);
56
- const max = Math.max(...numValues);
57
- // Example heuristic: percentages
58
- if (min >= 0 && max <= 100 && (colNameLower.includes("percent") || colNameLower.includes("rate") || colNameLower.includes("score"))) {
59
- extraLines.push(" validation: {\n min: 0,\n max: 100\n }");
60
- } else if (min >= 0 && (colNameLower.includes("count") || colNameLower.includes("total") || colNameLower.includes("amount"))) {
61
- extraLines.push(" validation: {\n min: 0\n }");
62
- }
63
- }
64
-
65
- // No currency heuristic. `admin.currency` was never a declared option and
66
- // nothing reads it, so a column called `price` got a block of config that did
67
- // nothing — invisible because this generator emits *source text*, which no
68
- // typechecker ever saw. Reinstate it by adding `currency` to
69
- // AdminNumberOptions first, and something that renders it.
70
- }
71
-
72
- // ── JSON / JSONB Analysis ────────────────────────────────────────────
73
- if (currentPropType === "map" || pgDataType.includes("json")) {
74
- // PostGres jsonb can be object or array
75
- let allArrays = true;
76
- let allObjects = true;
77
-
78
- for (const v of validValues) {
79
- let parsed = v;
80
- if (typeof v === "string") {
81
- try { parsed = JSON.parse(v); } catch (e) { allArrays = false; allObjects = false; break; }
82
- }
83
- if (Array.isArray(parsed)) {
84
- allObjects = false;
85
- } else if (typeof parsed === "object" && parsed !== null) {
86
- allArrays = false;
87
- } else {
88
- allArrays = false;
89
- allObjects = false;
90
- }
91
- }
92
-
93
- if (allArrays && !allObjects) {
94
- result.propType = "array";
95
- // Infer inner type
96
- let allNumbers = true;
97
- let allStrings = true;
98
- for (const v of validValues) {
99
- const parsed = typeof v === "string" ? JSON.parse(v) : v;
100
- for (const item of parsed) {
101
- if (typeof item !== "number") allNumbers = false;
102
- if (typeof item !== "string") allStrings = false;
103
- }
104
- }
105
- const innerType = allNumbers ? "number" : allStrings ? "string" : "map";
106
- extraLines.push(` of: { name: "${humanize(columnName)} Item", type: "${innerType}" }`);
107
- } else {
108
- result.propType = "map";
109
-
110
- // Infer inner schema
111
- if (allObjects && validValues.length > 0) {
112
- const schema: Record<string, string> = {};
113
- for (const v of validValues) {
114
- const parsed = typeof v === "string" ? JSON.parse(v) : v;
115
- for (const [k, val] of Object.entries(parsed)) {
116
- if (val === null || val === undefined) continue;
117
- const type = typeof val;
118
- if (type === "string" || type === "number" || type === "boolean") {
119
- if (!schema[k]) schema[k] = type;
120
- else if (schema[k] !== type) schema[k] = "mixed";
121
- } else if (Array.isArray(val)) {
122
- if (!schema[k]) schema[k] = "array";
123
- else if (schema[k] !== "array") schema[k] = "mixed";
124
- } else if (type === "object") {
125
- if (!schema[k]) schema[k] = "map";
126
- else if (schema[k] !== "map") schema[k] = "mixed";
127
- }
128
- }
129
- }
130
-
131
- const keys = Object.keys(schema).filter(k => schema[k] !== "mixed");
132
- if (keys.length > 0) {
133
- const props = keys.map(k => {
134
- return `\n ${k}: { name: "${humanize(k)}", type: "${schema[k]}" }`;
135
- }).join(",");
136
- extraLines.push(` properties: {${props}\n }`);
137
- } else {
138
- extraLines.push(" keyValue: true");
139
- }
140
- } else {
141
- extraLines.push(" keyValue: true");
142
- }
143
- }
144
- }
145
-
146
- // ── String Analysis ──────────────────────────────────────────────────
147
- if (currentPropType === "string") {
148
- // Date/Time Strings
149
- if (validValues.every(v => typeof v === "string" && ISO_8601_REGEX.test(v))) {
150
- result.propType = "date";
151
- return result;
152
- }
153
-
154
- // Implicit Enums
155
- const uniqueValues = new Set(validValues);
156
- // Determine the maximum length among unique values
157
- let maxEnumLength = 0;
158
- for (const v of uniqueValues) {
159
- if (typeof v === "string" && v.length > maxEnumLength) {
160
- maxEnumLength = v.length;
161
- }
162
- }
163
-
164
- // Ensure no empty string, max length makes sense, and fewer unique values than total values (unless small total)
165
- if (uniqueValues.size > 0 && uniqueValues.size <= 5 && maxEnumLength <= 50 && validValues.length > uniqueValues.size && !uniqueValues.has("")) {
166
- const isLikelyId = isPk || colNameLower.endsWith("_id");
167
- if (!isLikelyId) {
168
- const enumEntries = Array.from(uniqueValues).map(v => `{ id: ${JSON.stringify(v)}, label: ${JSON.stringify(humanize(v as string))} }`).join(", ");
169
- extraLines.push(` enum: [${enumEntries}]`);
170
- result.extra = extraLines.length > 0 ? "\n" + extraLines.join(",\n") + "," : "";
171
- return result; // Skip other string checks if it's an enum
172
- }
173
- }
174
-
175
- // UUID / CUID Detection
176
- const allUuid = validValues.every(v => typeof v === "string" && UUID_REGEX.test(v));
177
- const allCuid = validValues.every(v => typeof v === "string" && CUID_REGEX.test(v));
178
- if (allUuid) {
179
- if (isPk) extraLines.push(" isId: \"uuid\"");
180
- } else if (allCuid) {
181
- if (isPk) extraLines.push(" isId: \"cuid\"");
182
- }
183
-
184
- // No colour heuristic. `admin.color` was never a declared option and nothing
185
- // reads it — the same dead branch `currency` was. This generator emits *source
186
- // text*, so no typechecker ever saw either. Reinstate by adding the option and
187
- // something that renders it first.
188
-
189
- // Text Lengths, Multiline & Markdown
190
- let maxLength = 0;
191
- let hasNewlines = false;
192
- let hasMarkdown = false;
193
- for (const v of validValues) {
194
- if (typeof v === "string") {
195
- if (v.length > maxLength) maxLength = v.length;
196
- if (v.includes("\n")) hasNewlines = true;
197
- if (/^#{1,6}\s+.+/m.test(v) || /\*\*.+\*\*/.test(v) || /\[.+\]\(.+\)/.test(v) || /^\s*[-*]\s+.+/m.test(v)) {
198
- hasMarkdown = true;
199
- }
200
- }
201
- }
202
-
203
- // `multiline` and `markdown` are *admin* property options, so they have
204
- // to sit inside the `admin` block. Emitted at the top of the property —
205
- // where they were — `PostgresCollectionConfig` does not declare them and
206
- // the generated file does not compile.
207
- if (hasMarkdown) {
208
- adminOptions.push("multiline: true", "markdown: true");
209
- } else if (hasNewlines || maxLength > 100) {
210
- adminOptions.push("multiline: true");
211
- }
212
-
213
- if (maxLength > 0 && maxLength < 10000) { // arbitrary cap to avoid huge limits
214
- // Pad the max length slightly for the constraint
215
- const paddedMax = Math.ceil((maxLength * 1.5) / 10) * 10;
216
- // Only add length constraint if it seems like a bounded string, not a long text
217
- if (paddedMax < 255) {
218
- extraLines.push(` validation: {\n max: ${paddedMax}\n }`);
219
- }
220
- }
221
-
222
- // Storage & Media (Extracted from old logic)
223
- const isUrl = colNameLower.endsWith("_url") || colNameLower.endsWith("_uri") || colNameLower.endsWith("_link");
224
- const isMedia = colNameLower.includes("image") || colNameLower.includes("avatar") || colNameLower.includes("photo") || colNameLower.includes("logo") || colNameLower.includes("cover");
225
-
226
- const allAbsoluteUrls = validValues.every(v => typeof v === "string" && (v.startsWith("http://") || v.startsWith("https://")));
227
- if (allAbsoluteUrls) {
228
- const isImage = validValues.some(v => typeof v === "string" && v.match(/\.(jpeg|jpg|gif|png|webp|svg)/i));
229
- if (isImage || isMedia) {
230
- extraLines.push(" url: true");
231
- adminOptions.push("urlPreview: \"image\"");
232
- } else {
233
- extraLines.push(" url: true");
234
- }
235
- } else {
236
- const hasFileExtension = validValues.some(v => typeof v === "string" && v.match(/\.[a-zA-Z0-9]+$/));
237
- if (hasFileExtension) {
238
- const firstVal = validValues[0] as string;
239
- const lastSlash = firstVal.lastIndexOf("/");
240
- const inferredStoragePath = lastSlash > 0 ? firstVal.substring(0, lastSlash) : "files";
241
- extraLines.push(` storage: {\n storagePath: "${inferredStoragePath}"\n }`);
242
- } else if (isUrl) {
243
- extraLines.push(" url: true");
244
- if (isMedia) adminOptions.push("urlPreview: \"image\"");
245
- }
246
- }
247
- }
248
-
249
- if (emitAdmin && adminOptions.length > 0) {
250
- extraLines.push(` admin: {\n${adminOptions.map((o) => ` ${o}`).join(",\n")}\n }`);
251
- }
252
-
253
- result.extra = extraLines.length > 0 ? "\n" + extraLines.join(",\n") + "," : "";
254
- return result;
255
- }