@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.
- package/LICENSE +22 -0
- package/README.md +86 -0
- package/dist/PostgresAdapter.d.ts +6 -0
- package/dist/PostgresBackendDriver.d.ts +150 -0
- package/dist/PostgresBootstrapper.d.ts +51 -0
- package/dist/auth/ensure-tables.d.ts +10 -0
- package/dist/auth/services.d.ts +250 -0
- package/dist/backup/backup-cli.d.ts +3 -0
- package/dist/backup/backup-cron.d.ts +53 -0
- package/dist/backup/backup-service.d.ts +85 -0
- package/dist/backup/index.d.ts +12 -0
- package/dist/backup/pg-tools.d.ts +110 -0
- package/dist/backup/retention.d.ts +35 -0
- package/dist/chunk-DSJWtz9O.js +40 -0
- package/dist/cli-errors.d.ts +42 -0
- package/dist/cli-helpers.d.ts +7 -0
- package/dist/cli.d.ts +1 -0
- package/dist/collections/PostgresCollectionRegistry.d.ts +47 -0
- package/dist/connection.d.ts +65 -0
- package/dist/data-transformer.d.ts +55 -0
- package/dist/databasePoolManager.d.ts +20 -0
- package/dist/history/HistoryService.d.ts +71 -0
- package/dist/history/ensure-history-table.d.ts +7 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.es.js +23535 -0
- package/dist/index.es.js.map +1 -0
- package/dist/interfaces.d.ts +18 -0
- package/dist/schema/auth-bootstrap-sql.d.ts +24 -0
- package/dist/schema/auth-default-policies.d.ts +10 -0
- package/dist/schema/auth-schema.d.ts +2376 -0
- package/dist/schema/doctor-cli.d.ts +2 -0
- package/dist/schema/doctor.d.ts +58 -0
- package/dist/schema/dynamic-tables.d.ts +31 -0
- package/dist/schema/generate-drizzle-schema-logic.d.ts +2 -0
- package/dist/schema/generate-drizzle-schema.d.ts +1 -0
- package/dist/schema/generate-postgres-ddl-logic.d.ts +5 -0
- package/dist/schema/generate-postgres-ddl.d.ts +1 -0
- package/dist/schema/introspect-db-inference.d.ts +5 -0
- package/dist/schema/introspect-db-logic.d.ts +118 -0
- package/dist/schema/introspect-db.d.ts +1 -0
- package/dist/schema/introspect-runtime.d.ts +57 -0
- package/dist/schema/test-schema.d.ts +24 -0
- package/dist/security/policy-drift.d.ts +57 -0
- package/dist/security/rls-enforcement.d.ts +122 -0
- package/dist/services/BranchService.d.ts +47 -0
- package/dist/services/FetchService.d.ts +214 -0
- package/dist/services/PersistService.d.ts +39 -0
- package/dist/services/RelationService.d.ts +109 -0
- package/dist/services/cdc/CdcListener.d.ts +54 -0
- package/dist/services/cdc/trigger-cdc.d.ts +64 -0
- package/dist/services/collection-helpers.d.ts +38 -0
- package/dist/services/dataService.d.ts +110 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/realtimeService.d.ts +298 -0
- package/dist/src-Eh-CZosp.js +595 -0
- package/dist/src-Eh-CZosp.js.map +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/utils/drizzle-conditions.d.ts +138 -0
- package/dist/utils/pg-array-null-patch.d.ts +16 -0
- package/dist/utils/pg-error-utils.d.ts +65 -0
- package/dist/utils/table-classification.d.ts +8 -0
- package/dist/websocket.d.ts +18 -0
- package/package.json +113 -0
- package/src/PostgresAdapter.ts +58 -0
- package/src/PostgresBackendDriver.ts +1387 -0
- package/src/PostgresBootstrapper.ts +581 -0
- package/src/auth/ensure-tables.ts +367 -0
- package/src/auth/services.ts +1321 -0
- package/src/backup/backup-cli.ts +383 -0
- package/src/backup/backup-cron.ts +189 -0
- package/src/backup/backup-service.ts +299 -0
- package/src/backup/index.ts +12 -0
- package/src/backup/pg-tools.ts +231 -0
- package/src/backup/retention.ts +75 -0
- package/src/cli-errors.ts +265 -0
- package/src/cli-helpers.ts +196 -0
- package/src/cli.ts +786 -0
- package/src/collections/PostgresCollectionRegistry.ts +103 -0
- package/src/connection.ts +166 -0
- package/src/data-transformer.ts +733 -0
- package/src/databasePoolManager.ts +87 -0
- package/src/history/HistoryService.ts +272 -0
- package/src/history/ensure-history-table.ts +46 -0
- package/src/index.ts +15 -0
- package/src/interfaces.ts +60 -0
- package/src/schema/auth-bootstrap-sql.ts +41 -0
- package/src/schema/auth-default-policies.ts +125 -0
- package/src/schema/auth-schema.ts +233 -0
- package/src/schema/doctor-cli.ts +113 -0
- package/src/schema/doctor.ts +733 -0
- package/src/schema/dynamic-tables.test.ts +302 -0
- package/src/schema/dynamic-tables.ts +293 -0
- package/src/schema/generate-drizzle-schema-logic.ts +850 -0
- package/src/schema/generate-drizzle-schema.ts +131 -0
- package/src/schema/generate-postgres-ddl-logic.ts +490 -0
- package/src/schema/generate-postgres-ddl.ts +92 -0
- package/src/schema/introspect-db-inference.ts +238 -0
- package/src/schema/introspect-db-logic.ts +910 -0
- package/src/schema/introspect-db.ts +266 -0
- package/src/schema/introspect-runtime.test.ts +212 -0
- package/src/schema/introspect-runtime.ts +293 -0
- package/src/schema/test-schema.ts +11 -0
- package/src/security/policy-drift.test.ts +122 -0
- package/src/security/policy-drift.ts +159 -0
- package/src/security/rls-enforcement.ts +295 -0
- package/src/services/BranchService.ts +251 -0
- package/src/services/FetchService.ts +1661 -0
- package/src/services/PersistService.ts +329 -0
- package/src/services/RelationService.ts +1306 -0
- package/src/services/cdc/CdcListener.ts +167 -0
- package/src/services/cdc/trigger-cdc.ts +169 -0
- package/src/services/collection-helpers.ts +151 -0
- package/src/services/dataService.ts +246 -0
- package/src/services/index.ts +13 -0
- package/src/services/realtimeService.ts +1502 -0
- package/src/types.ts +4 -0
- package/src/utils/drizzle-conditions.ts +1162 -0
- package/src/utils/pg-array-null-patch.ts +42 -0
- package/src/utils/pg-error-utils.ts +227 -0
- package/src/utils/table-classification.ts +16 -0
- package/src/websocket.ts +640 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { StorageController } from "@rebasepro/server";
|
|
2
|
+
import { BackupDestination, VersionCompatibility } from "./pg-tools";
|
|
3
|
+
import { BackupObject, RetentionOptions } from "./retention";
|
|
4
|
+
export declare class BackupToolError extends Error {
|
|
5
|
+
readonly hint?: string | undefined;
|
|
6
|
+
constructor(message: string, hint?: string | undefined);
|
|
7
|
+
}
|
|
8
|
+
/** Locate `pg_dump` / `pg_restore`, honouring an env override. */
|
|
9
|
+
export declare function resolvePgBinary(tool: "pg_dump" | "pg_restore", env?: Record<string, string | undefined>): string | null;
|
|
10
|
+
/** Run `<bin> --version` and extract the major version. */
|
|
11
|
+
export declare function detectToolMajor(bin: string): Promise<number | null>;
|
|
12
|
+
/** Query the server for its major version via `server_version_num`. */
|
|
13
|
+
export declare function getServerVersionMajor(connectionString: string): Promise<number | null>;
|
|
14
|
+
export interface PreflightResult extends VersionCompatibility {
|
|
15
|
+
bin: string;
|
|
16
|
+
toolMajor: number | null;
|
|
17
|
+
serverMajor: number | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Verify the requested client tool exists and its major version is
|
|
21
|
+
* compatible with the live server. Throws {@link BackupToolError} — with a
|
|
22
|
+
* doctor-style hint — when the binary is missing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function preflight(tool: "pg_dump" | "pg_restore", connectionString: string, env?: Record<string, string | undefined>): Promise<PreflightResult>;
|
|
25
|
+
export interface BackupResult {
|
|
26
|
+
/** Absolute path of the produced dump file on local disk. */
|
|
27
|
+
localFile: string;
|
|
28
|
+
fileName: string;
|
|
29
|
+
sizeBytes: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Produce a custom-format dump on local disk. When `outDir` is omitted the
|
|
33
|
+
* file is written to the OS temp directory (used by the upload path, which
|
|
34
|
+
* cleans it up afterwards).
|
|
35
|
+
*/
|
|
36
|
+
export declare function createDump(opts: {
|
|
37
|
+
connectionString: string;
|
|
38
|
+
dbName: string;
|
|
39
|
+
outDir?: string;
|
|
40
|
+
fileName?: string;
|
|
41
|
+
excludeSchemas?: string[];
|
|
42
|
+
noOwner?: boolean;
|
|
43
|
+
inheritStdio?: boolean;
|
|
44
|
+
env?: Record<string, string | undefined>;
|
|
45
|
+
}): Promise<BackupResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Restore a custom-format dump into the database named by
|
|
48
|
+
* `connectionString`. Destructive when `clean` is set (drops objects
|
|
49
|
+
* first). Never called automatically — the CLI gates it behind explicit
|
|
50
|
+
* confirmation.
|
|
51
|
+
*/
|
|
52
|
+
export declare function restoreDump(opts: {
|
|
53
|
+
connectionString: string;
|
|
54
|
+
inputFile: string;
|
|
55
|
+
clean?: boolean;
|
|
56
|
+
noOwner?: boolean;
|
|
57
|
+
inheritStdio?: boolean;
|
|
58
|
+
env?: Record<string, string | undefined>;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Create a database (if absent) by connecting to the maintenance
|
|
62
|
+
* `postgres` database. Used by `restore --create-db`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function ensureDatabaseExists(adminConnectionString: string, dbName: string): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Upload a local dump to object storage under the destination's prefix.
|
|
67
|
+
* Backups may contain secrets/PII, so the object is written with a
|
|
68
|
+
* private/octet-stream content type; bucket-level ACLs must stay private.
|
|
69
|
+
*/
|
|
70
|
+
export declare function uploadBackup(storage: StorageController, localFile: string, dest: Extract<BackupDestination, {
|
|
71
|
+
kind: "s3" | "gcs";
|
|
72
|
+
}>): Promise<{
|
|
73
|
+
key: string;
|
|
74
|
+
storageUrl: string;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* List existing backups at a destination. For local destinations reads the
|
|
78
|
+
* directory; for object storage lists the prefix via the controller.
|
|
79
|
+
*/
|
|
80
|
+
export declare function listBackups(dest: BackupDestination, storage?: StorageController): Promise<BackupObject[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Apply a retention policy to a destination, deleting the backups selected
|
|
83
|
+
* by {@link selectBackupsToPrune}. Returns the keys that were removed.
|
|
84
|
+
*/
|
|
85
|
+
export declare function pruneBackups(dest: BackupDestination, options: RetentionOptions, storage?: StorageController): Promise<string[]>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup / restore for self-hosted rebase.
|
|
3
|
+
*
|
|
4
|
+
* - `pg-tools` — pure argument/version/path helpers (unit-tested)
|
|
5
|
+
* - `retention` — pure retention-pruning policy (unit-tested)
|
|
6
|
+
* - `backup-service`— pg_dump/pg_restore + storage orchestration
|
|
7
|
+
* - `backup-cron` — scheduled backups for the server cron system
|
|
8
|
+
*/
|
|
9
|
+
export * from "./pg-tools";
|
|
10
|
+
export * from "./retention";
|
|
11
|
+
export * from "./backup-service";
|
|
12
|
+
export * from "./backup-cron";
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for the backup/restore commands.
|
|
3
|
+
*
|
|
4
|
+
* Everything in this file is side-effect free so it can be unit-tested
|
|
5
|
+
* without a live Postgres server, matching the constraint that CI must
|
|
6
|
+
* not require a database.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* A parsed backup destination. `--out` (and the scheduled-backup config)
|
|
10
|
+
* accepts either a local filesystem path or an object-storage URL.
|
|
11
|
+
*/
|
|
12
|
+
export type BackupDestination = {
|
|
13
|
+
kind: "local";
|
|
14
|
+
path: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "s3";
|
|
17
|
+
bucket: string;
|
|
18
|
+
prefix: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "gcs";
|
|
21
|
+
bucket: string;
|
|
22
|
+
prefix: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Extract the database name from a Postgres connection string.
|
|
26
|
+
* Returns `null` when the URL has no database path (e.g. bare host).
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseDbNameFromUrl(connectionString: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Swap the database name in a connection string, preserving credentials,
|
|
31
|
+
* host, port and query params. Used by `--target-db` / `--create-db` so a
|
|
32
|
+
* restore can target a fresh database instead of clobbering the live one.
|
|
33
|
+
*/
|
|
34
|
+
export declare function withDatabaseName(connectionString: string, dbName: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Parse the major version out of `pg_dump --version` / `pg_restore --version`
|
|
37
|
+
* output, e.g. `"pg_dump (PostgreSQL) 16.2"` → `16`. Handles the pre-10
|
|
38
|
+
* `9.6.x` scheme (returns `9`) and beta strings like `"17beta1"`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parsePgToolMajor(versionOutput: string): number | null;
|
|
41
|
+
/**
|
|
42
|
+
* Convert `SELECT current_setting('server_version_num')` (e.g. `160002`)
|
|
43
|
+
* into a major version (`16`). Also accepts pre-10 encodings like `90603`
|
|
44
|
+
* → `9`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function serverVersionNumToMajor(versionNum: number | string): number | null;
|
|
47
|
+
export interface VersionCompatibility {
|
|
48
|
+
compatible: boolean;
|
|
49
|
+
reason?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* pg_dump / pg_restore must be **at least** as new as the server they talk
|
|
53
|
+
* to. A newer client against an older server is supported; an older client
|
|
54
|
+
* against a newer server is not and produces corrupt or rejected output.
|
|
55
|
+
*/
|
|
56
|
+
export declare function checkToolServerCompatibility(toolMajor: number | null, serverMajor: number | null): VersionCompatibility;
|
|
57
|
+
/**
|
|
58
|
+
* Build a deterministic, sortable backup file name:
|
|
59
|
+
* `rebase-<db>-<YYYYMMDD>T<HHMMSS>Z.dump`
|
|
60
|
+
*
|
|
61
|
+
* The UTC timestamp is embedded so retention pruning can recover the
|
|
62
|
+
* creation time from the object key alone, without extra metadata.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildBackupFilename(dbName: string, date?: Date): string;
|
|
65
|
+
/**
|
|
66
|
+
* Recover the creation timestamp encoded in a backup file name by
|
|
67
|
+
* {@link buildBackupFilename}. Returns `null` for names that don't match,
|
|
68
|
+
* so foreign objects in a shared prefix are never pruned.
|
|
69
|
+
*/
|
|
70
|
+
export declare function parseBackupTimestamp(fileName: string): Date | null;
|
|
71
|
+
/**
|
|
72
|
+
* Parse a destination string into a structured {@link BackupDestination}.
|
|
73
|
+
* `s3://bucket/prefix` and `gs://bucket/prefix` map to object storage;
|
|
74
|
+
* anything else is treated as a local path.
|
|
75
|
+
*/
|
|
76
|
+
export declare function parseBackupDestination(out: string): BackupDestination;
|
|
77
|
+
/**
|
|
78
|
+
* Join a storage prefix and a file name without producing a leading or
|
|
79
|
+
* doubled slash.
|
|
80
|
+
*/
|
|
81
|
+
export declare function joinStorageKey(prefix: string, fileName: string): string;
|
|
82
|
+
/**
|
|
83
|
+
* Assemble the `pg_dump` argument vector. Uses the custom format (`-Fc`),
|
|
84
|
+
* which is compressed and restorable selectively via `pg_restore`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function buildPgDumpArgs(opts: {
|
|
87
|
+
connectionString: string;
|
|
88
|
+
outFile: string;
|
|
89
|
+
/** Extra schemas/tables to exclude, e.g. Atlas revision tables. */
|
|
90
|
+
excludeSchemas?: string[];
|
|
91
|
+
/** Number of parallel jobs (directory format only; ignored for -Fc). */
|
|
92
|
+
noOwner?: boolean;
|
|
93
|
+
}): string[];
|
|
94
|
+
/**
|
|
95
|
+
* Assemble the `pg_restore` argument vector for a custom-format dump.
|
|
96
|
+
*/
|
|
97
|
+
export declare function buildPgRestoreArgs(opts: {
|
|
98
|
+
connectionString: string;
|
|
99
|
+
inputFile: string;
|
|
100
|
+
/** Drop objects before recreating them (destructive but idempotent). */
|
|
101
|
+
clean?: boolean;
|
|
102
|
+
/** Continue past individual errors instead of aborting. */
|
|
103
|
+
exitOnError?: boolean;
|
|
104
|
+
noOwner?: boolean;
|
|
105
|
+
}): string[];
|
|
106
|
+
/**
|
|
107
|
+
* Resolve the Postgres connection string the backup commands should use,
|
|
108
|
+
* mirroring the precedence the branch command already relies on.
|
|
109
|
+
*/
|
|
110
|
+
export declare function resolveConnectionString(env: Record<string, string | undefined>): string | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface BackupObject {
|
|
2
|
+
/** Storage key / file name. */
|
|
3
|
+
key: string;
|
|
4
|
+
/**
|
|
5
|
+
* Creation time. Optional — when absent it is recovered from the
|
|
6
|
+
* timestamp encoded in the key by `buildBackupFilename`.
|
|
7
|
+
*/
|
|
8
|
+
createdAt?: Date;
|
|
9
|
+
}
|
|
10
|
+
export interface RetentionOptions {
|
|
11
|
+
/** Delete backups older than this many days. `0`/negative disables age pruning. */
|
|
12
|
+
retentionDays?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Always keep at least this many of the most recent backups, even if
|
|
15
|
+
* they are older than `retentionDays`. Guards against wiping every
|
|
16
|
+
* backup after a long outage. Default: 0 (no minimum).
|
|
17
|
+
*/
|
|
18
|
+
keepMinimum?: number;
|
|
19
|
+
/** Reference "now" — injectable for deterministic tests. */
|
|
20
|
+
now?: Date;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Decide which backups to delete under the given retention policy.
|
|
24
|
+
*
|
|
25
|
+
* Rules, applied in order:
|
|
26
|
+
* 1. Objects whose key isn't a recognised rebase backup (no parseable
|
|
27
|
+
* timestamp and no `createdAt`) are never selected — foreign files in a
|
|
28
|
+
* shared bucket are left untouched.
|
|
29
|
+
* 2. The `keepMinimum` newest backups are always retained.
|
|
30
|
+
* 3. Of the remainder, any older than `retentionDays` are selected for
|
|
31
|
+
* deletion.
|
|
32
|
+
*
|
|
33
|
+
* Returns the keys to delete, oldest first.
|
|
34
|
+
*/
|
|
35
|
+
export declare function selectBackupsToPrune(backups: BackupObject[], options: RetentionOptions): string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
import "process";
|
|
3
|
+
const require = __createRequire(import.meta.url);
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var __create = Object.create;
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
12
|
+
var __exportAll = (all, no_symbols) => {
|
|
13
|
+
let target = {};
|
|
14
|
+
for (var name in all) __defProp(target, name, {
|
|
15
|
+
get: all[name],
|
|
16
|
+
enumerable: true
|
|
17
|
+
});
|
|
18
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
23
|
+
key = keys[i];
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
25
|
+
get: ((k) => from[k]).bind(null, key),
|
|
26
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return to;
|
|
30
|
+
};
|
|
31
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
32
|
+
value: mod,
|
|
33
|
+
enumerable: true
|
|
34
|
+
}) : target, mod));
|
|
35
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
|
|
36
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
37
|
+
throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
|
|
38
|
+
});
|
|
39
|
+
//#endregion
|
|
40
|
+
export { __toESM as i, __exportAll as n, __require as r, __commonJSMin as t };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect whether an error (or AggregateError wrapping multiple attempts)
|
|
3
|
+
* represents an ECONNREFUSED — i.e. the database is simply not running.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Direct `{ code: "ECONNREFUSED" }` errors from Node `net`
|
|
7
|
+
* - `AggregateError` from dual-stack IPv4+IPv6 connection attempts
|
|
8
|
+
* - Drizzle's `cause`-wrapped pg errors
|
|
9
|
+
*/
|
|
10
|
+
export declare function isEconnrefused(err: unknown): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Detect PostgreSQL authentication failures.
|
|
13
|
+
* PG error codes: 28P01 (invalid_password), 28000 (invalid_authorization_specification)
|
|
14
|
+
*/
|
|
15
|
+
export declare function isAuthFailure(err: unknown): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Detect the "SSL is not enabled on the server" failure — the client attempted
|
|
18
|
+
* an SSL handshake against a Postgres server that doesn't support it (common
|
|
19
|
+
* with a plain local dev database). The fix is `?sslmode=disable` on the URL.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isSslNotEnabled(err: unknown): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Detect PostgreSQL "cannot drop ... because other objects depend on it"
|
|
24
|
+
* (error code 2BP01, dependent_objects_still_exist). This is the failure that
|
|
25
|
+
* strands a declarative `db push` half-applied when a collection is removed but
|
|
26
|
+
* an enum type it defined is still referenced by another object.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isDependencyDropError(err: unknown): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Pre-flight check: verify that the database is reachable before running
|
|
31
|
+
* a heavy subprocess (Atlas, migrations, etc.).
|
|
32
|
+
*
|
|
33
|
+
* Exits with code 1 and a friendly banner on known failure modes.
|
|
34
|
+
* On unknown errors, logs a warning and allows the caller to proceed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function checkDatabaseConnectivity(databaseUrl: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Post-hoc error diagnosis for direct database operations (e.g. applyPolicies).
|
|
39
|
+
* Returns a formatted diagnostic string if the error matches a known pattern,
|
|
40
|
+
* or null if unrecognized.
|
|
41
|
+
*/
|
|
42
|
+
export declare function diagnoseDbError(err: unknown, databaseUrl?: string): string | null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
export declare function resolveLocalBin(binName: string): string | null;
|
|
3
|
+
export declare function getTableIncludesFromCollections(collections: CollectionConfig[]): Promise<string[]>;
|
|
4
|
+
export declare function getTableIncludes(collectionsPath: string): Promise<string[]>;
|
|
5
|
+
export declare function getDevDatabaseUrl(databaseUrl: string): string;
|
|
6
|
+
export declare function ensureDevDatabaseExists(databaseUrl: string, devDatabaseUrl: string): Promise<void>;
|
|
7
|
+
export declare function getTableExcludes(databaseUrl: string, collectionsPath: string): Promise<string[]>;
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runPluginCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CollectionRegistry } from "@rebasepro/common";
|
|
2
|
+
import { type CollectionConfig } 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
|
+
* Returns all registered table names.
|
|
24
|
+
*/
|
|
25
|
+
getTableNames(): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Finds collections assigned to a specific data source that do not have a registered table.
|
|
28
|
+
*/
|
|
29
|
+
getCollectionsWithoutTables(dataSourceKey?: string): CollectionConfig[];
|
|
30
|
+
registerEnums(enums: Record<string, PgEnum<[string, ...string[]]>>): void;
|
|
31
|
+
registerRelations(relations: Record<string, Relations>): void;
|
|
32
|
+
getEnum(name: string): PgEnum<[string, ...string[]]> | undefined;
|
|
33
|
+
getRelation(name: string): Relations | undefined;
|
|
34
|
+
getAllEnums(): Record<string, PgEnum<[string, ...string[]]>>;
|
|
35
|
+
getAllRelations(): Record<string, Relations>;
|
|
36
|
+
/**
|
|
37
|
+
* Get the merged schema object (tables + relations) for use with Drizzle's
|
|
38
|
+
* relational query API (`db.query`).
|
|
39
|
+
*/
|
|
40
|
+
getMergedSchema(): Record<string, unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the available Drizzle relation keys for a given collection path.
|
|
43
|
+
* Maps from the collection's relation property names to the Drizzle relation names
|
|
44
|
+
* defined in the schema.
|
|
45
|
+
*/
|
|
46
|
+
getRelationKeysForCollection(collectionPath: string): string[];
|
|
47
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Create a direct (non-pooled) connection for operations that require
|
|
43
|
+
* session-level features incompatible with PgBouncer transaction mode,
|
|
44
|
+
* such as LISTEN/NOTIFY, prepared statements, or advisory locks.
|
|
45
|
+
*
|
|
46
|
+
* Uses a smaller pool since this is only for specific use cases.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createDirectDatabaseConnection(connectionString: string, schema?: Record<string, unknown>, poolConfig?: PostgresPoolConfig): {
|
|
49
|
+
db: import("drizzle-orm/node-postgres").NodePgDatabase<Record<string, unknown>> & {
|
|
50
|
+
$client: Pool;
|
|
51
|
+
};
|
|
52
|
+
pool: Pool;
|
|
53
|
+
connectionString: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Create a read-only connection for routing read queries to replicas.
|
|
57
|
+
* Uses a moderate pool size since reads are distributed across replicas.
|
|
58
|
+
*/
|
|
59
|
+
export declare function createReadReplicaConnection(connectionString: string, schema?: Record<string, unknown>, poolConfig?: PostgresPoolConfig): {
|
|
60
|
+
db: import("drizzle-orm/node-postgres").NodePgDatabase<Record<string, unknown>> & {
|
|
61
|
+
$client: Pool;
|
|
62
|
+
};
|
|
63
|
+
pool: Pool;
|
|
64
|
+
connectionString: string;
|
|
65
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
2
|
+
import { CollectionConfig, 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
|
+
currentId?: 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>>(row: M, properties: Properties, collection?: CollectionConfig, 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: CollectionConfig, db?: NodePgDatabase<Record<string, unknown>>, registry?: PostgresCollectionRegistry): Promise<M>;
|
|
45
|
+
export declare function parsePropertyFromServer(value: unknown, property: Property, collection: CollectionConfig, propertyKey?: string): unknown;
|
|
46
|
+
/**
|
|
47
|
+
* Lightweight value normalization for db.query results.
|
|
48
|
+
* Only handles type coercion (dates, numbers, NaN) and property filtering.
|
|
49
|
+
* Does NOT query the database for relations — those are already resolved
|
|
50
|
+
* by Drizzle's relational query API.
|
|
51
|
+
*
|
|
52
|
+
* Use this instead of `parseDataFromServer` when processing results from
|
|
53
|
+
* `db.query.findFirst/findMany` which return pre-hydrated relation data.
|
|
54
|
+
*/
|
|
55
|
+
export declare function normalizeDbValues<M extends Record<string, unknown>>(data: M, collection: CollectionConfig): 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<Record<string, never>>;
|
|
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
|
+
id: 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 row. 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 row change history.
|
|
33
|
+
* Stores history entries 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 row 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 row.
|
|
45
|
+
*/
|
|
46
|
+
recordHistory(params: RecordHistoryParams): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Fetch history entries for an row, ordered by most recent first.
|
|
49
|
+
*/
|
|
50
|
+
fetchHistory(tableName: string, id: 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 row: enforce maxEntries and TTL.
|
|
60
|
+
*/
|
|
61
|
+
pruneEntity(tableName: string, id: string): Promise<number>;
|
|
62
|
+
/**
|
|
63
|
+
* Global prune: enforce TTL across ALL rows 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 row 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>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
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 "./backup";
|
|
14
|
+
export * from "./PostgresBootstrapper";
|
|
15
|
+
export * from "./PostgresAdapter";
|