@rebasepro/server-postgresql 0.3.0 → 0.5.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 (60) hide show
  1. package/README.md +69 -89
  2. package/dist/common/src/collections/default-collections.d.ts +5 -8
  3. package/dist/common/src/data/query_builder.d.ts +6 -2
  4. package/dist/common/src/util/permissions.d.ts +14 -6
  5. package/dist/index.es.js +379 -611
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +375 -607
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +2 -0
  10. package/dist/server-postgresql/src/auth/ensure-tables.d.ts +7 -4
  11. package/dist/server-postgresql/src/auth/services.d.ts +17 -42
  12. package/dist/server-postgresql/src/data-transformer.d.ts +0 -3
  13. package/dist/server-postgresql/src/databasePoolManager.d.ts +1 -1
  14. package/dist/server-postgresql/src/schema/auth-schema.d.ts +87 -340
  15. package/dist/server-postgresql/src/services/EntityFetchService.d.ts +2 -1
  16. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +4 -0
  17. package/dist/server-postgresql/src/services/entityService.d.ts +4 -0
  18. package/dist/server-postgresql/src/types.d.ts +3 -0
  19. package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +5 -1
  20. package/dist/server-postgresql/src/websocket.d.ts +8 -3
  21. package/dist/types/src/controllers/auth.d.ts +2 -2
  22. package/dist/types/src/controllers/client.d.ts +25 -40
  23. package/dist/types/src/controllers/data.d.ts +21 -3
  24. package/dist/types/src/controllers/data_driver.d.ts +5 -0
  25. package/dist/types/src/controllers/email.d.ts +2 -0
  26. package/dist/types/src/types/auth_adapter.d.ts +3 -56
  27. package/dist/types/src/types/backend.d.ts +38 -3
  28. package/dist/types/src/types/backend_hooks.d.ts +2 -17
  29. package/dist/types/src/types/collections.d.ts +30 -6
  30. package/dist/types/src/types/entity_views.d.ts +19 -28
  31. package/dist/types/src/types/properties.d.ts +9 -15
  32. package/dist/types/src/types/user_management_delegate.d.ts +16 -53
  33. package/dist/types/src/users/index.d.ts +0 -1
  34. package/dist/types/src/users/user.d.ts +0 -1
  35. package/package.json +6 -6
  36. package/src/PostgresBackendDriver.ts +10 -0
  37. package/src/PostgresBootstrapper.ts +27 -22
  38. package/src/auth/ensure-tables.ts +82 -129
  39. package/src/auth/services.ts +99 -197
  40. package/src/cli.ts +50 -23
  41. package/src/data-transformer.ts +57 -95
  42. package/src/databasePoolManager.ts +2 -1
  43. package/src/schema/auth-schema.ts +13 -69
  44. package/src/schema/doctor.ts +44 -3
  45. package/src/schema/generate-drizzle-schema-logic.ts +33 -3
  46. package/src/schema/generate-drizzle-schema.ts +2 -6
  47. package/src/schema/introspect-db-logic.ts +7 -0
  48. package/src/services/EntityFetchService.ts +13 -1
  49. package/src/services/EntityPersistService.ts +38 -12
  50. package/src/services/entityService.ts +7 -0
  51. package/src/types.ts +4 -0
  52. package/src/utils/drizzle-conditions.ts +40 -5
  53. package/src/websocket.ts +38 -25
  54. package/test/auth-services.test.ts +7 -150
  55. package/test/doctor.test.ts +6 -2
  56. package/test/relation-pipeline-gaps.test.ts +315 -0
  57. package/dist/server-postgresql/src/schema/default-collections.d.ts +0 -2
  58. package/dist/types/src/users/roles.d.ts +0 -14
  59. package/drizzle.test.config.ts +0 -10
  60. package/src/schema/default-collections.ts +0 -69
package/README.md CHANGED
@@ -1,106 +1,86 @@
1
- # @rebasepro/postgresql
1
+ # @rebasepro/server-postgresql
2
2
 
3
- PostgreSQL data source client for Rebase with real-time WebSocket connectivity.
4
-
5
- This package provides a complete client-side implementation for connecting Rebase applications to PostgreSQL backends, featuring real-time synchronization via WebSockets.
3
+ PostgreSQL database driver for Rebase, built on Drizzle ORM.
6
4
 
7
5
  ## Installation
8
6
 
9
7
  ```bash
10
- npm install @rebasepro/postgresql @rebasepro/core
8
+ pnpm add @rebasepro/server-postgresql
11
9
  ```
12
10
 
13
- ## Usage
11
+ ## What This Package Does
14
12
 
15
- ### Basic Setup with React Hook
13
+ Implements the Rebase `DatabaseAdapter` / `BackendBootstrapper` interfaces for PostgreSQL. It provides connection pooling, a Drizzle-based data driver, Postgres LISTEN/NOTIFY realtime, auth table management, entity history, schema generation, branching, read replicas, and WebSocket support. Plug it into `@rebasepro/server-core` via `createPostgresAdapter()` or `createPostgresBootstrapper()`.
16
14
 
17
- ```typescript
18
- import { usePostgresDataSource } from "@rebasepro/postgresql";
19
- import { Rebase } from "@rebasepro/core";
20
-
21
- function App() {
22
- const dataSource = usePostgresDataSource({
23
- baseUrl: "http://localhost:3001",
24
- websocketUrl: "ws://localhost:3001", // Optional, will be inferred from baseUrl
25
- headers: { // Optional
26
- "Authorization": "Bearer your-token"
27
- }
28
- });
29
-
30
- return (
31
- <Rebase
32
- dataSource={dataSource}
33
- collections={collections}
34
- // ... other props
35
- />
36
- );
37
- }
38
- ```
15
+ ## Key Exports
39
16
 
40
- ### Creating Data Source Directly
17
+ | Export | Description |
18
+ |--------|-------------|
19
+ | `createPostgresAdapter(config)` | Creates a `DatabaseAdapter` for use with `initializeRebaseBackend({ database: ... })`. Recommended API. |
20
+ | `createPostgresBootstrapper(config)` | Lower-level `BackendBootstrapper` factory. Used internally by the adapter. |
21
+ | `createPostgresDatabaseConnection(url, schema?, poolConfig?)` | Creates a production-grade pooled Drizzle connection. Returns `{ db, pool, connectionString }`. |
22
+ | `createDirectDatabaseConnection(url, schema?, poolConfig?)` | Non-pooled connection for LISTEN/NOTIFY and advisory locks (bypasses PgBouncer). |
23
+ | `createReadReplicaConnection(url, schema?, poolConfig?)` | Read-only connection for routing reads to replicas. |
24
+ | `PostgresBackendDriver` | The `DataDriver` implementation — CRUD, filtering, RLS, subcollections, admin SQL. |
25
+ | `RealtimeService` | Postgres LISTEN/NOTIFY-based `RealtimeProvider`. |
26
+ | `DatabasePoolManager` | Per-branch/per-tenant dynamic pool management (used with `ADMIN_CONNECTION_STRING`). |
27
+ | `PostgresCollectionRegistry` | Collection → Drizzle table registry with enum and relation tracking. |
28
+ | `BranchService` | Database branching (schema-level isolation). |
29
+ | `generateDrizzleSchema(collections)` | Generates Drizzle schema code from collection definitions. |
30
+ | `createAuthSchema(schemaName?)` | Generates Drizzle tables for the auth system (`users`, `roles`, `user_roles`). |
41
31
 
42
- ```typescript
43
- import { createPostgresDataSource } from "@rebasepro/postgresql";
32
+ ## Quick Start
44
33
 
45
- const dataSource = createPostgresDataSource({
46
- baseUrl: "http://localhost:3001",
47
- websocketUrl: "ws://localhost:3001"
34
+ ```typescript
35
+ import { createPostgresDatabaseConnection } from "@rebasepro/server-postgresql";
36
+ import { createPostgresAdapter } from "@rebasepro/server-postgresql";
37
+ import { initializeRebaseBackend } from "@rebasepro/server-core";
38
+ import * as schema from "./generated/schema";
39
+
40
+ // Create connection
41
+ const { db, pool } = createPostgresDatabaseConnection(
42
+ process.env.DATABASE_URL,
43
+ schema
44
+ );
45
+
46
+ // Create adapter and pass to server-core
47
+ const database = createPostgresAdapter({
48
+ connection: db,
49
+ connectionString: process.env.DATABASE_URL,
50
+ schema: { tables: schema },
48
51
  });
49
- ```
50
52
 
51
- ## Features
52
-
53
- - **Real-time Synchronization**: WebSocket-based real-time updates for collections and entities
54
- - **Automatic Reconnection**: Built-in reconnection logic with exponential backoff
55
- - **Type Safety**: Full TypeScript support with Rebase core types
56
- - **Error Handling**: Comprehensive error handling with custom error types
57
- - **Connection Management**: Connection status monitoring and queue management
58
-
59
- ## API
60
-
61
- ### Configuration
53
+ const backend = await initializeRebaseBackend({
54
+ app,
55
+ server,
56
+ database,
57
+ collections,
58
+ auth: { /* ... */ },
59
+ });
62
60
 
63
- ```typescript
64
- interface PostgresDataSourceConfig {
65
- baseUrl: string; // Backend server URL
66
- websocketUrl?: string; // WebSocket URL (optional)
67
- headers?: Record<string, string>; // Custom headers (optional)
68
- }
61
+ // Graceful shutdown
62
+ process.on("SIGTERM", async () => {
63
+ await backend.shutdown();
64
+ await pool.end();
65
+ });
69
66
  ```
70
67
 
71
- ### Methods
72
-
73
- The PostgreSQL data source implements all Rebase `DataSource` methods:
74
-
75
- - `fetchCollection<M>(props): Promise<Entity<M>[]>`
76
- - `fetchEntity<M>(props): Promise<Entity<M> | undefined>`
77
- - `saveEntity<M>(props): Promise<Entity<M>>`
78
- - `deleteEntity<M>(props): Promise<void>`
79
- - `checkUniqueField(...): Promise<boolean>`
80
- - `generateEntityId(...): string`
81
- - `countEntities<M>(props): Promise<number>`
82
- - `listenCollection<M>(props): () => void`
83
- - `listenEntity<M>(props): () => void`
84
-
85
- ## Backend Requirements
86
-
87
- This client expects a WebSocket-enabled backend that handles the following message types:
88
-
89
- - `FETCH_COLLECTION`
90
- - `FETCH_ENTITY`
91
- - `SAVE_ENTITY`
92
- - `DELETE_ENTITY`
93
- - `CHECK_UNIQUE_FIELD`
94
- - `GENERATE_ENTITY_ID`
95
- - `COUNT_ENTITIES`
96
- - `subscribe_collection`
97
- - `subscribe_entity`
98
- - `unsubscribe`
99
-
100
- ## Development
101
-
102
- This package is part of the Rebase monorepo. For development instructions, see the main repository README.
103
-
104
- ## License
105
-
106
- MIT
68
+ ## Connection Pool Defaults
69
+
70
+ | Option | Default |
71
+ |--------|---------|
72
+ | `max` | 20 |
73
+ | `idleTimeoutMillis` | 30,000 |
74
+ | `connectionTimeoutMillis` | 10,000 |
75
+ | `queryTimeout` | 30,000 |
76
+ | `statementTimeout` | 30,000 |
77
+ | `keepAlive` | true |
78
+
79
+ ## Related Packages
80
+
81
+ | Package | Role |
82
+ |---------|------|
83
+ | `@rebasepro/server-core` | Backend orchestrator that consumes this adapter |
84
+ | `@rebasepro/types` | Shared interfaces (`DatabaseAdapter`, `BackendBootstrapper`, `DataDriver`) |
85
+ | `@rebasepro/sdk-generator` | Generates typed SDKs from collections |
86
+ | `@rebasepro/common` | Default collections and shared utilities |
@@ -1,12 +1,9 @@
1
- import { PostgresCollection } from "@rebasepro/types";
1
+ import type { PostgresCollection } from "@rebasepro/types";
2
2
  /**
3
- * Default users collection definition.
3
+ * Default users collection.
4
4
  *
5
- * Shared between the admin UI (for navigation/display) and the backend
6
- * (for schema generation). Both consumers prepend this to the developer's
7
- * collections array and rely on generic slug-based deduplication
8
- * (Map keyed by slug, last-write-wins) so that developer-defined
9
- * collections with the same slug override this default — no hardcoded
10
- * string checks required.
5
+ * Prepended to the developer's collections array by the admin and server.
6
+ * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers
7
+ * override by defining their own collection with `slug: "users"`.
11
8
  */
12
9
  export declare const defaultUsersCollection: PostgresCollection;
@@ -1,4 +1,7 @@
1
- import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator } from "@rebasepro/types";
1
+ import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator, LogicalCondition, WhereValue, FilterCondition } from "@rebasepro/types";
2
+ export declare function or(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
3
+ export declare function and(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition;
4
+ export declare function cond(column: string, operator: FilterOperator, value: unknown): FilterCondition;
2
5
  export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {
3
6
  private collection;
4
7
  private params;
@@ -8,7 +11,8 @@ export declare class QueryBuilder<M extends Record<string, unknown> = Record<str
8
11
  * @example
9
12
  * client.collection('users').where('age', '>=', 18).find()
10
13
  */
11
- where(column: keyof M & string, operator: FilterOperator, value: unknown): this;
14
+ where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;
15
+ where(logicalCondition: LogicalCondition): this;
12
16
  /**
13
17
  * Order the results by a specific column.
14
18
  * @example
@@ -1,6 +1,14 @@
1
- import { AuthController, Entity, EntityCollection, User } from "@rebasepro/types";
2
- export declare function checkOperation<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, entity: Entity<M> | null, targetOperation: "select" | "insert" | "update" | "delete"): boolean;
3
- export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>): boolean;
4
- export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
5
- export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
6
- export declare function canDeleteEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
1
+ import { Entity, EntityCollection, User } from "@rebasepro/types";
2
+ /**
3
+ * Minimal auth context for permission checking.
4
+ * Only requires the user object avoids forcing callers to construct
5
+ * a full AuthController just to check permissions.
6
+ */
7
+ export interface AuthContext<USER extends User = User> {
8
+ user: USER | null;
9
+ }
10
+ export declare function checkOperation<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, entity: Entity<M> | null, targetOperation: "select" | "insert" | "update" | "delete"): boolean;
11
+ export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>): boolean;
12
+ export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
13
+ export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
14
+ export declare function canDeleteEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;