@rebasepro/server-postgresql 0.0.1-canary.4d4fb3e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +6 -0
- package/README.md +106 -0
- package/build-errors.txt +37 -0
- package/dist/common/src/collections/CollectionRegistry.d.ts +48 -0
- package/dist/common/src/collections/index.d.ts +1 -0
- package/dist/common/src/data/buildRebaseData.d.ts +14 -0
- package/dist/common/src/index.d.ts +3 -0
- package/dist/common/src/util/builders.d.ts +57 -0
- package/dist/common/src/util/callbacks.d.ts +6 -0
- package/dist/common/src/util/collections.d.ts +11 -0
- package/dist/common/src/util/common.d.ts +2 -0
- package/dist/common/src/util/conditions.d.ts +26 -0
- package/dist/common/src/util/entities.d.ts +36 -0
- package/dist/common/src/util/enums.d.ts +3 -0
- package/dist/common/src/util/index.d.ts +16 -0
- package/dist/common/src/util/navigation_from_path.d.ts +34 -0
- package/dist/common/src/util/navigation_utils.d.ts +20 -0
- package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
- package/dist/common/src/util/paths.d.ts +14 -0
- package/dist/common/src/util/permissions.d.ts +5 -0
- package/dist/common/src/util/references.d.ts +2 -0
- package/dist/common/src/util/relations.d.ts +12 -0
- package/dist/common/src/util/resolutions.d.ts +72 -0
- package/dist/common/src/util/storage.d.ts +24 -0
- package/dist/index.es.js +10635 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +10643 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +112 -0
- package/dist/server-postgresql/src/PostgresBootstrapper.d.ts +40 -0
- package/dist/server-postgresql/src/auth/ensure-tables.d.ts +6 -0
- package/dist/server-postgresql/src/auth/services.d.ts +188 -0
- package/dist/server-postgresql/src/cli.d.ts +1 -0
- package/dist/server-postgresql/src/collections/PostgresCollectionRegistry.d.ts +43 -0
- package/dist/server-postgresql/src/connection.d.ts +7 -0
- package/dist/server-postgresql/src/data-transformer.d.ts +36 -0
- package/dist/server-postgresql/src/databasePoolManager.d.ts +20 -0
- package/dist/server-postgresql/src/history/HistoryService.d.ts +71 -0
- package/dist/server-postgresql/src/history/ensure-history-table.d.ts +7 -0
- package/dist/server-postgresql/src/index.d.ts +13 -0
- package/dist/server-postgresql/src/interfaces.d.ts +18 -0
- package/dist/server-postgresql/src/schema/auth-schema.d.ts +767 -0
- package/dist/server-postgresql/src/schema/generate-drizzle-schema-logic.d.ts +2 -0
- package/dist/server-postgresql/src/schema/generate-drizzle-schema.d.ts +1 -0
- package/dist/server-postgresql/src/services/BranchService.d.ts +47 -0
- package/dist/server-postgresql/src/services/EntityFetchService.d.ts +195 -0
- package/dist/server-postgresql/src/services/EntityPersistService.d.ts +41 -0
- package/dist/server-postgresql/src/services/RelationService.d.ts +92 -0
- package/dist/server-postgresql/src/services/entity-helpers.d.ts +24 -0
- package/dist/server-postgresql/src/services/entityService.d.ts +102 -0
- package/dist/server-postgresql/src/services/index.d.ts +4 -0
- package/dist/server-postgresql/src/services/realtimeService.d.ts +186 -0
- package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +116 -0
- package/dist/server-postgresql/src/websocket.d.ts +5 -0
- package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
- package/dist/types/src/controllers/auth.d.ts +117 -0
- package/dist/types/src/controllers/client.d.ts +58 -0
- package/dist/types/src/controllers/collection_registry.d.ts +44 -0
- package/dist/types/src/controllers/customization_controller.d.ts +54 -0
- package/dist/types/src/controllers/data.d.ts +141 -0
- package/dist/types/src/controllers/data_driver.d.ts +168 -0
- package/dist/types/src/controllers/database_admin.d.ts +11 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
- package/dist/types/src/controllers/effective_role.d.ts +4 -0
- package/dist/types/src/controllers/index.d.ts +17 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
- package/dist/types/src/controllers/navigation.d.ts +213 -0
- package/dist/types/src/controllers/registry.d.ts +51 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts +89 -0
- package/dist/types/src/controllers/snackbar.d.ts +24 -0
- package/dist/types/src/controllers/storage.d.ts +173 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/rebase_context.d.ts +101 -0
- package/dist/types/src/types/backend.d.ts +533 -0
- package/dist/types/src/types/builders.d.ts +14 -0
- package/dist/types/src/types/chips.d.ts +5 -0
- package/dist/types/src/types/collections.d.ts +812 -0
- package/dist/types/src/types/data_source.d.ts +64 -0
- package/dist/types/src/types/entities.d.ts +145 -0
- package/dist/types/src/types/entity_actions.d.ts +98 -0
- package/dist/types/src/types/entity_callbacks.d.ts +173 -0
- package/dist/types/src/types/entity_link_builder.d.ts +7 -0
- package/dist/types/src/types/entity_overrides.d.ts +9 -0
- package/dist/types/src/types/entity_views.d.ts +61 -0
- package/dist/types/src/types/export_import.d.ts +21 -0
- package/dist/types/src/types/index.d.ts +22 -0
- package/dist/types/src/types/locales.d.ts +4 -0
- package/dist/types/src/types/modify_collections.d.ts +5 -0
- package/dist/types/src/types/plugins.d.ts +225 -0
- package/dist/types/src/types/properties.d.ts +1091 -0
- package/dist/types/src/types/property_config.d.ts +70 -0
- package/dist/types/src/types/relations.d.ts +336 -0
- package/dist/types/src/types/slots.d.ts +228 -0
- package/dist/types/src/types/translations.d.ts +826 -0
- package/dist/types/src/types/user_management_delegate.d.ts +120 -0
- package/dist/types/src/types/websockets.d.ts +78 -0
- package/dist/types/src/users/index.d.ts +2 -0
- package/dist/types/src/users/roles.d.ts +22 -0
- package/dist/types/src/users/user.d.ts +46 -0
- package/jest-all.log +3128 -0
- package/jest.log +49 -0
- package/package.json +93 -0
- package/src/PostgresBackendDriver.ts +1024 -0
- package/src/PostgresBootstrapper.ts +232 -0
- package/src/auth/ensure-tables.ts +309 -0
- package/src/auth/services.ts +740 -0
- package/src/cli.ts +347 -0
- package/src/collections/PostgresCollectionRegistry.ts +96 -0
- package/src/connection.ts +62 -0
- package/src/data-transformer.ts +569 -0
- package/src/databasePoolManager.ts +84 -0
- package/src/history/HistoryService.ts +257 -0
- package/src/history/ensure-history-table.ts +45 -0
- package/src/index.ts +13 -0
- package/src/interfaces.ts +60 -0
- package/src/schema/auth-schema.ts +146 -0
- package/src/schema/generate-drizzle-schema-logic.ts +618 -0
- package/src/schema/generate-drizzle-schema.ts +151 -0
- package/src/services/BranchService.ts +237 -0
- package/src/services/EntityFetchService.ts +1447 -0
- package/src/services/EntityPersistService.ts +351 -0
- package/src/services/RelationService.ts +1012 -0
- package/src/services/entity-helpers.ts +121 -0
- package/src/services/entityService.ts +209 -0
- package/src/services/index.ts +13 -0
- package/src/services/realtimeService.ts +1005 -0
- package/src/utils/drizzle-conditions.ts +999 -0
- package/src/websocket.ts +487 -0
- package/test/auth-services.test.ts +569 -0
- package/test/branchService.test.ts +357 -0
- package/test/drizzle-conditions.test.ts +895 -0
- package/test/entityService.errors.test.ts +352 -0
- package/test/entityService.relations.test.ts +912 -0
- package/test/entityService.subcollection-search.test.ts +516 -0
- package/test/entityService.test.ts +977 -0
- package/test/generate-drizzle-schema.test.ts +795 -0
- package/test/historyService.test.ts +126 -0
- package/test/postgresDataDriver.test.ts +556 -0
- package/test/realtimeService.test.ts +276 -0
- package/test/relations.test.ts +662 -0
- package/test_drizzle_mock.js +3 -0
- package/test_find_changed.mjs +30 -0
- package/test_output.txt +3145 -0
- package/tsconfig.json +49 -0
- package/tsconfig.prod.json +20 -0
- package/vite.config.ts +82 -0
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
*/
|
|
37
|
+
admin: DatabaseAdmin;
|
|
38
|
+
private resolveCollectionCallbacks;
|
|
39
|
+
fetchCollection<M extends Record<string, any>>({ path, collection, filter, limit, startAfter, orderBy, searchString, order }: FetchCollectionProps<M>): Promise<Entity<M>[]>;
|
|
40
|
+
listenCollection<M extends Record<string, any>>({ path, collection, filter, limit, startAfter, orderBy, searchString, order, onUpdate, onError }: ListenCollectionProps<M>): () => void;
|
|
41
|
+
fetchEntity<M extends Record<string, any>>({ path, entityId, databaseId, collection }: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
|
|
42
|
+
listenEntity<M extends Record<string, any>>({ path, entityId, collection, onUpdate, onError }: ListenEntityProps<M>): () => void;
|
|
43
|
+
saveEntity<M extends Record<string, any>>({ path, entityId, values, collection, status }: SaveEntityProps<M>): Promise<Entity<M>>;
|
|
44
|
+
deleteEntity<M extends Record<string, any>>({ entity, collection }: DeleteEntityProps<M>): Promise<void>;
|
|
45
|
+
checkUniqueField(path: string, name: string, value: unknown, entityId?: string, collection?: EntityCollection): Promise<boolean>;
|
|
46
|
+
countEntities<M extends Record<string, any>>({ path, collection, filter }: FetchCollectionProps<M>): Promise<number>;
|
|
47
|
+
private getTargetDb;
|
|
48
|
+
executeSql(sqlText: string, options?: {
|
|
49
|
+
database?: string;
|
|
50
|
+
role?: string;
|
|
51
|
+
}): Promise<Record<string, unknown>[]>;
|
|
52
|
+
fetchAvailableDatabases(): Promise<string[]>;
|
|
53
|
+
fetchAvailableRoles(): Promise<string[]>;
|
|
54
|
+
fetchCurrentDatabase(): Promise<string | undefined>;
|
|
55
|
+
/**
|
|
56
|
+
* Fetch public tables that are not yet mapped to a collection.
|
|
57
|
+
* Excludes internal tables (_rebase_*, _auth_*, auth tables, etc.)
|
|
58
|
+
* and junction/connection tables used for many-to-many relations.
|
|
59
|
+
*/
|
|
60
|
+
fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Fetch metadata for a given table from information_schema (columns, policies, constraints).
|
|
63
|
+
*/
|
|
64
|
+
fetchTableMetadata(tableName: string): Promise<TableMetadata>;
|
|
65
|
+
private generateSubscriptionId;
|
|
66
|
+
/**
|
|
67
|
+
* Create a new delegate instance with authenticated context.
|
|
68
|
+
* Starts a transaction and sets the current_user_id and current_user_roles
|
|
69
|
+
* configuration parameters for PostgreSQL Row Level Security.
|
|
70
|
+
*/
|
|
71
|
+
withAuth(user: User): Promise<DataDriver>;
|
|
72
|
+
}
|
|
73
|
+
export declare class AuthenticatedPostgresBackendDriver implements DataDriver {
|
|
74
|
+
delegate: PostgresBackendDriver;
|
|
75
|
+
key: string;
|
|
76
|
+
initialised: boolean;
|
|
77
|
+
user: User;
|
|
78
|
+
data: RebaseData;
|
|
79
|
+
constructor(delegate: PostgresBackendDriver, user: User);
|
|
80
|
+
/**
|
|
81
|
+
* Typed admin capabilities — delegates to the base driver.
|
|
82
|
+
*/
|
|
83
|
+
admin: DatabaseAdmin;
|
|
84
|
+
private withTransaction;
|
|
85
|
+
fetchCollection<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Injects the authenticated user's context into the most recently
|
|
88
|
+
* registered realtime subscription so RLS-aware polling can apply.
|
|
89
|
+
*/
|
|
90
|
+
private injectAuthContext;
|
|
91
|
+
listenCollection<M extends Record<string, any>>(props: ListenCollectionProps<M>): () => void;
|
|
92
|
+
fetchEntity<M extends Record<string, any>>(props: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
|
|
93
|
+
listenEntity<M extends Record<string, any>>(props: ListenEntityProps<M>): () => void;
|
|
94
|
+
saveEntity<M extends Record<string, any>>(props: SaveEntityProps<M>): Promise<Entity<M>>;
|
|
95
|
+
deleteEntity<M extends Record<string, any>>(props: DeleteEntityProps<M>): Promise<void>;
|
|
96
|
+
checkUniqueField(path: string, name: string, value: unknown, entityId?: string, collection?: EntityCollection): Promise<boolean>;
|
|
97
|
+
countEntities<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<number>;
|
|
98
|
+
/**
|
|
99
|
+
* Intentionally delegates to the base delegate WITHOUT RLS wrapping.
|
|
100
|
+
* executeSql is an admin-only feature; access control should be enforced
|
|
101
|
+
* at the API route level, not via database-level RLS.
|
|
102
|
+
*/
|
|
103
|
+
executeSql(sqlText: string, options?: {
|
|
104
|
+
database?: string;
|
|
105
|
+
role?: string;
|
|
106
|
+
}): Promise<Record<string, unknown>[]>;
|
|
107
|
+
fetchAvailableDatabases(): Promise<string[]>;
|
|
108
|
+
fetchAvailableRoles(): Promise<string[]>;
|
|
109
|
+
fetchCurrentDatabase(): Promise<string | undefined>;
|
|
110
|
+
fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]>;
|
|
111
|
+
fetchTableMetadata(tableName: string): Promise<TableMetadata>;
|
|
112
|
+
}
|
|
@@ -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,188 @@
|
|
|
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, 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
|
+
getUserByGoogleId(googleId: string): Promise<User | null>;
|
|
16
|
+
updateUser(id: string, data: Partial<Omit<NewUser, "id">>): Promise<User | null>;
|
|
17
|
+
deleteUser(id: string): Promise<void>;
|
|
18
|
+
listUsers(): Promise<User[]>;
|
|
19
|
+
listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Update user's password hash
|
|
22
|
+
*/
|
|
23
|
+
updatePassword(id: string, passwordHash: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Set email verification status
|
|
26
|
+
*/
|
|
27
|
+
setEmailVerified(id: string, verified: boolean): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Set email verification token
|
|
30
|
+
*/
|
|
31
|
+
setVerificationToken(id: string, token: string | null): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Find user by email verification token
|
|
34
|
+
*/
|
|
35
|
+
getUserByVerificationToken(token: string): Promise<User | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Get roles for a user from database
|
|
38
|
+
*/
|
|
39
|
+
getUserRoles(userId: string): Promise<Role[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get role IDs for a user
|
|
42
|
+
*/
|
|
43
|
+
getUserRoleIds(userId: string): Promise<string[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Set roles for a user
|
|
46
|
+
*/
|
|
47
|
+
setUserRoles(userId: string, roleIds: string[]): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Assign a specific role to new user
|
|
50
|
+
*/
|
|
51
|
+
assignDefaultRole(userId: string, roleId: string): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Get user with their roles
|
|
54
|
+
*/
|
|
55
|
+
getUserWithRoles(userId: string): Promise<{
|
|
56
|
+
user: User;
|
|
57
|
+
roles: Role[];
|
|
58
|
+
} | null>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* PostgreSQL implementation of RoleRepository.
|
|
62
|
+
* Handles all role-related database operations using Drizzle ORM.
|
|
63
|
+
*/
|
|
64
|
+
export declare class RoleService implements RoleRepository {
|
|
65
|
+
private db;
|
|
66
|
+
constructor(db: NodePgDatabase);
|
|
67
|
+
getRoleById(id: string): Promise<Role | null>;
|
|
68
|
+
listRoles(): Promise<Role[]>;
|
|
69
|
+
createRole(data: Omit<Role, "isAdmin" | "collectionPermissions"> & {
|
|
70
|
+
isAdmin?: boolean;
|
|
71
|
+
collectionPermissions?: Role["collectionPermissions"];
|
|
72
|
+
}): Promise<Role>;
|
|
73
|
+
updateRole(id: string, data: Partial<Omit<Role, "id">>): Promise<Role | null>;
|
|
74
|
+
deleteRole(id: string): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
export declare class RefreshTokenService {
|
|
77
|
+
private db;
|
|
78
|
+
constructor(db: NodePgDatabase);
|
|
79
|
+
createToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
|
|
80
|
+
findByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
|
|
81
|
+
deleteByHash(tokenHash: string): Promise<void>;
|
|
82
|
+
deleteAllForUser(userId: string): Promise<void>;
|
|
83
|
+
listForUser(userId: string): Promise<RefreshTokenInfo[]>;
|
|
84
|
+
deleteById(id: string, userId: string): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Password reset token service
|
|
88
|
+
*/
|
|
89
|
+
export declare class PasswordResetTokenService {
|
|
90
|
+
private db;
|
|
91
|
+
constructor(db: NodePgDatabase);
|
|
92
|
+
/**
|
|
93
|
+
* Create a password reset token
|
|
94
|
+
*/
|
|
95
|
+
createToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Find a valid (not expired, not used) token by hash
|
|
98
|
+
*/
|
|
99
|
+
findValidByHash(tokenHash: string): Promise<{
|
|
100
|
+
userId: string;
|
|
101
|
+
expiresAt: Date;
|
|
102
|
+
} | null>;
|
|
103
|
+
/**
|
|
104
|
+
* Mark token as used
|
|
105
|
+
*/
|
|
106
|
+
markAsUsed(tokenHash: string): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Delete all tokens for a user
|
|
109
|
+
*/
|
|
110
|
+
deleteAllForUser(userId: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Clean up expired tokens
|
|
113
|
+
*/
|
|
114
|
+
deleteExpired(): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* PostgreSQL implementation of TokenRepository.
|
|
118
|
+
* Combines refresh token and password reset token operations.
|
|
119
|
+
*/
|
|
120
|
+
export declare class PostgresTokenRepository implements TokenRepository {
|
|
121
|
+
private db;
|
|
122
|
+
private refreshTokenService;
|
|
123
|
+
private passwordResetTokenService;
|
|
124
|
+
constructor(db: NodePgDatabase);
|
|
125
|
+
createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
|
|
126
|
+
findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
|
|
127
|
+
deleteRefreshToken(tokenHash: string): Promise<void>;
|
|
128
|
+
deleteAllRefreshTokensForUser(userId: string): Promise<void>;
|
|
129
|
+
listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]>;
|
|
130
|
+
deleteRefreshTokenById(id: string, userId: string): Promise<void>;
|
|
131
|
+
createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
|
|
132
|
+
findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null>;
|
|
133
|
+
markPasswordResetTokenUsed(tokenHash: string): Promise<void>;
|
|
134
|
+
deleteAllPasswordResetTokensForUser(userId: string): Promise<void>;
|
|
135
|
+
deleteExpiredTokens(): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* PostgreSQL implementation of AuthRepository.
|
|
139
|
+
* Combines user, role, and token repository operations.
|
|
140
|
+
* This provides a convenient single-class interface for all auth operations.
|
|
141
|
+
*/
|
|
142
|
+
export declare class PostgresAuthRepository implements AuthRepository {
|
|
143
|
+
private db;
|
|
144
|
+
private userService;
|
|
145
|
+
private roleService;
|
|
146
|
+
private tokenRepository;
|
|
147
|
+
constructor(db: NodePgDatabase);
|
|
148
|
+
createUser(data: CreateUserData): Promise<UserData>;
|
|
149
|
+
getUserById(id: string): Promise<UserData | null>;
|
|
150
|
+
getUserByEmail(email: string): Promise<UserData | null>;
|
|
151
|
+
getUserByGoogleId(googleId: string): Promise<UserData | null>;
|
|
152
|
+
updateUser(id: string, data: Partial<Omit<CreateUserData, "id">>): Promise<UserData | null>;
|
|
153
|
+
deleteUser(id: string): Promise<void>;
|
|
154
|
+
listUsers(): Promise<UserData[]>;
|
|
155
|
+
listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
|
|
156
|
+
updatePassword(id: string, passwordHash: string): Promise<void>;
|
|
157
|
+
setEmailVerified(id: string, verified: boolean): Promise<void>;
|
|
158
|
+
setVerificationToken(id: string, token: string | null): Promise<void>;
|
|
159
|
+
getUserByVerificationToken(token: string): Promise<UserData | null>;
|
|
160
|
+
getUserRoles(userId: string): Promise<RoleData[]>;
|
|
161
|
+
getUserRoleIds(userId: string): Promise<string[]>;
|
|
162
|
+
setUserRoles(userId: string, roleIds: string[]): Promise<void>;
|
|
163
|
+
assignDefaultRole(userId: string, roleId: string): Promise<void>;
|
|
164
|
+
getUserWithRoles(userId: string): Promise<{
|
|
165
|
+
user: UserData;
|
|
166
|
+
roles: RoleData[];
|
|
167
|
+
} | null>;
|
|
168
|
+
getRoleById(id: string): Promise<RoleData | null>;
|
|
169
|
+
listRoles(): Promise<RoleData[]>;
|
|
170
|
+
createRole(data: CreateRoleData): Promise<RoleData>;
|
|
171
|
+
updateRole(id: string, data: Partial<Omit<RoleData, "id">>): Promise<RoleData | null>;
|
|
172
|
+
deleteRole(id: string): Promise<void>;
|
|
173
|
+
createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
|
|
174
|
+
findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
|
|
175
|
+
deleteRefreshToken(tokenHash: string): Promise<void>;
|
|
176
|
+
deleteAllRefreshTokensForUser(userId: string): Promise<void>;
|
|
177
|
+
listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]>;
|
|
178
|
+
deleteRefreshTokenById(id: string, userId: string): Promise<void>;
|
|
179
|
+
createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
|
|
180
|
+
findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null>;
|
|
181
|
+
markPasswordResetTokenUsed(tokenHash: string): Promise<void>;
|
|
182
|
+
deleteAllPasswordResetTokensForUser(userId: string): Promise<void>;
|
|
183
|
+
deleteExpiredTokens(): Promise<void>;
|
|
184
|
+
}
|
|
185
|
+
/** PostgreSQL user repository implementation */
|
|
186
|
+
export type PostgresUserRepository = UserService;
|
|
187
|
+
/** PostgreSQL role repository implementation */
|
|
188
|
+
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,7 @@
|
|
|
1
|
+
import { Pool } from "pg";
|
|
2
|
+
export declare function createPostgresDatabaseConnection(connectionString: string, schema?: Record<string, unknown>): {
|
|
3
|
+
db: import("drizzle-orm/node-postgres").NodePgDatabase<Record<string, unknown>> & {
|
|
4
|
+
$client: Pool;
|
|
5
|
+
};
|
|
6
|
+
connectionString: string;
|
|
7
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
2
|
+
import { EntityCollection, Properties, Property } from "@rebasepro/types";
|
|
3
|
+
import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
|
|
4
|
+
/**
|
|
5
|
+
* Data transformation utilities for converting between frontend and database formats.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Helper function to sanitize and convert dates to ISO strings
|
|
9
|
+
*/
|
|
10
|
+
export declare function sanitizeAndConvertDates(obj: unknown): unknown;
|
|
11
|
+
/**
|
|
12
|
+
* Transform relations for database storage (relation objects to IDs)
|
|
13
|
+
*/
|
|
14
|
+
export declare function serializeDataToServer<M extends Record<string, any>>(entity: M, properties: Properties, collection?: EntityCollection, registry?: PostgresCollectionRegistry): Record<string, unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Serialize a single property value for database storage
|
|
17
|
+
*/
|
|
18
|
+
export declare function serializePropertyToServer(value: unknown, property: Property): unknown;
|
|
19
|
+
/**
|
|
20
|
+
* Transform IDs back to relation objects for frontend
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseDataFromServer<M extends Record<string, any>>(data: M, collection: EntityCollection, db?: NodePgDatabase<any>, registry?: PostgresCollectionRegistry): Promise<M>;
|
|
23
|
+
/**
|
|
24
|
+
* Parse a single property value from database format to frontend format
|
|
25
|
+
*/
|
|
26
|
+
export declare function parsePropertyFromServer(value: unknown, property: Property, collection: EntityCollection, propertyKey?: string): unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Lightweight value normalization for db.query results.
|
|
29
|
+
* Only handles type coercion (dates, numbers, NaN) and property filtering.
|
|
30
|
+
* Does NOT query the database for relations — those are already resolved
|
|
31
|
+
* by Drizzle's relational query API.
|
|
32
|
+
*
|
|
33
|
+
* Use this instead of `parseDataFromServer` when processing results from
|
|
34
|
+
* `db.query.findFirst/findMany` which return pre-hydrated relation data.
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeDbValues<M extends Record<string, any>>(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 };
|