@rebasepro/server-postgres 0.15.0 → 0.16.0
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/dist/PostgresBackendDriver.d.ts +1 -1
- package/dist/PostgresBootstrapper.d.ts +0 -11
- package/dist/auth/services.d.ts +2 -2
- package/dist/{auth-users-columns-JJ8ngvy5.js → auth-users-columns-CgyPWQ18.js} +3 -3
- package/dist/auth-users-columns-CgyPWQ18.js.map +1 -0
- package/dist/backup/backup-logic.d.ts +20 -0
- package/dist/backup/backup-service.d.ts +6 -0
- package/dist/backup/retention.d.ts +11 -0
- package/dist/{backup-service-czK-OAuG.js → backup-service-BZoixhVl.js} +56 -11
- package/dist/backup-service-BZoixhVl.js.map +1 -0
- package/dist/collections-schema-version-BMeu3cgv.js +81 -0
- package/dist/collections-schema-version-BMeu3cgv.js.map +1 -0
- package/dist/{ensure-collection-policies-D5PtQLyR.js → ensure-collection-policies-BVFb2olB.js} +4 -3
- package/dist/ensure-collection-policies-BVFb2olB.js.map +1 -0
- package/dist/{ensure-collection-tables-BHUjQ-z4.js → ensure-collection-tables-BY1pHRD_.js} +2 -2
- package/dist/{ensure-collection-tables-BHUjQ-z4.js.map → ensure-collection-tables-BY1pHRD_.js.map} +1 -1
- package/dist/index.es.js +65 -21
- package/dist/index.es.js.map +1 -1
- package/dist/{rls-enforcement-BDBfuTD4.js → rls-enforcement-Ch0T6OwW.js} +7 -7
- package/dist/rls-enforcement-Ch0T6OwW.js.map +1 -0
- package/dist/schema/collections-schema-version.d.ts +32 -0
- package/dist/security/policy-drift.d.ts +2 -2
- package/dist/security/rls-enforcement.d.ts +6 -6
- package/dist/services/realtimeService.d.ts +3 -1
- package/dist/src-BBFsDaeA.js.map +1 -1
- package/dist/websocket-BVgDVO-V.js.map +1 -1
- package/package.json +6 -6
- package/src/PostgresAdapter.ts +14 -0
- package/src/PostgresBackendDriver.ts +3 -3
- package/src/PostgresBootstrapper.ts +82 -12
- package/src/auth/services.ts +2 -2
- package/src/backup/backup-cli.ts +49 -12
- package/src/backup/backup-logic.ts +31 -0
- package/src/backup/backup-service.ts +42 -8
- package/src/backup/pg-tools.ts +12 -1
- package/src/backup/retention.ts +11 -0
- package/src/schema/collections-schema-version.ts +103 -0
- package/src/security/policy-drift.test.ts +25 -6
- package/src/security/policy-drift.ts +14 -6
- package/src/security/rls-enforcement.ts +7 -7
- package/src/services/realtimeService.ts +9 -1
- package/dist/auth-users-columns-JJ8ngvy5.js.map +0 -1
- package/dist/backup-service-czK-OAuG.js.map +0 -1
- package/dist/ensure-collection-policies-D5PtQLyR.js.map +0 -1
- package/dist/rls-enforcement-BDBfuTD4.js.map +0 -1
|
@@ -21,3 +21,23 @@ export declare function applyGlobalsWith(runStatement: (sql: string) => Promise<
|
|
|
21
21
|
* `deleteObject` removes one key and rejects if it cannot (e.g. not found).
|
|
22
22
|
*/
|
|
23
23
|
export declare function pruneWith(keys: string[], deleteObject: (key: string) => Promise<void>): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Remove a dump artifact abandoned by a failed tool run.
|
|
26
|
+
*
|
|
27
|
+
* `pg_dump` creates its `--file=` target before it finishes connecting, so any
|
|
28
|
+
* failure — a URL libpq rejects, a dropped connection, a full disk — leaves a
|
|
29
|
+
* 0-byte file behind. That corpse is not inert: `rebase db backups list` used
|
|
30
|
+
* to show it as an ordinary entry, and `selectBackupsToPrune` ranks by
|
|
31
|
+
* timestamp alone, so it occupies a protected `keepMinimum` slot and can push
|
|
32
|
+
* a real backup out of retention.
|
|
33
|
+
*
|
|
34
|
+
* Best-effort on purpose: the caller is already throwing, and a failed unlink
|
|
35
|
+
* must not replace the real diagnosis with an ENOENT/EPERM from the cleanup.
|
|
36
|
+
*
|
|
37
|
+
* Lives here rather than in `backup-service.ts` for the reason at the top of
|
|
38
|
+
* this file — that module's top-level `execa` import makes it unloadable under
|
|
39
|
+
* jest, so anything placed there cannot be unit-tested.
|
|
40
|
+
*
|
|
41
|
+
* `remove` deletes one file and throws if it cannot; `exists` reports presence.
|
|
42
|
+
*/
|
|
43
|
+
export declare function discardPartialDumpWith(exists: (file: string) => boolean, remove: (file: string) => void, file: string): void;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { StorageController } from "@rebasepro/server";
|
|
2
2
|
import { BackupDestination, type RowSecurityIdentity, VersionCompatibility } from "./pg-tools";
|
|
3
3
|
import { BackupObject, RetentionOptions } from "./retention";
|
|
4
|
+
/**
|
|
5
|
+
* Remove a dump artifact abandoned by a failed tool run. See
|
|
6
|
+
* {@link discardPartialDumpWith} for why this exists and why the logic lives
|
|
7
|
+
* in the execa-free module.
|
|
8
|
+
*/
|
|
9
|
+
export declare function discardPartialDump(file: string): void;
|
|
4
10
|
export declare class BackupToolError extends Error {
|
|
5
11
|
readonly hint?: string | undefined;
|
|
6
12
|
constructor(message: string, hint?: string | undefined);
|
|
@@ -6,6 +6,17 @@ export interface BackupObject {
|
|
|
6
6
|
* timestamp encoded in the key by `buildBackupFilename`.
|
|
7
7
|
*/
|
|
8
8
|
createdAt?: Date;
|
|
9
|
+
/**
|
|
10
|
+
* Size on disk, when the lister knows it (local destinations always do).
|
|
11
|
+
*
|
|
12
|
+
* Reported so an empty artifact cannot masquerade as a backup in
|
|
13
|
+
* `rebase db backups list`. Deliberately NOT consulted by
|
|
14
|
+
* {@link selectBackupsToPrune}: retention decides by age, and a rule that
|
|
15
|
+
* silently skipped small files would make a genuinely tiny dump immortal.
|
|
16
|
+
* Visibility is the fix here; the artifacts themselves are now removed at
|
|
17
|
+
* the point of failure by `discardPartialDump`.
|
|
18
|
+
*/
|
|
19
|
+
sizeBytes?: number;
|
|
9
20
|
}
|
|
10
21
|
export interface RetentionOptions {
|
|
11
22
|
/** Delete backups older than this many days. `0`/negative disables age pruning. */
|
|
@@ -344,7 +344,10 @@ function globalsFileForDump(dumpPath) {
|
|
|
344
344
|
* abort the rest. Drops `--` comment lines and blank statements.
|
|
345
345
|
*/
|
|
346
346
|
function splitGlobalsStatements(sql) {
|
|
347
|
-
return sql.split("\n").filter((line) =>
|
|
347
|
+
return sql.split("\n").filter((line) => {
|
|
348
|
+
const trimmed = line.trim();
|
|
349
|
+
return !trimmed.startsWith("--") && !trimmed.startsWith("\\");
|
|
350
|
+
}).join("\n").split(";").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
348
351
|
}
|
|
349
352
|
/**
|
|
350
353
|
* Resolve the Postgres connection string the backup commands should use,
|
|
@@ -8696,6 +8699,30 @@ async function pruneWith(keys, deleteObject) {
|
|
|
8696
8699
|
} catch {}
|
|
8697
8700
|
}
|
|
8698
8701
|
}
|
|
8702
|
+
/**
|
|
8703
|
+
* Remove a dump artifact abandoned by a failed tool run.
|
|
8704
|
+
*
|
|
8705
|
+
* `pg_dump` creates its `--file=` target before it finishes connecting, so any
|
|
8706
|
+
* failure — a URL libpq rejects, a dropped connection, a full disk — leaves a
|
|
8707
|
+
* 0-byte file behind. That corpse is not inert: `rebase db backups list` used
|
|
8708
|
+
* to show it as an ordinary entry, and `selectBackupsToPrune` ranks by
|
|
8709
|
+
* timestamp alone, so it occupies a protected `keepMinimum` slot and can push
|
|
8710
|
+
* a real backup out of retention.
|
|
8711
|
+
*
|
|
8712
|
+
* Best-effort on purpose: the caller is already throwing, and a failed unlink
|
|
8713
|
+
* must not replace the real diagnosis with an ENOENT/EPERM from the cleanup.
|
|
8714
|
+
*
|
|
8715
|
+
* Lives here rather than in `backup-service.ts` for the reason at the top of
|
|
8716
|
+
* this file — that module's top-level `execa` import makes it unloadable under
|
|
8717
|
+
* jest, so anything placed there cannot be unit-tested.
|
|
8718
|
+
*
|
|
8719
|
+
* `remove` deletes one file and throws if it cannot; `exists` reports presence.
|
|
8720
|
+
*/
|
|
8721
|
+
function discardPartialDumpWith(exists, remove, file) {
|
|
8722
|
+
try {
|
|
8723
|
+
if (exists(file)) remove(file);
|
|
8724
|
+
} catch {}
|
|
8725
|
+
}
|
|
8699
8726
|
//#endregion
|
|
8700
8727
|
//#region src/backup/backup-service.ts
|
|
8701
8728
|
/**
|
|
@@ -8712,6 +8739,7 @@ var backup_service_exports = /* @__PURE__ */ __exportAll({
|
|
|
8712
8739
|
applyGlobals: () => applyGlobals,
|
|
8713
8740
|
createDump: () => createDump,
|
|
8714
8741
|
detectToolMajor: () => detectToolMajor,
|
|
8742
|
+
discardPartialDump: () => discardPartialDump,
|
|
8715
8743
|
ensureDatabaseExists: () => ensureDatabaseExists,
|
|
8716
8744
|
getServerVersionMajor: () => getServerVersionMajor,
|
|
8717
8745
|
listBackups: () => listBackups,
|
|
@@ -8722,6 +8750,14 @@ var backup_service_exports = /* @__PURE__ */ __exportAll({
|
|
|
8722
8750
|
uploadBackup: () => uploadBackup,
|
|
8723
8751
|
validateDump: () => validateDump
|
|
8724
8752
|
});
|
|
8753
|
+
/**
|
|
8754
|
+
* Remove a dump artifact abandoned by a failed tool run. See
|
|
8755
|
+
* {@link discardPartialDumpWith} for why this exists and why the logic lives
|
|
8756
|
+
* in the execa-free module.
|
|
8757
|
+
*/
|
|
8758
|
+
function discardPartialDump(file) {
|
|
8759
|
+
discardPartialDumpWith((f) => fs.existsSync(f), (f) => fs.unlinkSync(f), file);
|
|
8760
|
+
}
|
|
8725
8761
|
var BackupToolError = class extends Error {
|
|
8726
8762
|
hint;
|
|
8727
8763
|
constructor(message, hint) {
|
|
@@ -8806,6 +8842,7 @@ async function createDump(opts) {
|
|
|
8806
8842
|
env: dumpEnv
|
|
8807
8843
|
});
|
|
8808
8844
|
} catch (error) {
|
|
8845
|
+
discardPartialDump(localFile);
|
|
8809
8846
|
const diagnosis = diagnoseRowSecurityDumpFailure(error);
|
|
8810
8847
|
if (!diagnosis) throw error;
|
|
8811
8848
|
throw new BackupToolError(diagnosis, "Run `rebase db backup --help` for the flag, and read what it says about partial dumps.");
|
|
@@ -8819,13 +8856,19 @@ async function createDump(opts) {
|
|
|
8819
8856
|
const dumpallBin = resolvePgBinary("pg_dumpall", env);
|
|
8820
8857
|
if (!dumpallBin) throw new BackupToolError("Could not find the 'pg_dumpall' binary needed to capture cluster roles.", "Install the PostgreSQL client tools or set PG_DUMPALL_PATH. To take a role-incomplete backup anyway, pass includeGlobals: false.");
|
|
8821
8858
|
const globalsFile = globalsFileForDump(localFile);
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8859
|
+
try {
|
|
8860
|
+
await execa(dumpallBin, buildPgDumpallGlobalsArgs({
|
|
8861
|
+
connectionString: opts.connectionString,
|
|
8862
|
+
outFile: globalsFile
|
|
8863
|
+
}), {
|
|
8864
|
+
stdio: opts.inheritStdio ? "inherit" : "pipe",
|
|
8865
|
+
env: { ...env }
|
|
8866
|
+
});
|
|
8867
|
+
} catch (error) {
|
|
8868
|
+
discardPartialDump(globalsFile);
|
|
8869
|
+
discardPartialDump(localFile);
|
|
8870
|
+
throw error;
|
|
8871
|
+
}
|
|
8829
8872
|
result.globalsFile = globalsFile;
|
|
8830
8873
|
result.globalsSizeBytes = fs.existsSync(globalsFile) ? fs.statSync(globalsFile).size : 0;
|
|
8831
8874
|
}
|
|
@@ -8962,9 +9005,11 @@ async function listBackups(dest, storage) {
|
|
|
8962
9005
|
const dir = fs.statSync(dest.path).isDirectory() ? dest.path : path.dirname(dest.path);
|
|
8963
9006
|
return fs.readdirSync(dir).filter((f) => f.endsWith(".dump")).map((f) => {
|
|
8964
9007
|
const full = path.join(dir, f);
|
|
9008
|
+
const stats = fs.statSync(full);
|
|
8965
9009
|
return {
|
|
8966
9010
|
key: full,
|
|
8967
|
-
createdAt: parseBackupTimestamp(f) ??
|
|
9011
|
+
createdAt: parseBackupTimestamp(f) ?? stats.mtime,
|
|
9012
|
+
sizeBytes: stats.size
|
|
8968
9013
|
};
|
|
8969
9014
|
}).sort((a, b) => (b.createdAt?.getTime() ?? 0) - (a.createdAt?.getTime() ?? 0));
|
|
8970
9015
|
}
|
|
@@ -8993,6 +9038,6 @@ async function pruneBackups(dest, options, storage) {
|
|
|
8993
9038
|
return toDelete;
|
|
8994
9039
|
}
|
|
8995
9040
|
//#endregion
|
|
8996
|
-
export {
|
|
9041
|
+
export { parseDbNameFromUrl as A, buildRowSecurityPgOptions as C, joinStorageKey as D, globalsFileForDump as E, withDatabaseName as F, resolveConnectionString as M, serverVersionNumToMajor as N, parseBackupDestination as O, splitGlobalsStatements as P, buildPgRestoreListArgs as S, diagnoseRowSecurityDumpFailure as T, selectBackupsToPrune as _, detectToolMajor as a, buildPgDumpallGlobalsArgs as b, getServerVersionMajor as c, pruneBackups as d, resolvePgBinary as f, require_source as g, validateDump as h, createDump as i, parsePgToolMajor as j, parseBackupTimestamp as k, listBackups as l, uploadBackup as m, applyGlobals as n, discardPartialDump as o, restoreDump as p, backup_service_exports as r, ensureDatabaseExists as s, BackupToolError as t, preflight as u, buildBackupFilename as v, checkToolServerCompatibility as w, buildPgRestoreArgs as x, buildPgDumpArgs as y };
|
|
8997
9042
|
|
|
8998
|
-
//# sourceMappingURL=backup-service-
|
|
9043
|
+
//# sourceMappingURL=backup-service-BZoixhVl.js.map
|