@rebasepro/server-postgres 0.0.1-canary.4829d6e

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 (121) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +86 -0
  3. package/dist/PostgresAdapter.d.ts +6 -0
  4. package/dist/PostgresBackendDriver.d.ts +150 -0
  5. package/dist/PostgresBootstrapper.d.ts +51 -0
  6. package/dist/auth/ensure-tables.d.ts +10 -0
  7. package/dist/auth/services.d.ts +250 -0
  8. package/dist/backup/backup-cli.d.ts +3 -0
  9. package/dist/backup/backup-cron.d.ts +53 -0
  10. package/dist/backup/backup-service.d.ts +85 -0
  11. package/dist/backup/index.d.ts +12 -0
  12. package/dist/backup/pg-tools.d.ts +110 -0
  13. package/dist/backup/retention.d.ts +35 -0
  14. package/dist/chunk-DSJWtz9O.js +40 -0
  15. package/dist/cli-errors.d.ts +42 -0
  16. package/dist/cli-helpers.d.ts +7 -0
  17. package/dist/cli.d.ts +1 -0
  18. package/dist/collections/PostgresCollectionRegistry.d.ts +47 -0
  19. package/dist/connection.d.ts +65 -0
  20. package/dist/data-transformer.d.ts +55 -0
  21. package/dist/databasePoolManager.d.ts +20 -0
  22. package/dist/history/HistoryService.d.ts +71 -0
  23. package/dist/history/ensure-history-table.d.ts +7 -0
  24. package/dist/index.d.ts +15 -0
  25. package/dist/index.es.js +23535 -0
  26. package/dist/index.es.js.map +1 -0
  27. package/dist/interfaces.d.ts +18 -0
  28. package/dist/schema/auth-bootstrap-sql.d.ts +24 -0
  29. package/dist/schema/auth-default-policies.d.ts +10 -0
  30. package/dist/schema/auth-schema.d.ts +2376 -0
  31. package/dist/schema/doctor-cli.d.ts +2 -0
  32. package/dist/schema/doctor.d.ts +58 -0
  33. package/dist/schema/dynamic-tables.d.ts +31 -0
  34. package/dist/schema/generate-drizzle-schema-logic.d.ts +2 -0
  35. package/dist/schema/generate-drizzle-schema.d.ts +1 -0
  36. package/dist/schema/generate-postgres-ddl-logic.d.ts +5 -0
  37. package/dist/schema/generate-postgres-ddl.d.ts +1 -0
  38. package/dist/schema/introspect-db-inference.d.ts +5 -0
  39. package/dist/schema/introspect-db-logic.d.ts +118 -0
  40. package/dist/schema/introspect-db.d.ts +1 -0
  41. package/dist/schema/introspect-runtime.d.ts +57 -0
  42. package/dist/schema/test-schema.d.ts +24 -0
  43. package/dist/security/policy-drift.d.ts +57 -0
  44. package/dist/security/rls-enforcement.d.ts +122 -0
  45. package/dist/services/BranchService.d.ts +47 -0
  46. package/dist/services/FetchService.d.ts +214 -0
  47. package/dist/services/PersistService.d.ts +39 -0
  48. package/dist/services/RelationService.d.ts +109 -0
  49. package/dist/services/cdc/CdcListener.d.ts +54 -0
  50. package/dist/services/cdc/trigger-cdc.d.ts +64 -0
  51. package/dist/services/collection-helpers.d.ts +38 -0
  52. package/dist/services/dataService.d.ts +110 -0
  53. package/dist/services/index.d.ts +4 -0
  54. package/dist/services/realtimeService.d.ts +298 -0
  55. package/dist/src-Eh-CZosp.js +595 -0
  56. package/dist/src-Eh-CZosp.js.map +1 -0
  57. package/dist/types.d.ts +3 -0
  58. package/dist/utils/drizzle-conditions.d.ts +138 -0
  59. package/dist/utils/pg-array-null-patch.d.ts +16 -0
  60. package/dist/utils/pg-error-utils.d.ts +65 -0
  61. package/dist/utils/table-classification.d.ts +8 -0
  62. package/dist/websocket.d.ts +18 -0
  63. package/package.json +113 -0
  64. package/src/PostgresAdapter.ts +58 -0
  65. package/src/PostgresBackendDriver.ts +1387 -0
  66. package/src/PostgresBootstrapper.ts +581 -0
  67. package/src/auth/ensure-tables.ts +367 -0
  68. package/src/auth/services.ts +1321 -0
  69. package/src/backup/backup-cli.ts +383 -0
  70. package/src/backup/backup-cron.ts +189 -0
  71. package/src/backup/backup-service.ts +299 -0
  72. package/src/backup/index.ts +12 -0
  73. package/src/backup/pg-tools.ts +231 -0
  74. package/src/backup/retention.ts +75 -0
  75. package/src/cli-errors.ts +265 -0
  76. package/src/cli-helpers.ts +196 -0
  77. package/src/cli.ts +786 -0
  78. package/src/collections/PostgresCollectionRegistry.ts +103 -0
  79. package/src/connection.ts +166 -0
  80. package/src/data-transformer.ts +733 -0
  81. package/src/databasePoolManager.ts +87 -0
  82. package/src/history/HistoryService.ts +272 -0
  83. package/src/history/ensure-history-table.ts +46 -0
  84. package/src/index.ts +15 -0
  85. package/src/interfaces.ts +60 -0
  86. package/src/schema/auth-bootstrap-sql.ts +41 -0
  87. package/src/schema/auth-default-policies.ts +125 -0
  88. package/src/schema/auth-schema.ts +233 -0
  89. package/src/schema/doctor-cli.ts +113 -0
  90. package/src/schema/doctor.ts +733 -0
  91. package/src/schema/dynamic-tables.test.ts +302 -0
  92. package/src/schema/dynamic-tables.ts +293 -0
  93. package/src/schema/generate-drizzle-schema-logic.ts +850 -0
  94. package/src/schema/generate-drizzle-schema.ts +131 -0
  95. package/src/schema/generate-postgres-ddl-logic.ts +490 -0
  96. package/src/schema/generate-postgres-ddl.ts +92 -0
  97. package/src/schema/introspect-db-inference.ts +238 -0
  98. package/src/schema/introspect-db-logic.ts +910 -0
  99. package/src/schema/introspect-db.ts +266 -0
  100. package/src/schema/introspect-runtime.test.ts +212 -0
  101. package/src/schema/introspect-runtime.ts +293 -0
  102. package/src/schema/test-schema.ts +11 -0
  103. package/src/security/policy-drift.test.ts +122 -0
  104. package/src/security/policy-drift.ts +159 -0
  105. package/src/security/rls-enforcement.ts +295 -0
  106. package/src/services/BranchService.ts +251 -0
  107. package/src/services/FetchService.ts +1661 -0
  108. package/src/services/PersistService.ts +329 -0
  109. package/src/services/RelationService.ts +1306 -0
  110. package/src/services/cdc/CdcListener.ts +167 -0
  111. package/src/services/cdc/trigger-cdc.ts +169 -0
  112. package/src/services/collection-helpers.ts +151 -0
  113. package/src/services/dataService.ts +246 -0
  114. package/src/services/index.ts +13 -0
  115. package/src/services/realtimeService.ts +1502 -0
  116. package/src/types.ts +4 -0
  117. package/src/utils/drizzle-conditions.ts +1162 -0
  118. package/src/utils/pg-array-null-patch.ts +42 -0
  119. package/src/utils/pg-error-utils.ts +227 -0
  120. package/src/utils/table-classification.ts +16 -0
  121. package/src/websocket.ts +640 -0
@@ -0,0 +1,103 @@
1
+ import { CollectionRegistry } from "@rebasepro/common";
2
+ import { type CollectionConfig, type Relation, getDataSourceCapabilities } from "@rebasepro/types";
3
+ import { PgEnum, PgTable } from "drizzle-orm/pg-core";
4
+ import { Relations } from "drizzle-orm";
5
+ import { CollectionRegistryInterface } from "../interfaces";
6
+ import { getTableName } from "@rebasepro/common";
7
+
8
+ /**
9
+ * PostgreSQL-specific collection registry.
10
+ * Extends the base CollectionRegistry with support for Drizzle ORM tables, enums, and relations.
11
+ *
12
+ * Satisfies CollectionRegistryInterface through inheritance from CollectionRegistry.
13
+ */
14
+ export class PostgresCollectionRegistry extends CollectionRegistry implements CollectionRegistryInterface {
15
+
16
+ private tables = new Map<string, PgTable>();
17
+ private enums = new Map<string, PgEnum<[string, ...string[]]>>();
18
+ private relations = new Map<string, Relations>();
19
+
20
+ registerTable(table: PgTable, tableName: string) {
21
+ this.tables.set(tableName, table);
22
+ }
23
+
24
+ getTable(tableName: string): PgTable | undefined {
25
+ return this.tables.get(tableName);
26
+ }
27
+
28
+ /**
29
+ * Checks if a specific collection has a registered table
30
+ */
31
+ hasTableForCollection(tableName: string): boolean {
32
+ return this.tables.has(tableName);
33
+ }
34
+
35
+ /**
36
+ * Returns all registered table names.
37
+ */
38
+ getTableNames(): string[] {
39
+ return Array.from(this.tables.keys());
40
+ }
41
+
42
+ /**
43
+ * Finds collections assigned to a specific data source that do not have a registered table.
44
+ */
45
+ getCollectionsWithoutTables(dataSourceKey = "(default)"): CollectionConfig[] {
46
+ const collections = this.getCollections().filter(
47
+ c => c.dataSource === dataSourceKey || (!c.dataSource && dataSourceKey === "(default)")
48
+ );
49
+ return collections.filter(c => !this.tables.has(getTableName(c)));
50
+ }
51
+
52
+ registerEnums(enums: Record<string, PgEnum<[string, ...string[]]>>) {
53
+ Object.entries(enums).forEach(([name, value]) => this.enums.set(name, value));
54
+ }
55
+
56
+ registerRelations(relations: Record<string, Relations>) {
57
+ Object.entries(relations).forEach(([name, value]) => this.relations.set(name, value));
58
+ }
59
+
60
+ getEnum(name: string): PgEnum<[string, ...string[]]> | undefined {
61
+ return this.enums.get(name);
62
+ }
63
+
64
+ getRelation(name: string): Relations | undefined {
65
+ return this.relations.get(name);
66
+ }
67
+
68
+ getAllEnums(): Record<string, PgEnum<[string, ...string[]]>> {
69
+ return Object.fromEntries(this.enums.entries());
70
+ }
71
+
72
+ getAllRelations(): Record<string, Relations> {
73
+ return Object.fromEntries(this.relations.entries());
74
+ }
75
+
76
+ /**
77
+ * Get the merged schema object (tables + relations) for use with Drizzle's
78
+ * relational query API (`db.query`).
79
+ */
80
+ getMergedSchema(): Record<string, unknown> {
81
+ const result: Record<string, unknown> = {};
82
+ for (const [name, table] of this.tables.entries()) {
83
+ result[name] = table;
84
+ }
85
+ for (const [name, relation] of this.relations.entries()) {
86
+ result[name] = relation;
87
+ }
88
+ return result;
89
+ }
90
+
91
+ /**
92
+ * Get the available Drizzle relation keys for a given collection path.
93
+ * Maps from the collection's relation property names to the Drizzle relation names
94
+ * defined in the schema.
95
+ */
96
+ getRelationKeysForCollection(collectionPath: string): string[] {
97
+ const collection = this.getCollectionByPath(collectionPath);
98
+ if (!collection || !getDataSourceCapabilities(collection.engine).supportsRelations || !collection.relations) return [];
99
+ return collection.relations!.map((r: Relation) => r.relationName || r.localKey || "").filter(Boolean);
100
+ }
101
+
102
+ }
103
+
@@ -0,0 +1,166 @@
1
+ import { Pool, PoolConfig } from "pg";
2
+ import { drizzle } from "drizzle-orm/node-postgres";
3
+ import { logger } from "@rebasepro/server";
4
+
5
+ /**
6
+ * Configuration for the Postgres connection pool.
7
+ *
8
+ * Sensible defaults are provided for production Cloud Run / single-instance
9
+ * deployments. Override via environment variables or explicit config.
10
+ */
11
+ export interface PostgresPoolConfig {
12
+ /** Maximum number of connections in the pool (default: 20) */
13
+ max?: number;
14
+ /** Close idle connections after this many ms (default: 30 000) */
15
+ idleTimeoutMillis?: number;
16
+ /** Abort connection attempts after this many ms (default: 10 000) */
17
+ connectionTimeoutMillis?: number;
18
+ /** Per-query timeout in ms (default: 30 000) */
19
+ queryTimeout?: number;
20
+ /** Per-statement timeout in ms (default: 30 000) */
21
+ statementTimeout?: number;
22
+ /** Enable TCP keep-alive (default: true) */
23
+ keepAlive?: boolean;
24
+ }
25
+
26
+ const DEFAULT_POOL: Required<PostgresPoolConfig> = {
27
+ max: 20,
28
+ idleTimeoutMillis: 30_000,
29
+ connectionTimeoutMillis: 10_000,
30
+ queryTimeout: 30_000,
31
+ statementTimeout: 30_000,
32
+ keepAlive: true
33
+ };
34
+
35
+ /**
36
+ * Create a Drizzle-backed Postgres connection with a production-grade
37
+ * connection pool.
38
+ *
39
+ * @param connectionString Postgres connection URL
40
+ * @param schema Optional Drizzle schema for the relational API
41
+ * @param poolConfig Optional pool tuning (merged over defaults)
42
+ *
43
+ * @returns `{ db, pool, connectionString }` — the `pool` is exposed so
44
+ * callers can register shutdown hooks (`pool.end()`) or monitor
45
+ * pool metrics.
46
+ */
47
+ export function createPostgresDatabaseConnection(
48
+ connectionString: string,
49
+ schema?: Record<string, unknown>,
50
+ poolConfig?: PostgresPoolConfig
51
+ ) {
52
+ const opts = { ...DEFAULT_POOL,
53
+ ...poolConfig };
54
+
55
+ const pgPoolConfig: PoolConfig = {
56
+ connectionString,
57
+ max: opts.max,
58
+ idleTimeoutMillis: opts.idleTimeoutMillis,
59
+ connectionTimeoutMillis: opts.connectionTimeoutMillis,
60
+ query_timeout: opts.queryTimeout,
61
+ statement_timeout: opts.statementTimeout,
62
+ keepAlive: opts.keepAlive,
63
+ keepAliveInitialDelayMillis: 0
64
+ };
65
+
66
+ const pool = new Pool(pgPoolConfig);
67
+
68
+ // ── Pool event logging ────────────────────────────────────────────────
69
+ // Uses console.* because the structured logger lives in server
70
+ // (a separate package). The caller can replace these with the structured
71
+ // logger if desired via pool.on() after creation.
72
+ pool.on("error", (err) => {
73
+ logger.error("[pg-pool] Unexpected pool error", { detail: err.message });
74
+ if (err.message.includes("ETIMEDOUT")) {
75
+ logger.warn("[pg-pool] Connection timeout detected — pool will auto-retry");
76
+ }
77
+ });
78
+
79
+ // Create drizzle instance — pass schema when available to enable db.query relational API
80
+ const db = schema ? drizzle(pool, { schema }) : drizzle(pool);
81
+
82
+ return { db,
83
+ pool,
84
+ connectionString };
85
+ }
86
+
87
+ /**
88
+ * Create a direct (non-pooled) connection for operations that require
89
+ * session-level features incompatible with PgBouncer transaction mode,
90
+ * such as LISTEN/NOTIFY, prepared statements, or advisory locks.
91
+ *
92
+ * Uses a smaller pool since this is only for specific use cases.
93
+ */
94
+ export function createDirectDatabaseConnection(
95
+ connectionString: string,
96
+ schema?: Record<string, unknown>,
97
+ poolConfig?: PostgresPoolConfig
98
+ ) {
99
+ const opts = {
100
+ ...DEFAULT_POOL,
101
+ max: 5,
102
+ ...poolConfig
103
+ };
104
+
105
+ const pgPoolConfig: PoolConfig = {
106
+ connectionString,
107
+ max: opts.max,
108
+ idleTimeoutMillis: opts.idleTimeoutMillis,
109
+ connectionTimeoutMillis: opts.connectionTimeoutMillis,
110
+ query_timeout: opts.queryTimeout,
111
+ statement_timeout: opts.statementTimeout,
112
+ keepAlive: opts.keepAlive,
113
+ keepAliveInitialDelayMillis: 0
114
+ };
115
+
116
+ const pool = new Pool(pgPoolConfig);
117
+
118
+ pool.on("error", (err) => {
119
+ logger.error("[pg-direct-pool] Unexpected pool error", { detail: err.message });
120
+ });
121
+
122
+ const db = schema ? drizzle(pool, { schema }) : drizzle(pool);
123
+
124
+ return { db,
125
+ pool,
126
+ connectionString };
127
+ }
128
+
129
+ /**
130
+ * Create a read-only connection for routing read queries to replicas.
131
+ * Uses a moderate pool size since reads are distributed across replicas.
132
+ */
133
+ export function createReadReplicaConnection(
134
+ connectionString: string,
135
+ schema?: Record<string, unknown>,
136
+ poolConfig?: PostgresPoolConfig
137
+ ) {
138
+ const opts = {
139
+ ...DEFAULT_POOL,
140
+ max: 10,
141
+ ...poolConfig
142
+ };
143
+
144
+ const pgPoolConfig: PoolConfig = {
145
+ connectionString,
146
+ max: opts.max,
147
+ idleTimeoutMillis: opts.idleTimeoutMillis,
148
+ connectionTimeoutMillis: opts.connectionTimeoutMillis,
149
+ query_timeout: opts.queryTimeout,
150
+ statement_timeout: opts.statementTimeout,
151
+ keepAlive: opts.keepAlive,
152
+ keepAliveInitialDelayMillis: 0
153
+ };
154
+
155
+ const pool = new Pool(pgPoolConfig);
156
+
157
+ pool.on("error", (err) => {
158
+ logger.error("[pg-replica-pool] Unexpected pool error", { detail: err.message });
159
+ });
160
+
161
+ const db = schema ? drizzle(pool, { schema }) : drizzle(pool);
162
+
163
+ return { db,
164
+ pool,
165
+ connectionString };
166
+ }