@rebasepro/server-postgresql 0.6.0 → 0.7.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 (82) hide show
  1. package/package.json +24 -18
  2. package/src/PostgresBackendDriver.ts +65 -44
  3. package/src/PostgresBootstrapper.ts +49 -20
  4. package/src/auth/ensure-tables.ts +56 -1
  5. package/src/auth/services.ts +94 -1
  6. package/src/cli-errors.ts +162 -0
  7. package/src/cli-helpers.ts +183 -0
  8. package/src/cli.ts +198 -251
  9. package/src/data-transformer.ts +9 -1
  10. package/src/schema/auth-default-policies.ts +90 -0
  11. package/src/schema/auth-schema.ts +25 -2
  12. package/src/schema/doctor.ts +2 -4
  13. package/src/schema/generate-drizzle-schema-logic.ts +4 -3
  14. package/src/schema/generate-drizzle-schema.ts +3 -5
  15. package/src/schema/generate-postgres-ddl-logic.ts +524 -0
  16. package/src/schema/generate-postgres-ddl.ts +116 -0
  17. package/src/services/EntityPersistService.ts +18 -16
  18. package/src/services/entityService.ts +28 -3
  19. package/src/utils/pg-array-null-patch.ts +42 -0
  20. package/src/utils/pg-error-utils.ts +16 -0
  21. package/src/utils/table-classification.ts +16 -0
  22. package/src/websocket.ts +9 -0
  23. package/test/array-null-safety.test.ts +335 -0
  24. package/test/auth-default-policies.test.ts +89 -0
  25. package/test/cli-helpers-extended.test.ts +324 -0
  26. package/test/cli-helpers.test.ts +59 -0
  27. package/test/connection.test.ts +292 -0
  28. package/test/data-transformer.test.ts +53 -2
  29. package/test/databasePoolManager.test.ts +289 -0
  30. package/test/doctor-extended.test.ts +443 -0
  31. package/test/e2e/db-e2e.test.ts +293 -0
  32. package/test/e2e/pg-setup.ts +79 -0
  33. package/test/entity-persist-composite-keys.test.ts +451 -0
  34. package/test/generate-postgres-ddl-edge-cases.test.ts +716 -0
  35. package/test/generate-postgres-ddl.test.ts +300 -0
  36. package/test/mfa-service.test.ts +544 -0
  37. package/test/pg-array-null-patch.test.ts +65 -0
  38. package/test/pg-error-utils.test.ts +50 -1
  39. package/test/realtimeService-channels.test.ts +696 -0
  40. package/test/unmapped-tables-safety.test.ts +55 -342
  41. package/vite.config.ts +8 -6
  42. package/vitest.e2e.config.ts +10 -0
  43. package/build-errors.txt +0 -37
  44. package/dist/PostgresAdapter.d.ts +0 -6
  45. package/dist/PostgresBackendDriver.d.ts +0 -110
  46. package/dist/PostgresBootstrapper.d.ts +0 -46
  47. package/dist/auth/ensure-tables.d.ts +0 -10
  48. package/dist/auth/services.d.ts +0 -231
  49. package/dist/cli.d.ts +0 -1
  50. package/dist/collections/PostgresCollectionRegistry.d.ts +0 -47
  51. package/dist/connection.d.ts +0 -65
  52. package/dist/data-transformer.d.ts +0 -55
  53. package/dist/databasePoolManager.d.ts +0 -20
  54. package/dist/history/HistoryService.d.ts +0 -71
  55. package/dist/history/ensure-history-table.d.ts +0 -7
  56. package/dist/index.d.ts +0 -14
  57. package/dist/index.es.js +0 -10764
  58. package/dist/index.es.js.map +0 -1
  59. package/dist/index.umd.js +0 -11055
  60. package/dist/index.umd.js.map +0 -1
  61. package/dist/interfaces.d.ts +0 -18
  62. package/dist/schema/auth-schema.d.ts +0 -2149
  63. package/dist/schema/doctor-cli.d.ts +0 -2
  64. package/dist/schema/doctor.d.ts +0 -52
  65. package/dist/schema/generate-drizzle-schema-logic.d.ts +0 -2
  66. package/dist/schema/generate-drizzle-schema.d.ts +0 -1
  67. package/dist/schema/introspect-db-inference.d.ts +0 -5
  68. package/dist/schema/introspect-db-logic.d.ts +0 -118
  69. package/dist/schema/introspect-db.d.ts +0 -1
  70. package/dist/schema/test-schema.d.ts +0 -24
  71. package/dist/services/BranchService.d.ts +0 -47
  72. package/dist/services/EntityFetchService.d.ts +0 -214
  73. package/dist/services/EntityPersistService.d.ts +0 -40
  74. package/dist/services/RelationService.d.ts +0 -98
  75. package/dist/services/entity-helpers.d.ts +0 -38
  76. package/dist/services/entityService.d.ts +0 -110
  77. package/dist/services/index.d.ts +0 -4
  78. package/dist/services/realtimeService.d.ts +0 -220
  79. package/dist/types.d.ts +0 -3
  80. package/dist/utils/drizzle-conditions.d.ts +0 -138
  81. package/dist/utils/pg-error-utils.d.ts +0 -55
  82. package/dist/websocket.d.ts +0 -11
@@ -1,353 +1,66 @@
1
- /**
2
- * Tests to verify that Rebase schema generation and drizzle-kit configuration
3
- * never attempt to drop/modify tables, enums, or other database objects
4
- * that are NOT defined in the managed schema.
5
- *
6
- * How the safety mechanism works:
7
- *
8
- * 1. `tablesFilter` in drizzle.config.ts tells drizzle-kit which tables to
9
- * introspect from the live database. Tables not in the filter are INVISIBLE
10
- * to drizzle-kit — they never enter the diff snapshot, so they can't appear
11
- * in DROP TABLE statements.
12
- *
13
- * 2. `schemaFilter` restricts to the "public" PostgreSQL schema, so tables in
14
- * other schemas (extensions, internal, etc.) are also invisible.
15
- *
16
- * 3. `entities.roles: false` prevents drizzle-kit from managing database roles.
17
- *
18
- * 4. `extensionsFilters: ["postgis"]` ignores extension-managed tables.
19
- *
20
- * 5. The CLI always passes `--strict --verbose` to `db push`, so destructive
21
- * operations require explicit confirmation even if something slips through.
22
- *
23
- * These tests verify:
24
- * - The schema generator outputs correct table/enum lists for tablesFilter
25
- * - The tablesFilter scoping correctly excludes unmapped tables
26
- * - The drizzle-kit diff engine produces no destructive SQL when the previous
27
- * snapshot only contains managed tables (simulating what tablesFilter provides)
28
- * - Unmapped tables in the raw snapshot DO produce DROP statements (proving
29
- * the tablesFilter is the critical safety boundary, not the diff engine)
30
- */
31
- import { generateDrizzleJson, generateMigration } from "drizzle-kit/api";
32
- import { pgTable, varchar, text, integer, boolean, pgEnum } from "drizzle-orm/pg-core";
33
- import { getTableName, Table } from "drizzle-orm";
34
- import { EntityCollection } from "@rebasepro/types";
35
- import { generateSchema } from "../src/schema/generate-drizzle-schema-logic";
36
-
37
- // ── Helpers ─────────────────────────────────────────────────────────────
38
-
39
- function buildPrevSnapshot(tables: Record<string, any>, enums: Record<string, any> = {}) {
40
- return {
41
- id: "prev-snapshot",
42
- prevId: "prev-prev-snapshot",
43
- version: "7",
44
- dialect: "postgresql",
45
- tables,
46
- enums,
47
- schemas: {},
48
- sequences: {},
49
- roles: {},
50
- policies: {},
51
- views: {},
52
- _meta: { schemas: {},
53
- tables: {},
54
- columns: {} }
55
- };
56
- }
57
-
58
- function snapshotTable(name: string, columns: Record<string, any>) {
59
- return {
60
- name,
61
- schema: "",
62
- columns,
63
- indexes: {},
64
- foreignKeys: {},
65
- compositePrimaryKeys: {},
66
- uniqueConstraints: {},
67
- policies: {},
68
- checkConstraints: {},
69
- isRLSEnabled: false
70
- };
71
- }
72
-
73
- function snapshotColumn(name: string, type: string, opts: {
74
- primaryKey?: boolean;
75
- notNull?: boolean;
76
- } = {}) {
77
- return {
78
- name,
79
- type,
80
- primaryKey: opts.primaryKey ?? false,
81
- notNull: opts.notNull ?? (opts.primaryKey ?? false),
82
- default: undefined
83
- };
84
- }
85
-
86
- function snapshotEnum(name: string, schema: string, values: string[]) {
87
- return { name,
88
- schema,
89
- values };
90
- }
91
-
92
- // ── Drizzle schema objects (the "managed" schema) ───────────────────────
93
-
94
- const managedUsers = pgTable("users", {
95
- id: varchar("id").primaryKey(),
96
- name: varchar("name"),
97
- email: varchar("email")
98
- });
99
-
100
- const managedPosts = pgTable("posts", {
101
- id: varchar("id").primaryKey(),
102
- title: varchar("title").notNull(),
103
- user_id: varchar("user_id")
104
- });
105
-
106
- // ── Tests ───────────────────────────────────────────────────────────────
107
-
108
- describe("Unmapped tables safety", () => {
109
-
110
- describe("tablesFilter scoping", () => {
111
-
112
- it("should extract only managed table names from the tables export", () => {
113
- const tables = { managedUsers,
114
- managedPosts };
115
- const tableNames = Object.values(tables).map(t => getTableName(t as Table));
116
-
117
- expect(tableNames).toEqual(["users", "posts"]);
118
- expect(tableNames).not.toContain("legacy_orders");
119
- expect(tableNames).not.toContain("external_analytics");
120
- });
121
-
122
- it("should produce a tablesFilter that excludes unmapped tables", () => {
123
- const tables = { managedUsers,
124
- managedPosts };
125
- const tablesFilter = Object.values(tables).map(t => getTableName(t as Table));
126
-
127
- const unmappedTables = [
128
- "legacy_orders",
129
- "external_analytics",
130
- "stripe_webhooks",
131
- "audit_log"
132
- ];
133
-
134
- for (const unmapped of unmappedTables) {
135
- expect(tablesFilter).not.toContain(unmapped);
136
- }
137
- });
138
-
139
- it("should produce stable, deterministic table names regardless of export key names", () => {
140
- // The table name comes from pgTable("table_name", ...), not the JS variable name
141
- const weirdVarName = pgTable("actual_table_name", {
142
- id: varchar("id").primaryKey()
143
- });
144
- expect(getTableName(weirdVarName as Table)).toBe("actual_table_name");
145
- });
146
- });
147
-
148
- describe("tablesFilter as the safety boundary — proof by contradiction", () => {
149
-
150
- it("without tablesFilter: drizzle-kit WOULD drop unmapped tables (proving tablesFilter is essential)", async () => {
151
- // If unmapped tables leak into the prev snapshot (i.e. tablesFilter is NOT applied),
152
- // drizzle-kit's diff engine WILL generate DROP TABLE statements.
153
- // This test proves that tablesFilter is the critical safety layer.
154
- const prevWithUnmapped = buildPrevSnapshot({
155
- "public.users": snapshotTable("users", {
156
- id: snapshotColumn("id", "varchar", { primaryKey: true }),
157
- name: snapshotColumn("name", "varchar"),
158
- email: snapshotColumn("email", "varchar")
159
- }),
160
- // An unmapped table that leaked into the snapshot
161
- "public.legacy_orders": snapshotTable("legacy_orders", {
162
- id: snapshotColumn("id", "varchar", { primaryKey: true }),
163
- amount: snapshotColumn("amount", "integer")
164
- })
165
- });
166
-
167
- const curJson = generateDrizzleJson({ managedUsers });
168
- const statements = await generateMigration(prevWithUnmapped as any, curJson as any);
169
- const sql = statements.join("\n");
170
-
171
- // WITHOUT tablesFilter, drizzle-kit WOULD drop the unmapped table.
172
- // This is expected behavior — it proves tablesFilter is essential.
173
- expect(sql).toContain("DROP TABLE");
174
- expect(sql).toContain("legacy_orders");
175
- });
176
-
177
- it("without tablesFilter: drizzle-kit WOULD drop unmapped enums (proving tablesFilter scope is essential)", async () => {
178
- const prevWithUnmappedEnum = buildPrevSnapshot(
179
- {
180
- "public.users": snapshotTable("users", {
181
- id: snapshotColumn("id", "varchar", { primaryKey: true }),
182
- name: snapshotColumn("name", "varchar"),
183
- email: snapshotColumn("email", "varchar")
184
- })
185
- },
186
- {
187
- "public.order_priority": snapshotEnum("order_priority", "public", ["low", "medium", "high"])
188
- }
189
- );
190
-
191
- const curJson = generateDrizzleJson({ managedUsers });
192
- const statements = await generateMigration(prevWithUnmappedEnum as any, curJson as any);
193
- const sql = statements.join("\n");
194
-
195
- // Without filtering, drizzle-kit drops the unmapped enum
196
- expect(sql).toContain("DROP TYPE");
197
- expect(sql).toContain("order_priority");
198
- });
199
- });
200
-
201
- describe("with tablesFilter applied: only managed tables enter the diff", () => {
202
-
203
- it("should produce zero migration statements when managed schema is unchanged", async () => {
204
- // Simulate: tablesFilter ensures only managed tables appear in the snapshot
205
- const prevOnlyManaged = buildPrevSnapshot({
206
- "public.users": snapshotTable("users", {
207
- id: snapshotColumn("id", "varchar", { primaryKey: true }),
208
- name: snapshotColumn("name", "varchar"),
209
- email: snapshotColumn("email", "varchar")
210
- }),
211
- "public.posts": snapshotTable("posts", {
212
- id: snapshotColumn("id", "varchar", { primaryKey: true }),
213
- title: snapshotColumn("title", "varchar", { notNull: true }),
214
- user_id: snapshotColumn("user_id", "varchar")
215
- })
216
- });
217
-
218
- const curJson = generateDrizzleJson({ managedUsers,
219
- managedPosts });
220
- const statements = await generateMigration(prevOnlyManaged as any, curJson as any);
221
-
222
- // No changes needed — managed schema is identical
223
- expect(statements.length).toBe(0);
224
- });
225
-
226
- it("should correctly detect changes to managed tables without touching anything else", async () => {
227
- // Prev: users has id + name (missing email)
228
- const prevOnlyManaged = buildPrevSnapshot({
229
- "public.users": snapshotTable("users", {
230
- id: snapshotColumn("id", "varchar", { primaryKey: true }),
231
- name: snapshotColumn("name", "varchar")
232
- })
233
- });
234
-
235
- const curJson = generateDrizzleJson({ managedUsers });
236
- const statements = await generateMigration(prevOnlyManaged as any, curJson as any);
237
- const sql = statements.join("\n");
238
-
239
- // Should add the email column
240
- expect(sql.toLowerCase()).toContain("alter table");
241
- expect(sql).toContain("email");
242
-
243
- // Should NOT contain any DROP TABLE
244
- expect(sql).not.toContain("DROP TABLE");
245
- });
246
- });
247
-
248
- describe("schema generation exports correct metadata for tablesFilter", () => {
249
-
250
- it("should export a tables object containing all and only defined collection tables", async () => {
251
- const collections: EntityCollection[] = [
252
- {
253
- slug: "products",
254
- table: "products",
255
- name: "Products",
256
- properties: {
257
- name: { type: "string" },
258
- price: { type: "number" }
259
- }
260
- },
261
- {
262
- slug: "categories",
263
- table: "categories",
264
- name: "Categories",
265
- properties: {
266
- title: { type: "string" }
267
- }
268
- }
269
- ];
270
-
271
- const result = await generateSchema(collections);
272
-
273
- expect(result).toContain("export const tables = {");
274
- expect(result).toContain("products");
275
- expect(result).toContain("categories");
276
- expect(result).not.toContain("legacy_orders");
277
- });
278
-
279
- it("should include junction tables in the tables export for M2M relations", async () => {
280
- const postsCollection: EntityCollection = {
1
+ import { getTableIncludesFromCollections } from "../src/cli-helpers";
2
+
3
+ describe("Unmapped tables safety with Atlas", () => {
4
+ it("should produce include filters only for managed tables and M2M junction tables", async () => {
5
+ const mockCollections = [
6
+ {
7
+ slug: "users",
8
+ table: "users",
9
+ properties: { name: { type: "string" } }
10
+ },
11
+ {
281
12
  slug: "posts",
282
13
  table: "posts",
283
- name: "Posts",
284
14
  properties: {
285
- title: { type: "string" },
286
- tags: { type: "relation",
287
- relationName: "tags" }
15
+ title: { type: "string" }
288
16
  },
289
- relations: [{
290
- relationName: "tags",
291
- target: () => tagsCollection,
292
- cardinality: "many",
293
- direction: "owning",
294
- through: {
295
- table: "posts_to_tags",
296
- sourceColumn: "post_id",
297
- targetColumn: "tag_id"
17
+ relations: [
18
+ {
19
+ relationName: "tags",
20
+ target: () => ({ table: "tags", slug: "tags" }),
21
+ cardinality: "many",
22
+ direction: "owning",
23
+ through: {
24
+ table: "posts_to_tags",
25
+ sourceColumn: "post_id",
26
+ targetColumn: "tag_id"
27
+ }
298
28
  }
299
- }]
300
- };
301
- const tagsCollection: EntityCollection = {
302
- slug: "tags",
303
- table: "tags",
304
- name: "Tags",
305
- properties: { name: { type: "string" } }
306
- };
307
-
308
- const result = await generateSchema([postsCollection, tagsCollection]);
309
-
310
- // Junction table must appear in the tables export
311
- expect(result).toContain("export const tables = {");
312
- expect(result).toContain("postsToTags");
313
- });
29
+ ]
30
+ }
31
+ ];
32
+
33
+ const includes = await getTableIncludesFromCollections(mockCollections);
34
+
35
+ // Verify only managed tables and their junctions are included
36
+ expect(includes).toContain("public.users");
37
+ expect(includes).toContain("public.posts");
38
+ expect(includes).toContain("public.posts_to_tags");
39
+
40
+ // Verify unmapped tables are NOT included, ensuring they are ignored by Atlas --include filters
41
+ const unmappedTables = [
42
+ "public.legacy_orders",
43
+ "public.external_analytics",
44
+ "public.stripe_webhooks",
45
+ "public.audit_log"
46
+ ];
47
+ for (const unmapped of unmappedTables) {
48
+ expect(includes).not.toContain(unmapped);
49
+ }
50
+ });
314
51
 
315
- it("should export enums for schema-defined enum types", async () => {
316
- const collections: EntityCollection[] = [{
52
+ it("should support custom schemas in table include paths", async () => {
53
+ const mockCollections = [
54
+ {
317
55
  slug: "orders",
318
56
  table: "orders",
319
- name: "Orders",
320
- properties: {
321
- status: {
322
- type: "string",
323
- enumValues: ["pending", "shipped", "delivered"]
324
- }
325
- }
326
- }];
327
-
328
- const result = await generateSchema(collections);
329
-
330
- expect(result).toContain("export const enums = {");
331
- });
332
- });
333
-
334
- describe("drizzle.config.ts safety properties", () => {
335
-
336
- it("schemaFilter should restrict to public schema only", () => {
337
- const schemaFilter = ["public"];
338
- expect(schemaFilter).toEqual(["public"]);
339
- expect(schemaFilter).not.toContain("information_schema");
340
- expect(schemaFilter).not.toContain("pg_catalog");
341
- });
342
-
343
- it("entities.roles should be false to prevent managing DB roles", () => {
344
- const entities = { roles: false };
345
- expect(entities.roles).toBe(false);
346
- });
57
+ schema: "sales",
58
+ properties: { id: { type: "string" } }
59
+ }
60
+ ];
347
61
 
348
- it("extensionsFilters should include postgis", () => {
349
- const extensionsFilters = ["postgis"];
350
- expect(extensionsFilters).toContain("postgis");
351
- });
62
+ const includes = await getTableIncludesFromCollections(mockCollections);
63
+ expect(includes).toContain("sales.orders");
64
+ expect(includes).not.toContain("public.orders");
352
65
  });
353
66
  });
package/vite.config.ts CHANGED
@@ -45,6 +45,7 @@ export default defineConfig(() => ({
45
45
  lib: {
46
46
  entry: path.resolve(__dirname, "src/index.ts"),
47
47
  name: "Rebase Backend",
48
+ formats: ["es"],
48
49
  fileName: (format) => `index.${format}.js`
49
50
  },
50
51
  target: "ESNEXT",
@@ -52,13 +53,14 @@ export default defineConfig(() => ({
52
53
  sourcemap: true,
53
54
  rollupOptions: {
54
55
  external: isExternal,
56
+ onwarn(warning, warn) {
57
+ if (warning.code === "MISSING_GLOBAL_NAME") return;
58
+ if (warning.code === "INEFFECTIVE_DYNAMIC_IMPORT") return;
59
+ if (warning.code === "EMPTY_IMPORT_META") return;
60
+ warn(warning);
61
+ },
55
62
  output: {
56
- banner: 'import { createRequire as __createRequire } from "module"; import process from "process"; const require = __createRequire(import.meta.url);',
57
- globals: {
58
- "json-logic-js": "jsonLogic",
59
- "fast-equals": "fastEquals",
60
- "lodash/cloneDeep.js": "cloneDeep"
61
- }
63
+ banner: 'import { createRequire as __createRequire } from "module"; import process from "process"; const require = __createRequire(import.meta.url);'
62
64
  }
63
65
  }
64
66
  },
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: "node",
7
+ include: ["test/e2e/**/*.test.ts"],
8
+ testTimeout: 180_000 // 3 min — container startup + migrations
9
+ }
10
+ });
package/build-errors.txt DELETED
@@ -1,37 +0,0 @@
1
-
2
- > @rebasepro/server-postgresql@0.0.1 build /Users/francesco/rebase/packages/server-postgresql
3
- > vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json
4
-
5
- vite v5.4.21 building for production...
6
- transforming...
7
- ✓ 328 modules transformed.
8
- rendering chunks...
9
- computing gzip size...
10
- dist/index.es.js 434.54 kB │ gzip: 83.11 kB │ map: 1,031.37 kB
11
- dist/index.umd.js 459.59 kB │ gzip: 84.58 kB │ map: 1,035.30 kB
12
- ✓ built in 1.23s
13
- src/auth/services.ts(119,15): error TS2322: Type '{ id: unknown; email: unknown; passwordHash: {} | null; displayName: {} | null; photoUrl: {} | null; provider: unknown; googleId: {} | null; emailVerified: {}; emailVerificationToken: {} | null; emailVerificationSentAt: {} | null; createdAt: unknown; updatedAt: unknown; }[]' is not assignable to type '{ email: string; id: string; createdAt: Date; passwordHash: string | null; displayName: string | null; photoUrl: string | null; provider: string; googleId: string | null; emailVerified: boolean; emailVerificationToken: string | null; emailVerificationSentAt: Date | null; updatedAt: Date; }[]'.
14
- Type '{ id: unknown; email: unknown; passwordHash: {} | null; displayName: {} | null; photoUrl: {} | null; provider: unknown; googleId: {} | null; emailVerified: {}; emailVerificationToken: {} | null; emailVerificationSentAt: {} | null; createdAt: unknown; updatedAt: unknown; }' is not assignable to type '{ email: string; id: string; createdAt: Date; passwordHash: string | null; displayName: string | null; photoUrl: string | null; provider: string; googleId: string | null; emailVerified: boolean; emailVerificationToken: string | null; emailVerificationSentAt: Date | null; updatedAt: Date; }'.
15
- Types of property 'email' are incompatible.
16
- Type 'unknown' is not assignable to type 'string'.
17
- src/collections/PostgresCollectionRegistry.ts(90,143): error TS2344: Type 'Record<string, unknown>' does not satisfy the constraint 'User'.
18
- Type 'Record<string, unknown>' is missing the following properties from type 'User': uid, displayName, email, photoURL, and 2 more.
19
- src/PostgresBootstrapper.ts(201,59): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'Partial<HistoryRetentionConfig> | undefined'.
20
- Type 'number' has no properties in common with type 'Partial<HistoryRetentionConfig>'.
21
- src/schema/generate-drizzle-schema-logic.ts(455,121): error TS2344: Type 'Record<string, unknown>' does not satisfy the constraint 'User'.
22
- Type 'Record<string, unknown>' is missing the following properties from type 'User': uid, displayName, email, photoURL, and 2 more.
23
- src/services/EntityFetchService.ts(37,72): error TS2344: Type 'Record<string, unknown>' does not satisfy the constraint 'TablesRelationalConfig'.
24
- 'string' index signatures are incompatible.
25
- Type 'unknown' is not assignable to type 'TableRelationalConfig'.
26
- src/services/EntityFetchService.ts(39,61): error TS2344: Type 'Record<string, unknown>' does not satisfy the constraint 'TablesRelationalConfig'.
27
- 'string' index signatures are incompatible.
28
- Type 'unknown' is not assignable to type 'TableRelationalConfig'.
29
- src/services/realtimeService.ts(621,21): error TS2322: Type 'Record<string, unknown> | undefined' is not assignable to type 'Partial<Record<string, [WhereFilterOp, unknown]>> | undefined'.
30
- Type 'Record<string, unknown>' is not assignable to type 'Partial<Record<string, [WhereFilterOp, unknown]>>'.
31
- 'string' index signatures are incompatible.
32
- Type 'unknown' is not assignable to type '[WhereFilterOp, unknown] | undefined'.
33
- src/services/realtimeService.ts(630,13): error TS2322: Type 'Record<string, unknown> | undefined' is not assignable to type 'Partial<Record<string, [WhereFilterOp, unknown]>> | undefined'.
34
- Type 'Record<string, unknown>' is not assignable to type 'Partial<Record<string, [WhereFilterOp, unknown]>>'.
35
- 'string' index signatures are incompatible.
36
- Type 'unknown' is not assignable to type '[WhereFilterOp, unknown] | undefined'.
37
-  ELIFECYCLE  Command failed with exit code 2.
@@ -1,6 +0,0 @@
1
- import { DatabaseAdapter } from "@rebasepro/types";
2
- import type { PostgresDriverConfig } from "./PostgresBootstrapper";
3
- /**
4
- * Creates a Postgres database adapter for Rebase.
5
- */
6
- export declare function createPostgresAdapter(pgConfig: PostgresDriverConfig): DatabaseAdapter;
@@ -1,110 +0,0 @@
1
- import { EntityService } from "./services/entityService";
2
- import { BranchService } from "./services/BranchService";
3
- import { RealtimeService } from "./services/realtimeService";
4
- import { DatabasePoolManager } from "./databasePoolManager";
5
- import { DrizzleClient } from "./interfaces";
6
- import { DatabaseAdmin, DataDriver, DeleteEntityProps, Entity, EntityCollection, FetchCollectionProps, FetchEntityProps, ListenCollectionProps, ListenEntityProps, RebaseClient, RebaseData, RestFetchService, SaveEntityProps, TableMetadata, User } from "@rebasepro/types";
7
- import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
8
- import { HistoryService } from "./history/HistoryService";
9
- export declare class PostgresBackendDriver implements DataDriver {
10
- db: DrizzleClient;
11
- readonly registry: PostgresCollectionRegistry;
12
- poolManager?: DatabasePoolManager | undefined;
13
- key: string;
14
- initialised: boolean;
15
- entityService: EntityService;
16
- realtimeService: RealtimeService;
17
- historyService?: HistoryService;
18
- branchService?: BranchService;
19
- user?: User;
20
- data: RebaseData;
21
- client?: RebaseClient;
22
- /**
23
- * When true, realtime notifications are deferred until after the
24
- * wrapping transaction commits. Set by `withAuth` → `withTransaction`.
25
- */
26
- _deferNotifications: boolean;
27
- _pendingNotifications: Array<{
28
- path: string;
29
- entityId: string;
30
- entity: Entity | null;
31
- databaseId?: string;
32
- }>;
33
- constructor(db: DrizzleClient, realtimeService: RealtimeService, registry: PostgresCollectionRegistry, user?: User, poolManager?: DatabasePoolManager | undefined, historyService?: HistoryService);
34
- /**
35
- * Typed admin capabilities (SQLAdmin + SchemaAdmin + BranchAdmin).
36
- * Implemented as a getter so method references are resolved at call-time,
37
- * allowing test spies applied after construction to take effect.
38
- */
39
- get admin(): DatabaseAdmin;
40
- /**
41
- * REST-optimised fetch service (include-aware eager-loading).
42
- * Delegates to the underlying EntityFetchService which already
43
- * implements the matching method signatures.
44
- */
45
- get restFetchService(): import("./services").EntityFetchService;
46
- private buildCallContext;
47
- private resolveCollectionCallbacks;
48
- fetchCollection<M extends Record<string, unknown>>({ path, collection, filter, limit, offset, startAfter, orderBy, searchString, order, vectorSearch }: FetchCollectionProps<M>): Promise<Entity<M>[]>;
49
- listenCollection<M extends Record<string, unknown>>({ path, collection, filter, limit, offset, startAfter, orderBy, searchString, order, onUpdate, onError }: ListenCollectionProps<M>): () => void;
50
- fetchEntity<M extends Record<string, unknown>>({ path, entityId, databaseId, collection }: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
51
- listenEntity<M extends Record<string, unknown>>({ path, entityId, collection, onUpdate, onError }: ListenEntityProps<M>): () => void;
52
- saveEntity<M extends Record<string, unknown>>({ path, entityId, values, collection, status }: SaveEntityProps<M>): Promise<Entity<M>>;
53
- deleteEntity<M extends Record<string, unknown>>({ entity, collection }: DeleteEntityProps<M>): Promise<void>;
54
- deleteAll(path: string): Promise<void>;
55
- checkUniqueField(path: string, name: string, value: unknown, entityId?: string, collection?: EntityCollection): Promise<boolean>;
56
- countEntities<M extends Record<string, unknown>>({ path, collection, filter, searchString }: FetchCollectionProps<M>): Promise<number>;
57
- private getTargetDb;
58
- executeSql(sqlText: string, options?: {
59
- database?: string;
60
- role?: string;
61
- }): Promise<Record<string, unknown>[]>;
62
- fetchAvailableDatabases(): Promise<string[]>;
63
- fetchAvailableRoles(): Promise<string[]>;
64
- fetchCurrentDatabase(): Promise<string | undefined>;
65
- /**
66
- * Fetch public tables that are not yet mapped to a collection.
67
- * Excludes internal tables (_rebase_*, _auth_*, auth tables, etc.)
68
- * and junction/connection tables used for many-to-many relations.
69
- */
70
- fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]>;
71
- /**
72
- * Fetch metadata for a given table from information_schema (columns, policies, constraints).
73
- */
74
- fetchTableMetadata(tableName: string): Promise<TableMetadata>;
75
- private generateSubscriptionId;
76
- /**
77
- * Create a new delegate instance with authenticated context.
78
- * Starts a transaction and sets the current_user_id and current_user_roles
79
- * configuration parameters for PostgreSQL Row Level Security.
80
- */
81
- withAuth(user: User): Promise<DataDriver>;
82
- }
83
- export declare class AuthenticatedPostgresBackendDriver implements DataDriver {
84
- delegate: PostgresBackendDriver;
85
- key: string;
86
- initialised: boolean;
87
- user: User;
88
- data: RebaseData;
89
- constructor(delegate: PostgresBackendDriver, user: User);
90
- /**
91
- * Typed admin capabilities — delegates to the base driver.
92
- */
93
- admin: DatabaseAdmin;
94
- get restFetchService(): RestFetchService | undefined;
95
- private withTransaction;
96
- fetchCollection<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]>;
97
- /**
98
- * Injects the authenticated user's context into the most recently
99
- * registered realtime subscription so RLS-aware polling can apply.
100
- */
101
- private injectAuthContext;
102
- listenCollection<M extends Record<string, unknown>>(props: ListenCollectionProps<M>): () => void;
103
- fetchEntity<M extends Record<string, unknown>>(props: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
104
- listenEntity<M extends Record<string, unknown>>(props: ListenEntityProps<M>): () => void;
105
- saveEntity<M extends Record<string, unknown>>(props: SaveEntityProps<M>): Promise<Entity<M>>;
106
- deleteEntity<M extends Record<string, unknown>>(props: DeleteEntityProps<M>): Promise<void>;
107
- deleteAll(path: string): Promise<void>;
108
- checkUniqueField(path: string, name: string, value: unknown, entityId?: string, collection?: EntityCollection): Promise<boolean>;
109
- countEntities<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;
110
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * PostgresBootstrapper
3
- *
4
- * Implements the `BackendBootstrapper` interface for PostgreSQL.
5
- */
6
- import { NodePgDatabase } from "drizzle-orm/node-postgres";
7
- import { BackendBootstrapper } from "@rebasepro/types";
8
- import { PostgresBackendDriver } from "./PostgresBackendDriver";
9
- import { RealtimeService } from "./services/realtimeService";
10
- import { DatabasePoolManager } from "./databasePoolManager";
11
- import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
12
- export interface PostgresDriverConfig {
13
- connectionString?: string;
14
- adminConnectionString?: string;
15
- readConnectionString?: string;
16
- connection?: unknown;
17
- schema?: {
18
- tables?: Record<string, unknown>;
19
- enums?: Record<string, unknown>;
20
- relations?: Record<string, unknown>;
21
- };
22
- }
23
- /**
24
- * Opaque internals bag that PostgresBootstrapper stores during `initializeDriver()`
25
- * and re-uses in subsequent lifecycle hooks.
26
- */
27
- export interface PostgresDriverInternals {
28
- db: NodePgDatabase<any>;
29
- readDb?: NodePgDatabase<any>;
30
- registry: PostgresCollectionRegistry;
31
- realtimeService: RealtimeService;
32
- driver: PostgresBackendDriver;
33
- poolManager?: DatabasePoolManager;
34
- }
35
- /**
36
- * Default PostgreSQL bootstrapper.
37
- *
38
- * Use it to register Postgres with `initializeRebaseBackend()`:
39
- * ```typescript
40
- * initializeRebaseBackend({
41
- * ...config,
42
- * bootstrappers: [postgresBootstrapper()]
43
- * });
44
- * ```
45
- */
46
- export declare function createPostgresBootstrapper(pgConfig: PostgresDriverConfig): BackendBootstrapper;