@rebasepro/server-postgresql 0.0.1-canary.09e5ec5

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 (196) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +106 -0
  3. package/build-errors.txt +37 -0
  4. package/dist/common/src/collections/CollectionRegistry.d.ts +56 -0
  5. package/dist/common/src/collections/index.d.ts +1 -0
  6. package/dist/common/src/data/buildRebaseData.d.ts +14 -0
  7. package/dist/common/src/index.d.ts +3 -0
  8. package/dist/common/src/util/builders.d.ts +57 -0
  9. package/dist/common/src/util/callbacks.d.ts +6 -0
  10. package/dist/common/src/util/collections.d.ts +11 -0
  11. package/dist/common/src/util/common.d.ts +2 -0
  12. package/dist/common/src/util/conditions.d.ts +26 -0
  13. package/dist/common/src/util/entities.d.ts +58 -0
  14. package/dist/common/src/util/enums.d.ts +3 -0
  15. package/dist/common/src/util/index.d.ts +16 -0
  16. package/dist/common/src/util/navigation_from_path.d.ts +34 -0
  17. package/dist/common/src/util/navigation_utils.d.ts +20 -0
  18. package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
  19. package/dist/common/src/util/paths.d.ts +14 -0
  20. package/dist/common/src/util/permissions.d.ts +5 -0
  21. package/dist/common/src/util/references.d.ts +2 -0
  22. package/dist/common/src/util/relations.d.ts +22 -0
  23. package/dist/common/src/util/resolutions.d.ts +72 -0
  24. package/dist/common/src/util/storage.d.ts +24 -0
  25. package/dist/index.es.js +11298 -0
  26. package/dist/index.es.js.map +1 -0
  27. package/dist/index.umd.js +11306 -0
  28. package/dist/index.umd.js.map +1 -0
  29. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +100 -0
  30. package/dist/server-postgresql/src/PostgresBootstrapper.d.ts +40 -0
  31. package/dist/server-postgresql/src/auth/ensure-tables.d.ts +6 -0
  32. package/dist/server-postgresql/src/auth/services.d.ts +192 -0
  33. package/dist/server-postgresql/src/cli.d.ts +1 -0
  34. package/dist/server-postgresql/src/collections/PostgresCollectionRegistry.d.ts +43 -0
  35. package/dist/server-postgresql/src/connection.d.ts +40 -0
  36. package/dist/server-postgresql/src/data-transformer.d.ts +58 -0
  37. package/dist/server-postgresql/src/databasePoolManager.d.ts +20 -0
  38. package/dist/server-postgresql/src/history/HistoryService.d.ts +71 -0
  39. package/dist/server-postgresql/src/history/ensure-history-table.d.ts +7 -0
  40. package/dist/server-postgresql/src/index.d.ts +13 -0
  41. package/dist/server-postgresql/src/interfaces.d.ts +18 -0
  42. package/dist/server-postgresql/src/schema/auth-schema.d.ts +868 -0
  43. package/dist/server-postgresql/src/schema/doctor-cli.d.ts +2 -0
  44. package/dist/server-postgresql/src/schema/doctor.d.ts +43 -0
  45. package/dist/server-postgresql/src/schema/generate-drizzle-schema-logic.d.ts +2 -0
  46. package/dist/server-postgresql/src/schema/generate-drizzle-schema.d.ts +1 -0
  47. package/dist/server-postgresql/src/schema/introspect-db-logic.d.ts +82 -0
  48. package/dist/server-postgresql/src/schema/introspect-db.d.ts +1 -0
  49. package/dist/server-postgresql/src/schema/test-schema.d.ts +24 -0
  50. package/dist/server-postgresql/src/services/BranchService.d.ts +47 -0
  51. package/dist/server-postgresql/src/services/EntityFetchService.d.ts +209 -0
  52. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +41 -0
  53. package/dist/server-postgresql/src/services/RelationService.d.ts +98 -0
  54. package/dist/server-postgresql/src/services/entity-helpers.d.ts +38 -0
  55. package/dist/server-postgresql/src/services/entityService.d.ts +104 -0
  56. package/dist/server-postgresql/src/services/index.d.ts +4 -0
  57. package/dist/server-postgresql/src/services/realtimeService.d.ts +188 -0
  58. package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +116 -0
  59. package/dist/server-postgresql/src/websocket.d.ts +5 -0
  60. package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
  61. package/dist/types/src/controllers/auth.d.ts +119 -0
  62. package/dist/types/src/controllers/client.d.ts +170 -0
  63. package/dist/types/src/controllers/collection_registry.d.ts +45 -0
  64. package/dist/types/src/controllers/customization_controller.d.ts +60 -0
  65. package/dist/types/src/controllers/data.d.ts +168 -0
  66. package/dist/types/src/controllers/data_driver.d.ts +160 -0
  67. package/dist/types/src/controllers/database_admin.d.ts +11 -0
  68. package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
  69. package/dist/types/src/controllers/effective_role.d.ts +4 -0
  70. package/dist/types/src/controllers/email.d.ts +34 -0
  71. package/dist/types/src/controllers/index.d.ts +18 -0
  72. package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
  73. package/dist/types/src/controllers/navigation.d.ts +213 -0
  74. package/dist/types/src/controllers/registry.d.ts +54 -0
  75. package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
  76. package/dist/types/src/controllers/side_entity_controller.d.ts +90 -0
  77. package/dist/types/src/controllers/snackbar.d.ts +24 -0
  78. package/dist/types/src/controllers/storage.d.ts +171 -0
  79. package/dist/types/src/index.d.ts +4 -0
  80. package/dist/types/src/rebase_context.d.ts +105 -0
  81. package/dist/types/src/types/backend.d.ts +536 -0
  82. package/dist/types/src/types/builders.d.ts +15 -0
  83. package/dist/types/src/types/chips.d.ts +5 -0
  84. package/dist/types/src/types/collections.d.ts +856 -0
  85. package/dist/types/src/types/cron.d.ts +102 -0
  86. package/dist/types/src/types/data_source.d.ts +64 -0
  87. package/dist/types/src/types/entities.d.ts +145 -0
  88. package/dist/types/src/types/entity_actions.d.ts +98 -0
  89. package/dist/types/src/types/entity_callbacks.d.ts +173 -0
  90. package/dist/types/src/types/entity_link_builder.d.ts +7 -0
  91. package/dist/types/src/types/entity_overrides.d.ts +10 -0
  92. package/dist/types/src/types/entity_views.d.ts +61 -0
  93. package/dist/types/src/types/export_import.d.ts +21 -0
  94. package/dist/types/src/types/index.d.ts +23 -0
  95. package/dist/types/src/types/locales.d.ts +4 -0
  96. package/dist/types/src/types/modify_collections.d.ts +5 -0
  97. package/dist/types/src/types/plugins.d.ts +279 -0
  98. package/dist/types/src/types/properties.d.ts +1176 -0
  99. package/dist/types/src/types/property_config.d.ts +70 -0
  100. package/dist/types/src/types/relations.d.ts +336 -0
  101. package/dist/types/src/types/slots.d.ts +252 -0
  102. package/dist/types/src/types/translations.d.ts +870 -0
  103. package/dist/types/src/types/user_management_delegate.d.ts +121 -0
  104. package/dist/types/src/types/websockets.d.ts +78 -0
  105. package/dist/types/src/users/index.d.ts +2 -0
  106. package/dist/types/src/users/roles.d.ts +22 -0
  107. package/dist/types/src/users/user.d.ts +46 -0
  108. package/drizzle-test/0000_woozy_junta.sql +6 -0
  109. package/drizzle-test/0001_youthful_arachne.sql +1 -0
  110. package/drizzle-test/0002_lively_dragon_lord.sql +2 -0
  111. package/drizzle-test/0003_mean_king_cobra.sql +2 -0
  112. package/drizzle-test/meta/0000_snapshot.json +47 -0
  113. package/drizzle-test/meta/0001_snapshot.json +48 -0
  114. package/drizzle-test/meta/0002_snapshot.json +38 -0
  115. package/drizzle-test/meta/0003_snapshot.json +48 -0
  116. package/drizzle-test/meta/_journal.json +34 -0
  117. package/drizzle-test-out/0000_tan_trauma.sql +6 -0
  118. package/drizzle-test-out/0001_rapid_drax.sql +1 -0
  119. package/drizzle-test-out/meta/0000_snapshot.json +44 -0
  120. package/drizzle-test-out/meta/0001_snapshot.json +54 -0
  121. package/drizzle-test-out/meta/_journal.json +20 -0
  122. package/drizzle.test.config.ts +10 -0
  123. package/jest-all.log +3128 -0
  124. package/jest.log +49 -0
  125. package/package.json +92 -0
  126. package/scratch.ts +41 -0
  127. package/src/PostgresBackendDriver.ts +1008 -0
  128. package/src/PostgresBootstrapper.ts +231 -0
  129. package/src/auth/ensure-tables.ts +381 -0
  130. package/src/auth/services.ts +799 -0
  131. package/src/cli.ts +648 -0
  132. package/src/collections/PostgresCollectionRegistry.ts +96 -0
  133. package/src/connection.ts +84 -0
  134. package/src/data-transformer.ts +608 -0
  135. package/src/databasePoolManager.ts +85 -0
  136. package/src/history/HistoryService.ts +248 -0
  137. package/src/history/ensure-history-table.ts +45 -0
  138. package/src/index.ts +13 -0
  139. package/src/interfaces.ts +60 -0
  140. package/src/schema/auth-schema.ts +169 -0
  141. package/src/schema/doctor-cli.ts +47 -0
  142. package/src/schema/doctor.ts +595 -0
  143. package/src/schema/generate-drizzle-schema-logic.ts +765 -0
  144. package/src/schema/generate-drizzle-schema.ts +151 -0
  145. package/src/schema/introspect-db-logic.ts +542 -0
  146. package/src/schema/introspect-db.ts +211 -0
  147. package/src/schema/test-schema.ts +11 -0
  148. package/src/services/BranchService.ts +237 -0
  149. package/src/services/EntityFetchService.ts +1576 -0
  150. package/src/services/EntityPersistService.ts +349 -0
  151. package/src/services/RelationService.ts +1274 -0
  152. package/src/services/entity-helpers.ts +147 -0
  153. package/src/services/entityService.ts +211 -0
  154. package/src/services/index.ts +13 -0
  155. package/src/services/realtimeService.ts +1034 -0
  156. package/src/utils/drizzle-conditions.ts +1000 -0
  157. package/src/websocket.ts +518 -0
  158. package/test/auth-services.test.ts +661 -0
  159. package/test/batch-many-to-many-regression.test.ts +573 -0
  160. package/test/branchService.test.ts +367 -0
  161. package/test/data-transformer-hardening.test.ts +417 -0
  162. package/test/data-transformer.test.ts +175 -0
  163. package/test/doctor.test.ts +182 -0
  164. package/test/drizzle-conditions.test.ts +895 -0
  165. package/test/entityService.errors.test.ts +367 -0
  166. package/test/entityService.relations.test.ts +1008 -0
  167. package/test/entityService.subcollection-search.test.ts +566 -0
  168. package/test/entityService.test.ts +1035 -0
  169. package/test/generate-drizzle-schema.test.ts +988 -0
  170. package/test/historyService.test.ts +141 -0
  171. package/test/introspect-db-generation.test.ts +436 -0
  172. package/test/introspect-db-utils.test.ts +389 -0
  173. package/test/n-plus-one-regression.test.ts +314 -0
  174. package/test/postgresDataDriver.test.ts +648 -0
  175. package/test/realtimeService.test.ts +307 -0
  176. package/test/relation-pipeline-gaps.test.ts +637 -0
  177. package/test/relations.test.ts +1115 -0
  178. package/test/unmapped-tables-safety.test.ts +345 -0
  179. package/test-drizzle-bug.ts +18 -0
  180. package/test-drizzle-out/0000_cultured_freak.sql +7 -0
  181. package/test-drizzle-out/0001_tiresome_professor_monster.sql +1 -0
  182. package/test-drizzle-out/meta/0000_snapshot.json +55 -0
  183. package/test-drizzle-out/meta/0001_snapshot.json +63 -0
  184. package/test-drizzle-out/meta/_journal.json +20 -0
  185. package/test-drizzle-prompt.sh +2 -0
  186. package/test-policy-prompt.sh +3 -0
  187. package/test-programmatic.ts +30 -0
  188. package/test-programmatic2.ts +59 -0
  189. package/test-schema-no-policies.ts +12 -0
  190. package/test_drizzle_mock.js +3 -0
  191. package/test_find_changed.mjs +32 -0
  192. package/test_hash.js +14 -0
  193. package/test_output.txt +3145 -0
  194. package/tsconfig.json +49 -0
  195. package/tsconfig.prod.json +20 -0
  196. package/vite.config.ts +82 -0
@@ -0,0 +1,100 @@
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 { User } from "@rebasepro/types";
7
+ import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
8
+ import { DataDriver, DeleteEntityProps, Entity, EntityCollection, FetchCollectionProps, FetchEntityProps, ListenCollectionProps, ListenEntityProps, SaveEntityProps, RebaseData, TableMetadata, DatabaseAdmin } from "@rebasepro/types";
9
+ import { HistoryService } from "./history/HistoryService";
10
+ export declare class PostgresBackendDriver implements DataDriver {
11
+ db: DrizzleClient;
12
+ readonly registry: PostgresCollectionRegistry;
13
+ poolManager?: DatabasePoolManager | undefined;
14
+ key: string;
15
+ initialised: boolean;
16
+ entityService: EntityService;
17
+ realtimeService: RealtimeService;
18
+ historyService?: HistoryService;
19
+ branchService?: BranchService;
20
+ user?: User;
21
+ data: RebaseData;
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
+ private resolveCollectionCallbacks;
41
+ fetchCollection<M extends Record<string, unknown>>({ path, collection, filter, limit, offset, startAfter, orderBy, searchString, order }: FetchCollectionProps<M>): Promise<Entity<M>[]>;
42
+ listenCollection<M extends Record<string, unknown>>({ path, collection, filter, limit, offset, startAfter, orderBy, searchString, order, onUpdate, onError }: ListenCollectionProps<M>): () => void;
43
+ fetchEntity<M extends Record<string, unknown>>({ path, entityId, databaseId, collection }: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
44
+ listenEntity<M extends Record<string, unknown>>({ path, entityId, collection, onUpdate, onError }: ListenEntityProps<M>): () => void;
45
+ saveEntity<M extends Record<string, unknown>>({ path, entityId, values, collection, status }: SaveEntityProps<M>): Promise<Entity<M>>;
46
+ deleteEntity<M extends Record<string, unknown>>({ entity, collection }: DeleteEntityProps<M>): Promise<void>;
47
+ checkUniqueField(path: string, name: string, value: unknown, entityId?: string, collection?: EntityCollection): Promise<boolean>;
48
+ countEntities<M extends Record<string, unknown>>({ path, collection, filter, searchString }: FetchCollectionProps<M>): Promise<number>;
49
+ private getTargetDb;
50
+ executeSql(sqlText: string, options?: {
51
+ database?: string;
52
+ role?: string;
53
+ }): Promise<Record<string, unknown>[]>;
54
+ fetchAvailableDatabases(): Promise<string[]>;
55
+ fetchAvailableRoles(): Promise<string[]>;
56
+ fetchCurrentDatabase(): Promise<string | undefined>;
57
+ /**
58
+ * Fetch public tables that are not yet mapped to a collection.
59
+ * Excludes internal tables (_rebase_*, _auth_*, auth tables, etc.)
60
+ * and junction/connection tables used for many-to-many relations.
61
+ */
62
+ fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]>;
63
+ /**
64
+ * Fetch metadata for a given table from information_schema (columns, policies, constraints).
65
+ */
66
+ fetchTableMetadata(tableName: string): Promise<TableMetadata>;
67
+ private generateSubscriptionId;
68
+ /**
69
+ * Create a new delegate instance with authenticated context.
70
+ * Starts a transaction and sets the current_user_id and current_user_roles
71
+ * configuration parameters for PostgreSQL Row Level Security.
72
+ */
73
+ withAuth(user: User): Promise<DataDriver>;
74
+ }
75
+ export declare class AuthenticatedPostgresBackendDriver implements DataDriver {
76
+ delegate: PostgresBackendDriver;
77
+ key: string;
78
+ initialised: boolean;
79
+ user: User;
80
+ data: RebaseData;
81
+ constructor(delegate: PostgresBackendDriver, user: User);
82
+ /**
83
+ * Typed admin capabilities — delegates to the base driver.
84
+ */
85
+ admin: DatabaseAdmin;
86
+ private withTransaction;
87
+ fetchCollection<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]>;
88
+ /**
89
+ * Injects the authenticated user's context into the most recently
90
+ * registered realtime subscription so RLS-aware polling can apply.
91
+ */
92
+ private injectAuthContext;
93
+ listenCollection<M extends Record<string, unknown>>(props: ListenCollectionProps<M>): () => void;
94
+ fetchEntity<M extends Record<string, unknown>>(props: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
95
+ listenEntity<M extends Record<string, unknown>>(props: ListenEntityProps<M>): () => void;
96
+ saveEntity<M extends Record<string, unknown>>(props: SaveEntityProps<M>): Promise<Entity<M>>;
97
+ deleteEntity<M extends Record<string, unknown>>(props: DeleteEntityProps<M>): Promise<void>;
98
+ checkUniqueField(path: string, name: string, value: unknown, entityId?: string, collection?: EntityCollection): Promise<boolean>;
99
+ countEntities<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;
100
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * PostgresBootstrapper
3
+ *
4
+ * Implements the `BackendBootstrapper` interface for PostgreSQL.
5
+ * Encapsulates all Postgres-specific initialization logic that was previously
6
+ * hardcoded inside `initializeRebaseBackend()`.
7
+ *
8
+ * Third-party drivers (MongoDB, MySQL, etc.) can implement their own
9
+ * bootstrapper following this pattern and pass it to the coordinator.
10
+ */
11
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
12
+ import { BackendBootstrapper } from "@rebasepro/types";
13
+ import { PostgresBackendDriver } from "./PostgresBackendDriver";
14
+ import { RealtimeService } from "./services/realtimeService";
15
+ import { DatabasePoolManager } from "./databasePoolManager";
16
+ import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
17
+ import type { PostgresDriverConfig } from "@rebasepro/server-core";
18
+ /**
19
+ * Opaque internals bag that PostgresBootstrapper stores during `initializeDriver()`
20
+ * and re-uses in subsequent lifecycle hooks.
21
+ */
22
+ export interface PostgresDriverInternals {
23
+ db: NodePgDatabase<any>;
24
+ registry: PostgresCollectionRegistry;
25
+ realtimeService: RealtimeService;
26
+ driver: PostgresBackendDriver;
27
+ poolManager?: DatabasePoolManager;
28
+ }
29
+ /**
30
+ * Default PostgreSQL bootstrapper.
31
+ *
32
+ * Use it to register Postgres with `initializeRebaseBackend()`:
33
+ * ```typescript
34
+ * initializeRebaseBackend({
35
+ * ...config,
36
+ * bootstrappers: [postgresBootstrapper()]
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function createPostgresBootstrapper(pgConfig: PostgresDriverConfig): BackendBootstrapper;
@@ -0,0 +1,6 @@
1
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ /**
3
+ * Auto-create auth tables if they don't exist
4
+ * This runs on startup to ensure the database is ready for auth
5
+ */
6
+ export declare function ensureAuthTablesExist(db: NodePgDatabase): Promise<void>;
@@ -0,0 +1,192 @@
1
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ import { User, NewUser } from "../schema/auth-schema";
3
+ import { UserRepository, RoleRepository, TokenRepository, AuthRepository, UserData, CreateUserData, RoleData, CreateRoleData, RefreshTokenInfo, PasswordResetTokenInfo, UserIdentityData, ListUsersOptions, PaginatedUsersResult, RoleData as Role } from "@rebasepro/server-core";
4
+ export type { Role };
5
+ /**
6
+ * PostgreSQL implementation of UserRepository.
7
+ * Handles all user-related database operations using Drizzle ORM.
8
+ */
9
+ export declare class UserService implements UserRepository {
10
+ private db;
11
+ constructor(db: NodePgDatabase);
12
+ createUser(data: NewUser): Promise<User>;
13
+ getUserById(id: string): Promise<User | null>;
14
+ getUserByEmail(email: string): Promise<User | null>;
15
+ getUserByIdentity(provider: string, providerId: string): Promise<User | null>;
16
+ getUserIdentities(userId: string): Promise<UserIdentityData[]>;
17
+ linkUserIdentity(userId: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void>;
18
+ updateUser(id: string, data: Partial<Omit<NewUser, "id">>): Promise<User | null>;
19
+ deleteUser(id: string): Promise<void>;
20
+ listUsers(): Promise<User[]>;
21
+ listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
22
+ /**
23
+ * Update user's password hash
24
+ */
25
+ updatePassword(id: string, passwordHash: string): Promise<void>;
26
+ /**
27
+ * Set email verification status
28
+ */
29
+ setEmailVerified(id: string, verified: boolean): Promise<void>;
30
+ /**
31
+ * Set email verification token
32
+ */
33
+ setVerificationToken(id: string, token: string | null): Promise<void>;
34
+ /**
35
+ * Find user by email verification token
36
+ */
37
+ getUserByVerificationToken(token: string): Promise<User | null>;
38
+ /**
39
+ * Get roles for a user from database
40
+ */
41
+ getUserRoles(userId: string): Promise<Role[]>;
42
+ /**
43
+ * Get role IDs for a user
44
+ */
45
+ getUserRoleIds(userId: string): Promise<string[]>;
46
+ /**
47
+ * Set roles for a user
48
+ */
49
+ setUserRoles(userId: string, roleIds: string[]): Promise<void>;
50
+ /**
51
+ * Assign a specific role to new user
52
+ */
53
+ assignDefaultRole(userId: string, roleId: string): Promise<void>;
54
+ /**
55
+ * Get user with their roles
56
+ */
57
+ getUserWithRoles(userId: string): Promise<{
58
+ user: User;
59
+ roles: Role[];
60
+ } | null>;
61
+ }
62
+ /**
63
+ * PostgreSQL implementation of RoleRepository.
64
+ * Handles all role-related database operations using Drizzle ORM.
65
+ */
66
+ export declare class RoleService implements RoleRepository {
67
+ private db;
68
+ constructor(db: NodePgDatabase);
69
+ getRoleById(id: string): Promise<Role | null>;
70
+ listRoles(): Promise<Role[]>;
71
+ createRole(data: Omit<Role, "isAdmin" | "collectionPermissions"> & {
72
+ isAdmin?: boolean;
73
+ collectionPermissions?: Role["collectionPermissions"];
74
+ }): Promise<Role>;
75
+ updateRole(id: string, data: Partial<Omit<Role, "id">>): Promise<Role | null>;
76
+ deleteRole(id: string): Promise<void>;
77
+ }
78
+ export declare class RefreshTokenService {
79
+ private db;
80
+ constructor(db: NodePgDatabase);
81
+ createToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
82
+ findByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
83
+ deleteByHash(tokenHash: string): Promise<void>;
84
+ deleteAllForUser(userId: string): Promise<void>;
85
+ listForUser(userId: string): Promise<RefreshTokenInfo[]>;
86
+ deleteById(id: string, userId: string): Promise<void>;
87
+ }
88
+ /**
89
+ * Password reset token service
90
+ */
91
+ export declare class PasswordResetTokenService {
92
+ private db;
93
+ constructor(db: NodePgDatabase);
94
+ /**
95
+ * Create a password reset token
96
+ */
97
+ createToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
98
+ /**
99
+ * Find a valid (not expired, not used) token by hash
100
+ */
101
+ findValidByHash(tokenHash: string): Promise<{
102
+ userId: string;
103
+ expiresAt: Date;
104
+ } | null>;
105
+ /**
106
+ * Mark token as used
107
+ */
108
+ markAsUsed(tokenHash: string): Promise<void>;
109
+ /**
110
+ * Delete all tokens for a user
111
+ */
112
+ deleteAllForUser(userId: string): Promise<void>;
113
+ /**
114
+ * Clean up expired tokens
115
+ */
116
+ deleteExpired(): Promise<void>;
117
+ }
118
+ /**
119
+ * PostgreSQL implementation of TokenRepository.
120
+ * Combines refresh token and password reset token operations.
121
+ */
122
+ export declare class PostgresTokenRepository implements TokenRepository {
123
+ private db;
124
+ private refreshTokenService;
125
+ private passwordResetTokenService;
126
+ constructor(db: NodePgDatabase);
127
+ createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
128
+ findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
129
+ deleteRefreshToken(tokenHash: string): Promise<void>;
130
+ deleteAllRefreshTokensForUser(userId: string): Promise<void>;
131
+ listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]>;
132
+ deleteRefreshTokenById(id: string, userId: string): Promise<void>;
133
+ createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
134
+ findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null>;
135
+ markPasswordResetTokenUsed(tokenHash: string): Promise<void>;
136
+ deleteAllPasswordResetTokensForUser(userId: string): Promise<void>;
137
+ deleteExpiredTokens(): Promise<void>;
138
+ }
139
+ /**
140
+ * PostgreSQL implementation of AuthRepository.
141
+ * Combines user, role, and token repository operations.
142
+ * This provides a convenient single-class interface for all auth operations.
143
+ */
144
+ export declare class PostgresAuthRepository implements AuthRepository {
145
+ private db;
146
+ private userService;
147
+ private roleService;
148
+ private tokenRepository;
149
+ constructor(db: NodePgDatabase);
150
+ createUser(data: CreateUserData): Promise<UserData>;
151
+ getUserById(id: string): Promise<UserData | null>;
152
+ getUserByEmail(email: string): Promise<UserData | null>;
153
+ getUserByIdentity(provider: string, providerId: string): Promise<UserData | null>;
154
+ getUserIdentities(userId: string): Promise<UserIdentityData[]>;
155
+ linkUserIdentity(userId: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void>;
156
+ updateUser(id: string, data: Partial<Omit<CreateUserData, "id">>): Promise<UserData | null>;
157
+ deleteUser(id: string): Promise<void>;
158
+ listUsers(): Promise<UserData[]>;
159
+ listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
160
+ updatePassword(id: string, passwordHash: string): Promise<void>;
161
+ setEmailVerified(id: string, verified: boolean): Promise<void>;
162
+ setVerificationToken(id: string, token: string | null): Promise<void>;
163
+ getUserByVerificationToken(token: string): Promise<UserData | null>;
164
+ getUserRoles(userId: string): Promise<RoleData[]>;
165
+ getUserRoleIds(userId: string): Promise<string[]>;
166
+ setUserRoles(userId: string, roleIds: string[]): Promise<void>;
167
+ assignDefaultRole(userId: string, roleId: string): Promise<void>;
168
+ getUserWithRoles(userId: string): Promise<{
169
+ user: UserData;
170
+ roles: RoleData[];
171
+ } | null>;
172
+ getRoleById(id: string): Promise<RoleData | null>;
173
+ listRoles(): Promise<RoleData[]>;
174
+ createRole(data: CreateRoleData): Promise<RoleData>;
175
+ updateRole(id: string, data: Partial<Omit<RoleData, "id">>): Promise<RoleData | null>;
176
+ deleteRole(id: string): Promise<void>;
177
+ createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
178
+ findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
179
+ deleteRefreshToken(tokenHash: string): Promise<void>;
180
+ deleteAllRefreshTokensForUser(userId: string): Promise<void>;
181
+ listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]>;
182
+ deleteRefreshTokenById(id: string, userId: string): Promise<void>;
183
+ createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
184
+ findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null>;
185
+ markPasswordResetTokenUsed(tokenHash: string): Promise<void>;
186
+ deleteAllPasswordResetTokensForUser(userId: string): Promise<void>;
187
+ deleteExpiredTokens(): Promise<void>;
188
+ }
189
+ /** PostgreSQL user repository implementation */
190
+ export type PostgresUserRepository = UserService;
191
+ /** PostgreSQL role repository implementation */
192
+ export type PostgresRoleRepository = RoleService;
@@ -0,0 +1 @@
1
+ export declare function runPluginCommand(args: string[]): Promise<void>;
@@ -0,0 +1,43 @@
1
+ import { CollectionRegistry } from "@rebasepro/common";
2
+ import { type EntityCollection } from "@rebasepro/types";
3
+ import { PgEnum, PgTable } from "drizzle-orm/pg-core";
4
+ import { Relations } from "drizzle-orm";
5
+ import { CollectionRegistryInterface } from "../interfaces";
6
+ /**
7
+ * PostgreSQL-specific collection registry.
8
+ * Extends the base CollectionRegistry with support for Drizzle ORM tables, enums, and relations.
9
+ *
10
+ * Satisfies CollectionRegistryInterface through inheritance from CollectionRegistry.
11
+ */
12
+ export declare class PostgresCollectionRegistry extends CollectionRegistry implements CollectionRegistryInterface {
13
+ private tables;
14
+ private enums;
15
+ private relations;
16
+ registerTable(table: PgTable, tableName: string): void;
17
+ getTable(tableName: string): PgTable | undefined;
18
+ /**
19
+ * Checks if a specific collection has a registered table
20
+ */
21
+ hasTableForCollection(tableName: string): boolean;
22
+ /**
23
+ * Finds collections assigned to a specific driver that do not have a registered table.
24
+ */
25
+ getCollectionsWithoutTables(driverId?: string): EntityCollection[];
26
+ registerEnums(enums: Record<string, PgEnum<[string, ...string[]]>>): void;
27
+ registerRelations(relations: Record<string, Relations>): void;
28
+ getEnum(name: string): PgEnum<[string, ...string[]]> | undefined;
29
+ getRelation(name: string): Relations | undefined;
30
+ getAllEnums(): Record<string, PgEnum<[string, ...string[]]>>;
31
+ getAllRelations(): Record<string, Relations>;
32
+ /**
33
+ * Get the merged schema object (tables + relations) for use with Drizzle's
34
+ * relational query API (`db.query`).
35
+ */
36
+ getMergedSchema(): Record<string, unknown>;
37
+ /**
38
+ * Get the available Drizzle relation keys for a given collection path.
39
+ * Maps from the collection's relation property names to the Drizzle relation names
40
+ * defined in the schema.
41
+ */
42
+ getRelationKeysForCollection(collectionPath: string): string[];
43
+ }
@@ -0,0 +1,40 @@
1
+ import { Pool } from "pg";
2
+ /**
3
+ * Configuration for the Postgres connection pool.
4
+ *
5
+ * Sensible defaults are provided for production Cloud Run / single-instance
6
+ * deployments. Override via environment variables or explicit config.
7
+ */
8
+ export interface PostgresPoolConfig {
9
+ /** Maximum number of connections in the pool (default: 20) */
10
+ max?: number;
11
+ /** Close idle connections after this many ms (default: 30 000) */
12
+ idleTimeoutMillis?: number;
13
+ /** Abort connection attempts after this many ms (default: 10 000) */
14
+ connectionTimeoutMillis?: number;
15
+ /** Per-query timeout in ms (default: 30 000) */
16
+ queryTimeout?: number;
17
+ /** Per-statement timeout in ms (default: 30 000) */
18
+ statementTimeout?: number;
19
+ /** Enable TCP keep-alive (default: true) */
20
+ keepAlive?: boolean;
21
+ }
22
+ /**
23
+ * Create a Drizzle-backed Postgres connection with a production-grade
24
+ * connection pool.
25
+ *
26
+ * @param connectionString Postgres connection URL
27
+ * @param schema Optional Drizzle schema for the relational API
28
+ * @param poolConfig Optional pool tuning (merged over defaults)
29
+ *
30
+ * @returns `{ db, pool, connectionString }` — the `pool` is exposed so
31
+ * callers can register shutdown hooks (`pool.end()`) or monitor
32
+ * pool metrics.
33
+ */
34
+ export declare function createPostgresDatabaseConnection(connectionString: string, schema?: Record<string, unknown>, poolConfig?: PostgresPoolConfig): {
35
+ db: import("drizzle-orm/node-postgres").NodePgDatabase<Record<string, unknown>> & {
36
+ $client: Pool;
37
+ };
38
+ pool: Pool;
39
+ connectionString: string;
40
+ };
@@ -0,0 +1,58 @@
1
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ import { EntityCollection, Properties, Property, Relation } from "@rebasepro/types";
3
+ import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
4
+ /**
5
+ * Data transformation utilities for converting between frontend and database formats.
6
+ */
7
+ /**
8
+ * Typed result from `serializeDataToServer`.
9
+ * Replaces the hidden `__inverseRelationUpdates` / `__joinPathRelationUpdates`
10
+ * dunder-property mutation pattern with explicit, typed state management.
11
+ */
12
+ export interface SerializedEntityData {
13
+ /** Scalar column values ready for INSERT/UPDATE. */
14
+ scalarData: Record<string, unknown>;
15
+ /** Inverse relation updates that must be applied to target tables. */
16
+ inverseRelationUpdates: Array<{
17
+ relationKey: string;
18
+ relation: Relation;
19
+ newValue: unknown;
20
+ currentEntityId?: string | number;
21
+ }>;
22
+ /** JoinPath relation updates that require multi-hop writes. */
23
+ joinPathRelationUpdates: Array<{
24
+ relationKey: string;
25
+ relation: Relation;
26
+ newTargetId: string | number | null;
27
+ }>;
28
+ }
29
+ /**
30
+ * Helper function to sanitize and convert dates to ISO strings
31
+ */
32
+ export declare function sanitizeAndConvertDates(obj: unknown): unknown;
33
+ /**
34
+ * Transform relations for database storage (relation objects to IDs)
35
+ */
36
+ export declare function serializeDataToServer<M extends Record<string, unknown>>(entity: M, properties: Properties, collection?: EntityCollection, registry?: PostgresCollectionRegistry): SerializedEntityData;
37
+ /**
38
+ * Serialize a single property value for database storage
39
+ */
40
+ export declare function serializePropertyToServer(value: unknown, property: Property): unknown;
41
+ /**
42
+ * Transform IDs back to relation objects for frontend
43
+ */
44
+ export declare function parseDataFromServer<M extends Record<string, unknown>>(data: M, collection: EntityCollection, db?: NodePgDatabase<Record<string, unknown>>, registry?: PostgresCollectionRegistry): Promise<M>;
45
+ /**
46
+ * Parse a single property value from database format to frontend format
47
+ */
48
+ export declare function parsePropertyFromServer(value: unknown, property: Property, collection: EntityCollection, propertyKey?: string): unknown;
49
+ /**
50
+ * Lightweight value normalization for db.query results.
51
+ * Only handles type coercion (dates, numbers, NaN) and property filtering.
52
+ * Does NOT query the database for relations — those are already resolved
53
+ * by Drizzle's relational query API.
54
+ *
55
+ * Use this instead of `parseDataFromServer` when processing results from
56
+ * `db.query.findFirst/findMany` which return pre-hydrated relation data.
57
+ */
58
+ export declare function normalizeDbValues<M extends Record<string, unknown>>(data: M, collection: EntityCollection): M;
@@ -0,0 +1,20 @@
1
+ import { Pool } from "pg";
2
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
3
+ export declare class DatabasePoolManager {
4
+ private pools;
5
+ private drizzleInstances;
6
+ readonly defaultDatabaseName: string;
7
+ private readonly rootConnectionString;
8
+ constructor(adminConnectionString: string);
9
+ getDrizzle(databaseName: string): NodePgDatabase<any>;
10
+ getPool(databaseName: string): Pool;
11
+ /**
12
+ * Disconnect and remove the pool for a specific database.
13
+ * Required before `CREATE DATABASE ... TEMPLATE` or `DROP DATABASE`,
14
+ * which need exclusive access to the target database.
15
+ */
16
+ disconnectDatabase(databaseName: string): Promise<void>;
17
+ /** Check if a pool exists for a given database name. */
18
+ hasPool(databaseName: string): boolean;
19
+ shutdown(): Promise<void>;
20
+ }
@@ -0,0 +1,71 @@
1
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ export interface HistoryEntry {
3
+ id: string;
4
+ table_name: string;
5
+ entity_id: string;
6
+ action: "create" | "update" | "delete";
7
+ changed_fields: string[] | null;
8
+ values: Record<string, unknown> | null;
9
+ previous_values: Record<string, unknown> | null;
10
+ updated_by: string | null;
11
+ updated_at: string;
12
+ }
13
+ export interface RecordHistoryParams {
14
+ tableName: string;
15
+ entityId: string;
16
+ action: "create" | "update" | "delete";
17
+ values?: Record<string, unknown> | null;
18
+ previousValues?: Record<string, unknown> | null;
19
+ updatedBy?: string | null;
20
+ }
21
+ export interface FetchHistoryOptions {
22
+ limit?: number;
23
+ offset?: number;
24
+ }
25
+ export interface HistoryRetentionConfig {
26
+ /** Max entries per entity. Oldest pruned first. Default 200. */
27
+ maxEntries: number;
28
+ /** Entries older than this many days are pruned. Default 90. */
29
+ ttlDays: number;
30
+ }
31
+ /**
32
+ * Service for recording and querying entity change history.
33
+ * Stores snapshots in the `rebase.entity_history` table.
34
+ */
35
+ export declare class HistoryService {
36
+ private db;
37
+ retention: HistoryRetentionConfig;
38
+ constructor(db: NodePgDatabase, retention?: Partial<HistoryRetentionConfig>);
39
+ /**
40
+ * Record a history entry for an entity change.
41
+ * This is intentionally fire-and-forget safe — errors are logged but never
42
+ * bubble up to block the main save/delete operation.
43
+ *
44
+ * After inserting, kicks off a non-blocking pruning pass for this entity.
45
+ */
46
+ recordHistory(params: RecordHistoryParams): Promise<void>;
47
+ /**
48
+ * Fetch history entries for an entity, ordered by most recent first.
49
+ */
50
+ fetchHistory(tableName: string, entityId: string, options?: FetchHistoryOptions): Promise<{
51
+ data: HistoryEntry[];
52
+ total: number;
53
+ }>;
54
+ /**
55
+ * Fetch a single history entry by ID.
56
+ */
57
+ fetchHistoryEntry(historyId: string): Promise<HistoryEntry | null>;
58
+ /**
59
+ * Prune history for a single entity: enforce maxEntries and TTL.
60
+ */
61
+ pruneEntity(tableName: string, entityId: string): Promise<number>;
62
+ /**
63
+ * Global prune: enforce TTL across ALL entities in a single sweep.
64
+ * Intended to be called periodically (e.g. once per hour or daily).
65
+ */
66
+ pruneExpired(): Promise<number>;
67
+ }
68
+ /**
69
+ * Shallow comparison to find top-level keys that changed between two objects.
70
+ */
71
+ export declare function findChangedFields(oldValues: Record<string, unknown>, newValues: Record<string, unknown>): string[] | null;
@@ -0,0 +1,7 @@
1
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ /**
3
+ * Auto-create the entity history table if it doesn't exist.
4
+ * This runs on startup when history is enabled, following the same
5
+ * pattern as `ensureAuthTablesExist`.
6
+ */
7
+ export declare function ensureHistoryTableExists(db: NodePgDatabase): Promise<void>;
@@ -0,0 +1,13 @@
1
+ export * from "./connection";
2
+ export * from "./interfaces";
3
+ export * from "./PostgresBackendDriver";
4
+ export * from "./databasePoolManager";
5
+ export * from "./schema/auth-schema";
6
+ export * from "./schema/generate-drizzle-schema-logic";
7
+ export * from "./schema/generate-drizzle-schema";
8
+ export * from "./utils/drizzle-conditions";
9
+ export * from "./services/realtimeService";
10
+ export * from "./websocket";
11
+ export * from "./collections/PostgresCollectionRegistry";
12
+ export * from "./services/BranchService";
13
+ export * from "./PostgresBootstrapper";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Database Abstraction Interfaces
3
+ *
4
+ * These interfaces define the contracts that any database backend must implement
5
+ * to be used with Rebase. This allows for pluggable database backends like
6
+ * PostgreSQL, MongoDB, MySQL, etc.
7
+ */
8
+ import { DatabaseConnection, QueryFilter, FetchCollectionOptions, SearchOptions, CountOptions, ConditionBuilder, ConditionBuilderStatic, EntityRepository, CollectionSubscriptionConfig, EntitySubscriptionConfig, RealtimeProvider, CollectionRegistryInterface, DataTransformer, BackendConfig, BackendInstance, BackendFactory } from "@rebasepro/types";
9
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
10
+ import { PgTransaction } from "drizzle-orm/pg-core";
11
+ /**
12
+ * Type representing either a direct database connection or a transaction.
13
+ * Used to allow services to operate within a transaction context.
14
+ * Note: `any` is intentional here — it represents a Drizzle client with
15
+ * a dynamic schema, enabling `db.query[tableName]` access without casts.
16
+ */
17
+ export type DrizzleClient = NodePgDatabase<any> | PgTransaction<any, any, any>;
18
+ export type { DatabaseConnection, QueryFilter, FetchCollectionOptions, SearchOptions, CountOptions, ConditionBuilder, ConditionBuilderStatic, EntityRepository, CollectionSubscriptionConfig, EntitySubscriptionConfig, RealtimeProvider, CollectionRegistryInterface, DataTransformer, BackendConfig, BackendInstance, BackendFactory };