@rebasepro/server-postgresql 0.0.1-canary.4d4fb3e → 0.0.1-canary.5584634

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 (143) hide show
  1. package/dist/common/src/collections/CollectionRegistry.d.ts +8 -0
  2. package/dist/common/src/util/entities.d.ts +22 -0
  3. package/dist/common/src/util/relations.d.ts +14 -4
  4. package/dist/common/src/util/resolutions.d.ts +1 -1
  5. package/dist/index.es.js +1254 -591
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +1254 -591
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +17 -29
  10. package/dist/server-postgresql/src/auth/services.d.ts +7 -3
  11. package/dist/server-postgresql/src/collections/PostgresCollectionRegistry.d.ts +1 -1
  12. package/dist/server-postgresql/src/connection.d.ts +34 -1
  13. package/dist/server-postgresql/src/data-transformer.d.ts +26 -4
  14. package/dist/server-postgresql/src/databasePoolManager.d.ts +2 -2
  15. package/dist/server-postgresql/src/schema/auth-schema.d.ts +139 -38
  16. package/dist/server-postgresql/src/schema/doctor-cli.d.ts +2 -0
  17. package/dist/server-postgresql/src/schema/doctor.d.ts +43 -0
  18. package/dist/server-postgresql/src/schema/generate-drizzle-schema-logic.d.ts +1 -1
  19. package/dist/server-postgresql/src/schema/introspect-db-logic.d.ts +82 -0
  20. package/dist/server-postgresql/src/schema/introspect-db.d.ts +1 -0
  21. package/dist/server-postgresql/src/schema/test-schema.d.ts +24 -0
  22. package/dist/server-postgresql/src/services/EntityFetchService.d.ts +22 -8
  23. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +1 -1
  24. package/dist/server-postgresql/src/services/RelationService.d.ts +11 -5
  25. package/dist/server-postgresql/src/services/entity-helpers.d.ts +16 -2
  26. package/dist/server-postgresql/src/services/entityService.d.ts +8 -6
  27. package/dist/server-postgresql/src/services/realtimeService.d.ts +2 -0
  28. package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +2 -2
  29. package/dist/types/src/controllers/auth.d.ts +2 -0
  30. package/dist/types/src/controllers/client.d.ts +119 -7
  31. package/dist/types/src/controllers/collection_registry.d.ts +4 -3
  32. package/dist/types/src/controllers/customization_controller.d.ts +7 -1
  33. package/dist/types/src/controllers/data.d.ts +34 -7
  34. package/dist/types/src/controllers/data_driver.d.ts +20 -28
  35. package/dist/types/src/controllers/database_admin.d.ts +2 -2
  36. package/dist/types/src/controllers/email.d.ts +34 -0
  37. package/dist/types/src/controllers/index.d.ts +1 -0
  38. package/dist/types/src/controllers/local_config_persistence.d.ts +4 -4
  39. package/dist/types/src/controllers/navigation.d.ts +5 -5
  40. package/dist/types/src/controllers/registry.d.ts +6 -3
  41. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -6
  42. package/dist/types/src/controllers/storage.d.ts +24 -26
  43. package/dist/types/src/rebase_context.d.ts +8 -4
  44. package/dist/types/src/types/backend.d.ts +4 -1
  45. package/dist/types/src/types/builders.d.ts +5 -4
  46. package/dist/types/src/types/chips.d.ts +1 -1
  47. package/dist/types/src/types/collections.d.ts +169 -125
  48. package/dist/types/src/types/cron.d.ts +102 -0
  49. package/dist/types/src/types/data_source.d.ts +1 -1
  50. package/dist/types/src/types/entity_actions.d.ts +8 -8
  51. package/dist/types/src/types/entity_callbacks.d.ts +15 -15
  52. package/dist/types/src/types/entity_link_builder.d.ts +1 -1
  53. package/dist/types/src/types/entity_overrides.d.ts +2 -1
  54. package/dist/types/src/types/entity_views.d.ts +8 -8
  55. package/dist/types/src/types/export_import.d.ts +3 -3
  56. package/dist/types/src/types/index.d.ts +1 -0
  57. package/dist/types/src/types/plugins.d.ts +72 -18
  58. package/dist/types/src/types/properties.d.ts +118 -33
  59. package/dist/types/src/types/relations.d.ts +1 -1
  60. package/dist/types/src/types/slots.d.ts +30 -6
  61. package/dist/types/src/types/translations.d.ts +44 -0
  62. package/dist/types/src/types/user_management_delegate.d.ts +1 -0
  63. package/drizzle-test/0000_woozy_junta.sql +6 -0
  64. package/drizzle-test/0001_youthful_arachne.sql +1 -0
  65. package/drizzle-test/0002_lively_dragon_lord.sql +2 -0
  66. package/drizzle-test/0003_mean_king_cobra.sql +2 -0
  67. package/drizzle-test/meta/0000_snapshot.json +47 -0
  68. package/drizzle-test/meta/0001_snapshot.json +48 -0
  69. package/drizzle-test/meta/0002_snapshot.json +38 -0
  70. package/drizzle-test/meta/0003_snapshot.json +48 -0
  71. package/drizzle-test/meta/_journal.json +34 -0
  72. package/drizzle-test-out/0000_tan_trauma.sql +6 -0
  73. package/drizzle-test-out/0001_rapid_drax.sql +1 -0
  74. package/drizzle-test-out/meta/0000_snapshot.json +44 -0
  75. package/drizzle-test-out/meta/0001_snapshot.json +54 -0
  76. package/drizzle-test-out/meta/_journal.json +20 -0
  77. package/drizzle.test.config.ts +10 -0
  78. package/package.json +89 -89
  79. package/scratch.ts +41 -0
  80. package/src/PostgresBackendDriver.ts +63 -79
  81. package/src/PostgresBootstrapper.ts +7 -8
  82. package/src/auth/ensure-tables.ts +158 -86
  83. package/src/auth/services.ts +109 -50
  84. package/src/cli.ts +317 -16
  85. package/src/collections/PostgresCollectionRegistry.ts +6 -6
  86. package/src/connection.ts +70 -48
  87. package/src/data-transformer.ts +155 -116
  88. package/src/databasePoolManager.ts +6 -5
  89. package/src/history/HistoryService.ts +3 -12
  90. package/src/interfaces.ts +3 -3
  91. package/src/schema/auth-schema.ts +26 -3
  92. package/src/schema/doctor-cli.ts +47 -0
  93. package/src/schema/doctor.ts +595 -0
  94. package/src/schema/generate-drizzle-schema-logic.ts +204 -57
  95. package/src/schema/generate-drizzle-schema.ts +6 -6
  96. package/src/schema/introspect-db-logic.ts +592 -0
  97. package/src/schema/introspect-db.ts +211 -0
  98. package/src/schema/test-schema.ts +11 -0
  99. package/src/services/BranchService.ts +5 -5
  100. package/src/services/EntityFetchService.ts +317 -188
  101. package/src/services/EntityPersistService.ts +15 -17
  102. package/src/services/RelationService.ts +299 -37
  103. package/src/services/entity-helpers.ts +39 -13
  104. package/src/services/entityService.ts +11 -9
  105. package/src/services/realtimeService.ts +58 -29
  106. package/src/utils/drizzle-conditions.ts +25 -24
  107. package/src/websocket.ts +52 -21
  108. package/test/auth-services.test.ts +131 -39
  109. package/test/batch-many-to-many-regression.test.ts +573 -0
  110. package/test/branchService.test.ts +22 -12
  111. package/test/data-transformer-hardening.test.ts +417 -0
  112. package/test/data-transformer.test.ts +175 -0
  113. package/test/doctor.test.ts +182 -0
  114. package/test/entityService.errors.test.ts +31 -16
  115. package/test/entityService.relations.test.ts +155 -59
  116. package/test/entityService.subcollection-search.test.ts +107 -57
  117. package/test/entityService.test.ts +105 -47
  118. package/test/generate-drizzle-schema.test.ts +262 -69
  119. package/test/historyService.test.ts +31 -16
  120. package/test/introspect-db-generation.test.ts +436 -0
  121. package/test/introspect-db-utils.test.ts +389 -0
  122. package/test/n-plus-one-regression.test.ts +314 -0
  123. package/test/postgresDataDriver.test.ts +260 -168
  124. package/test/realtimeService.test.ts +70 -39
  125. package/test/relation-pipeline-gaps.test.ts +637 -0
  126. package/test/relations.test.ts +492 -39
  127. package/test/unmapped-tables-safety.test.ts +345 -0
  128. package/test-drizzle-bug.ts +18 -0
  129. package/test-drizzle-out/0000_cultured_freak.sql +7 -0
  130. package/test-drizzle-out/0001_tiresome_professor_monster.sql +1 -0
  131. package/test-drizzle-out/meta/0000_snapshot.json +55 -0
  132. package/test-drizzle-out/meta/0001_snapshot.json +63 -0
  133. package/test-drizzle-out/meta/_journal.json +20 -0
  134. package/test-drizzle-prompt.sh +2 -0
  135. package/test-policy-prompt.sh +3 -0
  136. package/test-programmatic.ts +30 -0
  137. package/test-programmatic2.ts +59 -0
  138. package/test-schema-no-policies.ts +12 -0
  139. package/test_drizzle_mock.js +2 -2
  140. package/test_find_changed.mjs +3 -1
  141. package/test_hash.js +14 -0
  142. package/tsconfig.json +1 -1
  143. package/vite.config.ts +5 -5
@@ -33,17 +33,19 @@ export declare class PostgresBackendDriver implements DataDriver {
33
33
  constructor(db: DrizzleClient, realtimeService: RealtimeService, registry: PostgresCollectionRegistry, user?: User, poolManager?: DatabasePoolManager | undefined, historyService?: HistoryService);
34
34
  /**
35
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.
36
38
  */
37
- admin: DatabaseAdmin;
39
+ get admin(): DatabaseAdmin;
38
40
  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>;
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>;
45
47
  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>;
48
+ countEntities<M extends Record<string, unknown>>({ path, collection, filter, searchString }: FetchCollectionProps<M>): Promise<number>;
47
49
  private getTargetDb;
48
50
  executeSql(sqlText: string, options?: {
49
51
  database?: string;
@@ -82,31 +84,17 @@ export declare class AuthenticatedPostgresBackendDriver implements DataDriver {
82
84
  */
83
85
  admin: DatabaseAdmin;
84
86
  private withTransaction;
85
- fetchCollection<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]>;
87
+ fetchCollection<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]>;
86
88
  /**
87
89
  * Injects the authenticated user's context into the most recently
88
90
  * registered realtime subscription so RLS-aware polling can apply.
89
91
  */
90
92
  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>;
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>;
96
98
  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>;
99
+ countEntities<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;
112
100
  }
@@ -1,6 +1,6 @@
1
1
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
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";
3
+ import { UserRepository, RoleRepository, TokenRepository, AuthRepository, UserData, CreateUserData, RoleData, CreateRoleData, RefreshTokenInfo, PasswordResetTokenInfo, UserIdentityData, ListUsersOptions, PaginatedUsersResult, RoleData as Role } from "@rebasepro/server-core";
4
4
  export type { Role };
5
5
  /**
6
6
  * PostgreSQL implementation of UserRepository.
@@ -12,7 +12,9 @@ export declare class UserService implements UserRepository {
12
12
  createUser(data: NewUser): Promise<User>;
13
13
  getUserById(id: string): Promise<User | null>;
14
14
  getUserByEmail(email: string): Promise<User | null>;
15
- getUserByGoogleId(googleId: 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>;
16
18
  updateUser(id: string, data: Partial<Omit<NewUser, "id">>): Promise<User | null>;
17
19
  deleteUser(id: string): Promise<void>;
18
20
  listUsers(): Promise<User[]>;
@@ -148,7 +150,9 @@ export declare class PostgresAuthRepository implements AuthRepository {
148
150
  createUser(data: CreateUserData): Promise<UserData>;
149
151
  getUserById(id: string): Promise<UserData | null>;
150
152
  getUserByEmail(email: string): Promise<UserData | null>;
151
- getUserByGoogleId(googleId: 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>;
152
156
  updateUser(id: string, data: Partial<Omit<CreateUserData, "id">>): Promise<UserData | null>;
153
157
  deleteUser(id: string): Promise<void>;
154
158
  listUsers(): Promise<UserData[]>;
@@ -1,5 +1,5 @@
1
1
  import { CollectionRegistry } from "@rebasepro/common";
2
- import type { EntityCollection } from "@rebasepro/types";
2
+ import { type EntityCollection } from "@rebasepro/types";
3
3
  import { PgEnum, PgTable } from "drizzle-orm/pg-core";
4
4
  import { Relations } from "drizzle-orm";
5
5
  import { CollectionRegistryInterface } from "../interfaces";
@@ -1,7 +1,40 @@
1
1
  import { Pool } from "pg";
2
- export declare function createPostgresDatabaseConnection(connectionString: string, schema?: Record<string, unknown>): {
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): {
3
35
  db: import("drizzle-orm/node-postgres").NodePgDatabase<Record<string, unknown>> & {
4
36
  $client: Pool;
5
37
  };
38
+ pool: Pool;
6
39
  connectionString: string;
7
40
  };
@@ -1,9 +1,31 @@
1
1
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
- import { EntityCollection, Properties, Property } from "@rebasepro/types";
2
+ import { EntityCollection, Properties, Property, Relation } from "@rebasepro/types";
3
3
  import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry";
4
4
  /**
5
5
  * Data transformation utilities for converting between frontend and database formats.
6
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
+ }
7
29
  /**
8
30
  * Helper function to sanitize and convert dates to ISO strings
9
31
  */
@@ -11,7 +33,7 @@ export declare function sanitizeAndConvertDates(obj: unknown): unknown;
11
33
  /**
12
34
  * Transform relations for database storage (relation objects to IDs)
13
35
  */
14
- export declare function serializeDataToServer<M extends Record<string, any>>(entity: M, properties: Properties, collection?: EntityCollection, registry?: PostgresCollectionRegistry): Record<string, unknown>;
36
+ export declare function serializeDataToServer<M extends Record<string, unknown>>(entity: M, properties: Properties, collection?: EntityCollection, registry?: PostgresCollectionRegistry): SerializedEntityData;
15
37
  /**
16
38
  * Serialize a single property value for database storage
17
39
  */
@@ -19,7 +41,7 @@ export declare function serializePropertyToServer(value: unknown, property: Prop
19
41
  /**
20
42
  * Transform IDs back to relation objects for frontend
21
43
  */
22
- export declare function parseDataFromServer<M extends Record<string, any>>(data: M, collection: EntityCollection, db?: NodePgDatabase<any>, registry?: PostgresCollectionRegistry): Promise<M>;
44
+ export declare function parseDataFromServer<M extends Record<string, unknown>>(data: M, collection: EntityCollection, db?: NodePgDatabase<Record<string, unknown>>, registry?: PostgresCollectionRegistry): Promise<M>;
23
45
  /**
24
46
  * Parse a single property value from database format to frontend format
25
47
  */
@@ -33,4 +55,4 @@ export declare function parsePropertyFromServer(value: unknown, property: Proper
33
55
  * Use this instead of `parseDataFromServer` when processing results from
34
56
  * `db.query.findFirst/findMany` which return pre-hydrated relation data.
35
57
  */
36
- export declare function normalizeDbValues<M extends Record<string, any>>(data: M, collection: EntityCollection): M;
58
+ export declare function normalizeDbValues<M extends Record<string, unknown>>(data: M, collection: EntityCollection): M;
@@ -1,5 +1,5 @@
1
- import { Pool } from 'pg';
2
- import { NodePgDatabase } from 'drizzle-orm/node-postgres';
1
+ import { Pool } from "pg";
2
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
3
3
  export declare class DatabasePoolManager {
4
4
  private pools;
5
5
  private drizzleInstances;
@@ -103,44 +103,6 @@ export declare const users: import("drizzle-orm/pg-core").PgTableWithColumns<{
103
103
  }, {}, {
104
104
  length: 500;
105
105
  }>;
106
- provider: import("drizzle-orm/pg-core").PgColumn<{
107
- name: "provider";
108
- tableName: "users";
109
- dataType: "string";
110
- columnType: "PgVarchar";
111
- data: string;
112
- driverParam: string;
113
- notNull: true;
114
- hasDefault: true;
115
- isPrimaryKey: false;
116
- isAutoincrement: false;
117
- hasRuntimeDefault: false;
118
- enumValues: [string, ...string[]];
119
- baseColumn: never;
120
- identity: undefined;
121
- generated: undefined;
122
- }, {}, {
123
- length: 50;
124
- }>;
125
- googleId: import("drizzle-orm/pg-core").PgColumn<{
126
- name: "google_id";
127
- tableName: "users";
128
- dataType: "string";
129
- columnType: "PgVarchar";
130
- data: string;
131
- driverParam: string;
132
- notNull: false;
133
- hasDefault: false;
134
- isPrimaryKey: false;
135
- isAutoincrement: false;
136
- hasRuntimeDefault: false;
137
- enumValues: [string, ...string[]];
138
- baseColumn: never;
139
- identity: undefined;
140
- generated: undefined;
141
- }, {}, {
142
- length: 255;
143
- }>;
144
106
  emailVerified: import("drizzle-orm/pg-core").PgColumn<{
145
107
  name: "email_verified";
146
108
  tableName: "users";
@@ -739,10 +701,144 @@ export declare const appConfig: import("drizzle-orm/pg-core").PgTableWithColumns
739
701
  };
740
702
  dialect: "pg";
741
703
  }>;
704
+ /**
705
+ * User identities - maps external OAuth profiles back to local users
706
+ */
707
+ export declare const userIdentities: import("drizzle-orm/pg-core").PgTableWithColumns<{
708
+ name: "user_identities";
709
+ schema: "rebase";
710
+ columns: {
711
+ id: import("drizzle-orm/pg-core").PgColumn<{
712
+ name: "id";
713
+ tableName: "user_identities";
714
+ dataType: "string";
715
+ columnType: "PgUUID";
716
+ data: string;
717
+ driverParam: string;
718
+ notNull: true;
719
+ hasDefault: true;
720
+ isPrimaryKey: true;
721
+ isAutoincrement: false;
722
+ hasRuntimeDefault: false;
723
+ enumValues: undefined;
724
+ baseColumn: never;
725
+ identity: undefined;
726
+ generated: undefined;
727
+ }, {}, {}>;
728
+ userId: import("drizzle-orm/pg-core").PgColumn<{
729
+ name: "user_id";
730
+ tableName: "user_identities";
731
+ dataType: "string";
732
+ columnType: "PgUUID";
733
+ data: string;
734
+ driverParam: string;
735
+ notNull: true;
736
+ hasDefault: false;
737
+ isPrimaryKey: false;
738
+ isAutoincrement: false;
739
+ hasRuntimeDefault: false;
740
+ enumValues: undefined;
741
+ baseColumn: never;
742
+ identity: undefined;
743
+ generated: undefined;
744
+ }, {}, {}>;
745
+ provider: import("drizzle-orm/pg-core").PgColumn<{
746
+ name: "provider";
747
+ tableName: "user_identities";
748
+ dataType: "string";
749
+ columnType: "PgVarchar";
750
+ data: string;
751
+ driverParam: string;
752
+ notNull: true;
753
+ hasDefault: false;
754
+ isPrimaryKey: false;
755
+ isAutoincrement: false;
756
+ hasRuntimeDefault: false;
757
+ enumValues: [string, ...string[]];
758
+ baseColumn: never;
759
+ identity: undefined;
760
+ generated: undefined;
761
+ }, {}, {
762
+ length: 50;
763
+ }>;
764
+ providerId: import("drizzle-orm/pg-core").PgColumn<{
765
+ name: "provider_id";
766
+ tableName: "user_identities";
767
+ dataType: "string";
768
+ columnType: "PgVarchar";
769
+ data: string;
770
+ driverParam: string;
771
+ notNull: true;
772
+ hasDefault: false;
773
+ isPrimaryKey: false;
774
+ isAutoincrement: false;
775
+ hasRuntimeDefault: false;
776
+ enumValues: [string, ...string[]];
777
+ baseColumn: never;
778
+ identity: undefined;
779
+ generated: undefined;
780
+ }, {}, {
781
+ length: 255;
782
+ }>;
783
+ profileData: import("drizzle-orm/pg-core").PgColumn<{
784
+ name: "profile_data";
785
+ tableName: "user_identities";
786
+ dataType: "json";
787
+ columnType: "PgJsonb";
788
+ data: unknown;
789
+ driverParam: unknown;
790
+ notNull: false;
791
+ hasDefault: false;
792
+ isPrimaryKey: false;
793
+ isAutoincrement: false;
794
+ hasRuntimeDefault: false;
795
+ enumValues: undefined;
796
+ baseColumn: never;
797
+ identity: undefined;
798
+ generated: undefined;
799
+ }, {}, {}>;
800
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
801
+ name: "created_at";
802
+ tableName: "user_identities";
803
+ dataType: "date";
804
+ columnType: "PgTimestamp";
805
+ data: Date;
806
+ driverParam: string;
807
+ notNull: true;
808
+ hasDefault: true;
809
+ isPrimaryKey: false;
810
+ isAutoincrement: false;
811
+ hasRuntimeDefault: false;
812
+ enumValues: undefined;
813
+ baseColumn: never;
814
+ identity: undefined;
815
+ generated: undefined;
816
+ }, {}, {}>;
817
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
818
+ name: "updated_at";
819
+ tableName: "user_identities";
820
+ dataType: "date";
821
+ columnType: "PgTimestamp";
822
+ data: Date;
823
+ driverParam: string;
824
+ notNull: true;
825
+ hasDefault: true;
826
+ isPrimaryKey: false;
827
+ isAutoincrement: false;
828
+ hasRuntimeDefault: false;
829
+ enumValues: undefined;
830
+ baseColumn: never;
831
+ identity: undefined;
832
+ generated: undefined;
833
+ }, {}, {}>;
834
+ };
835
+ dialect: "pg";
836
+ }>;
742
837
  export declare const usersRelations: import("drizzle-orm").Relations<"users", {
743
838
  userRoles: import("drizzle-orm").Many<"user_roles">;
744
839
  refreshTokens: import("drizzle-orm").Many<"refresh_tokens">;
745
840
  passwordResetTokens: import("drizzle-orm").Many<"password_reset_tokens">;
841
+ userIdentities: import("drizzle-orm").Many<"user_identities">;
746
842
  }>;
747
843
  export declare const rolesRelations: import("drizzle-orm").Relations<"roles", {
748
844
  userRoles: import("drizzle-orm").Many<"user_roles">;
@@ -757,6 +853,9 @@ export declare const refreshTokensRelations: import("drizzle-orm").Relations<"re
757
853
  export declare const passwordResetTokensRelations: import("drizzle-orm").Relations<"password_reset_tokens", {
758
854
  user: import("drizzle-orm").One<"users", true>;
759
855
  }>;
856
+ export declare const userIdentitiesRelations: import("drizzle-orm").Relations<"user_identities", {
857
+ user: import("drizzle-orm").One<"users", true>;
858
+ }>;
760
859
  export type User = typeof users.$inferSelect;
761
860
  export type NewUser = typeof users.$inferInsert;
762
861
  export type Role = typeof roles.$inferSelect;
@@ -765,3 +864,5 @@ export type UserRole = typeof userRoles.$inferSelect;
765
864
  export type RefreshToken = typeof refreshTokens.$inferSelect;
766
865
  export type PasswordResetToken = typeof passwordResetTokens.$inferSelect;
767
866
  export type AppConfig = typeof appConfig.$inferSelect;
867
+ export type UserIdentity = typeof userIdentities.$inferSelect;
868
+ export type NewUserIdentity = typeof userIdentities.$inferInsert;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,43 @@
1
+ import { EntityCollection, Property } from "@rebasepro/types";
2
+ export type IssueSeverity = "error" | "warning" | "info";
3
+ export interface DoctorIssue {
4
+ severity: IssueSeverity;
5
+ category: "missing_table" | "missing_column" | "type_mismatch" | "missing_constraint" | "schema_stale" | "missing_enum" | "enum_value_mismatch" | "missing_foreign_key";
6
+ table?: string;
7
+ column?: string;
8
+ expected?: string;
9
+ actual?: string;
10
+ message: string;
11
+ fix: string;
12
+ }
13
+ export interface DoctorReport {
14
+ collectionsToSchema: {
15
+ passed: boolean;
16
+ issues: DoctorIssue[];
17
+ };
18
+ schemaToDatabase: {
19
+ passed: boolean;
20
+ issues: DoctorIssue[];
21
+ };
22
+ summary: {
23
+ passed: number;
24
+ warnings: number;
25
+ errors: number;
26
+ };
27
+ }
28
+ export declare function getExpectedColumnType(prop: Property): string | null;
29
+ export declare function loadCollections(collectionsPath: string): Promise<EntityCollection[]>;
30
+ export declare function checkCollectionsVsSchema(collections: EntityCollection[], schemaFilePath: string): Promise<{
31
+ passed: boolean;
32
+ issues: DoctorIssue[];
33
+ }>;
34
+ export declare function checkCollectionsVsDatabase(collections: EntityCollection[], databaseUrl: string): Promise<{
35
+ passed: boolean;
36
+ issues: DoctorIssue[];
37
+ }>;
38
+ export declare function renderReport(report: DoctorReport): void;
39
+ export declare function runDoctor(options: {
40
+ collectionsPath: string;
41
+ schemaPath: string;
42
+ databaseUrl?: string;
43
+ }): Promise<DoctorReport>;
@@ -1,2 +1,2 @@
1
1
  import { EntityCollection } from "@rebasepro/types";
2
- export declare const generateSchema: (collections: EntityCollection[]) => Promise<string>;
2
+ export declare const generateSchema: (collections: EntityCollection[], stripPolicies?: boolean) => Promise<string>;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Introspection logic — pure functions and the pipeline that transforms
3
+ * raw PostgreSQL metadata into Rebase collection definition files.
4
+ *
5
+ * This module contains NO side-effects: no fs writes, no pg.Client creation,
6
+ * no process.exit. It is imported by introspect-db.ts (the CLI entry-point)
7
+ * and consumed directly by tests.
8
+ */
9
+ export interface TableRow {
10
+ table_name: string;
11
+ }
12
+ export interface TableColumn {
13
+ table_name: string;
14
+ column_name: string;
15
+ data_type: string;
16
+ udt_name: string;
17
+ is_nullable: string;
18
+ column_default: string | null;
19
+ }
20
+ export interface EnumValue {
21
+ enum_name: string;
22
+ enum_value: string;
23
+ sort_order: number;
24
+ }
25
+ export interface PrimaryKeyRow {
26
+ table_name: string;
27
+ column_name: string;
28
+ }
29
+ export interface ForeignKeyRow {
30
+ table_name: string;
31
+ column_name: string;
32
+ foreign_table_name: string;
33
+ foreign_column_name: string;
34
+ }
35
+ export interface TableMeta {
36
+ name: string;
37
+ columns: TableColumn[];
38
+ pks: string[];
39
+ fks: ForeignKeyRow[];
40
+ }
41
+ export declare function singularize(word: string): string;
42
+ /**
43
+ * Convert a snake_case name to a human-readable Title Case label.
44
+ * e.g. "created_at" -> "Created At", "customer_id" -> "Customer Id"
45
+ */
46
+ export declare function humanize(snakeName: string): string;
47
+ /**
48
+ * Convert a snake_case table name to a camelCase + "Collection" variable name.
49
+ * e.g. "company_token" -> "companyTokenCollection"
50
+ */
51
+ export declare function toCollectionVarName(tableName: string): string;
52
+ export declare function getIconForTable(tableName: string): string;
53
+ /**
54
+ * Map a PostgreSQL data type to a Rebase property type.
55
+ */
56
+ export declare function mapPgType(dataType: string): string;
57
+ export declare function buildEnumMap(enumValues: EnumValue[]): Map<string, string[]>;
58
+ export declare function buildTablesMap(tables: TableRow[], columns: TableColumn[], pks: PrimaryKeyRow[], fks: ForeignKeyRow[]): Map<string, TableMeta>;
59
+ export declare function identifyJoinTables(tablesMap: Map<string, TableMeta>): Set<string>;
60
+ export interface GeneratedFile {
61
+ tableName: string;
62
+ fileName: string;
63
+ content: string;
64
+ }
65
+ /**
66
+ * Generate the full TypeScript file content for a single collection.
67
+ * Pure function — no I/O.
68
+ */
69
+ export declare function generateCollectionFile(tableName: string, meta: TableMeta, allFks: ForeignKeyRow[], joinTables: Set<string>, tablesMap: Map<string, TableMeta>, enumMap: Map<string, string[]>): string;
70
+ /**
71
+ * Generate the content for an index.ts file that re-exports all collections.
72
+ */
73
+ export declare function generateIndexContent(fileNames: string[]): string;
74
+ /**
75
+ * Merge new exports into existing index.ts content.
76
+ * Returns the merged content string.
77
+ */
78
+ export declare function mergeIndexContent(existingContent: string, newFileNames: string[]): string;
79
+ /**
80
+ * Safely extract the host portion of a database URL for logging.
81
+ */
82
+ export declare function safeHostFromUrl(url: string): string;
@@ -0,0 +1,24 @@
1
+ export declare const testTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "test";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: "id";
7
+ tableName: "test";
8
+ dataType: "string";
9
+ columnType: "PgText";
10
+ data: string;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: false;
14
+ isPrimaryKey: true;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: [string, ...string[]];
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {}>;
22
+ };
23
+ dialect: "pg";
24
+ }>;