@rebasepro/server-postgres 0.17.3-canary.gdd23447 → 0.18.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/LICENSE +0 -1
- package/README.md +31 -0
- package/dist/backup-argv.d.ts +19 -0
- package/dist/branch-argv.d.ts +28 -0
- package/dist/branch-prune.d.ts +77 -0
- package/dist/cli-collections-path.d.ts +31 -0
- package/dist/cli-errors.d.ts +123 -0
- package/dist/cli-flags.d.ts +101 -0
- package/dist/cli-helpers.d.ts +94 -10
- package/dist/collection-index-C7LopMyX.js +247 -0
- package/dist/collection-index-C7LopMyX.js.map +1 -0
- package/dist/databasePoolManager.d.ts +27 -0
- package/dist/{ensure-collection-policies-UCqgv_8c.js → ensure-collection-policies-CagOzEPS.js} +6 -6
- package/dist/{ensure-collection-policies-UCqgv_8c.js.map → ensure-collection-policies-CagOzEPS.js.map} +1 -1
- package/dist/{ensure-collection-tables-DgVixhX3.js → ensure-collection-tables-DbAhrjnG.js} +614 -52
- package/dist/ensure-collection-tables-DbAhrjnG.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.es.js +19307 -3059
- package/dist/index.es.js.map +1 -1
- package/dist/{rls-enforcement-DvAbL9YJ.js → rls-enforcement-ClJoTboT.js} +53 -189
- package/dist/rls-enforcement-ClJoTboT.js.map +1 -0
- package/dist/schema/column-type-drift.d.ts +79 -0
- package/dist/schema/doctor.d.ts +42 -0
- package/dist/schema/ensure-collection-tables.d.ts +90 -0
- package/dist/schema/generate-next-step.d.ts +30 -0
- package/dist/schema/generate-postgres-ddl-logic.d.ts +28 -0
- package/dist/schema/generated-schema-staleness.d.ts +37 -0
- package/dist/schema/introspect-db-queries.d.ts +34 -0
- package/dist/security/rls-enforcement.d.ts +63 -2
- package/dist/services/BranchService.d.ts +86 -1
- package/dist/services/collection-helpers.d.ts +1 -1
- package/dist/services/realtimeService.d.ts +30 -2
- package/dist/services/row-pipeline.d.ts +12 -1
- package/dist/utils/pg-error-utils.d.ts +3 -1
- package/dist/utils/pg-numeric-number-patch.d.ts +31 -0
- package/package.json +32 -27
- package/dist/backup-service-DCk7KhhL.js +0 -9044
- package/dist/backup-service-DCk7KhhL.js.map +0 -1
- package/dist/collection-index-BRUg10H5.js +0 -5690
- package/dist/collection-index-BRUg10H5.js.map +0 -1
- package/dist/connection-GOKU3Hu5.js +0 -277
- package/dist/connection-GOKU3Hu5.js.map +0 -1
- package/dist/ensure-collection-tables-DgVixhX3.js.map +0 -1
- package/dist/rls-bootstrap-sql-B5C9LoJ6.js +0 -244
- package/dist/rls-bootstrap-sql-B5C9LoJ6.js.map +0 -1
- package/dist/rls-enforcement-DvAbL9YJ.js.map +0 -1
- package/dist/src-DiB5RP2Z.js +0 -541
- package/dist/src-DiB5RP2Z.js.map +0 -1
- package/dist/websocket-BZ4H5wUz.js +0 -8198
- package/dist/websocket-BZ4H5wUz.js.map +0 -1
- package/src/PostgresAdapter.ts +0 -91
- package/src/PostgresBackendDriver.ts +0 -1857
- package/src/PostgresBootstrapper.ts +0 -1157
- package/src/auth/ensure-tables.ts +0 -896
- package/src/auth/schema-version.ts +0 -260
- package/src/auth/services.ts +0 -1610
- package/src/backup/backup-cli.ts +0 -520
- package/src/backup/backup-cron.ts +0 -212
- package/src/backup/backup-logic.ts +0 -93
- package/src/backup/backup-service.ts +0 -485
- package/src/backup/index.ts +0 -12
- package/src/backup/pg-tools.ts +0 -403
- package/src/backup/retention.ts +0 -86
- package/src/cli-errors.ts +0 -265
- package/src/cli-helpers.ts +0 -569
- package/src/cli-output.ts +0 -43
- package/src/cli.ts +0 -1339
- package/src/collections/PostgresCollectionRegistry.ts +0 -108
- package/src/collections/buildRegistry.ts +0 -68
- package/src/collections/validate-relations.ts +0 -402
- package/src/connection.ts +0 -333
- package/src/data-transformer.ts +0 -845
- package/src/databasePoolManager.ts +0 -95
- package/src/history/HistoryService.ts +0 -254
- package/src/history/ensure-history-table.ts +0 -53
- package/src/index.ts +0 -19
- package/src/interfaces.ts +0 -60
- package/src/module-dir.ts +0 -7
- package/src/schema/atlas-argv.ts +0 -94
- package/src/schema/auth-schema.ts +0 -298
- package/src/schema/auth-users-columns.ts +0 -131
- package/src/schema/carved-out-migration.ts +0 -404
- package/src/schema/classify-change.ts +0 -436
- package/src/schema/collection-index.ts +0 -427
- package/src/schema/collections-schema-version.ts +0 -103
- package/src/schema/destructive-sql.ts +0 -94
- package/src/schema/doctor-cli.ts +0 -66
- package/src/schema/doctor-policy-checks.ts +0 -105
- package/src/schema/doctor.ts +0 -837
- package/src/schema/drizzle-ddl.ts +0 -33
- package/src/schema/dynamic-tables.test.ts +0 -302
- package/src/schema/dynamic-tables.ts +0 -293
- package/src/schema/ensure-collection-policies.ts +0 -198
- package/src/schema/ensure-collection-tables.test.ts +0 -518
- package/src/schema/ensure-collection-tables.ts +0 -1267
- package/src/schema/generate-drizzle-schema-logic.ts +0 -957
- package/src/schema/generate-drizzle-schema.ts +0 -143
- package/src/schema/generate-postgres-ddl-logic.ts +0 -1339
- package/src/schema/generate-postgres-ddl.ts +0 -180
- package/src/schema/generate-schema-commit.ts +0 -267
- package/src/schema/generated-schema-staleness.ts +0 -284
- package/src/schema/introspect-db-constraints.ts +0 -385
- package/src/schema/introspect-db-inference.ts +0 -255
- package/src/schema/introspect-db-logic.ts +0 -1387
- package/src/schema/introspect-db-naming.ts +0 -15
- package/src/schema/introspect-db-project.ts +0 -78
- package/src/schema/introspect-db-queries.ts +0 -326
- package/src/schema/introspect-db-structure.ts +0 -670
- package/src/schema/introspect-db-types.ts +0 -56
- package/src/schema/introspect-db.ts +0 -257
- package/src/schema/introspect-runtime.test.ts +0 -260
- package/src/schema/introspect-runtime.ts +0 -327
- package/src/schema/non-sql-collections.test.ts +0 -131
- package/src/schema/rls-bootstrap-sql.ts +0 -288
- package/src/schema/search-column.ts +0 -643
- package/src/schema/test-schema.ts +0 -11
- package/src/schema/vector-index.ts +0 -491
- package/src/security/anonymous-grants.test.ts +0 -73
- package/src/security/policy-drift.test.ts +0 -435
- package/src/security/policy-drift.ts +0 -473
- package/src/security/rls-enforcement.ts +0 -505
- package/src/services/BranchService.ts +0 -326
- package/src/services/FetchService.ts +0 -2115
- package/src/services/PersistService.ts +0 -557
- package/src/services/RelationService.ts +0 -978
- package/src/services/RelationWriteService.ts +0 -653
- package/src/services/cdc/CdcListener.ts +0 -103
- package/src/services/cdc/junction-tables.ts +0 -91
- package/src/services/cdc/trigger-cdc.ts +0 -173
- package/src/services/channel-bus/ChannelBus.ts +0 -44
- package/src/services/channel-bus/PostgresChannelBus.ts +0 -299
- package/src/services/channel-bus/index.ts +0 -114
- package/src/services/channel-history.ts +0 -424
- package/src/services/channel-presence.ts +0 -185
- package/src/services/collection-helpers.ts +0 -420
- package/src/services/dataService.ts +0 -256
- package/src/services/index.ts +0 -14
- package/src/services/junction-writes.ts +0 -295
- package/src/services/nested-path.ts +0 -145
- package/src/services/pg-notify-listener.ts +0 -151
- package/src/services/realtimeService.ts +0 -2545
- package/src/services/row-pipeline.ts +0 -240
- package/src/services/write-denial.ts +0 -55
- package/src/types.ts +0 -4
- package/src/utils/connection-string.ts +0 -58
- package/src/utils/drizzle-conditions.ts +0 -2743
- package/src/utils/pg-array-null-patch.ts +0 -42
- package/src/utils/pg-error-utils.ts +0 -391
- package/src/websocket.ts +0 -855
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scheduled backups, wired into the server cron system.
|
|
3
|
-
*
|
|
4
|
-
* A backend enables nightly (or custom-schedule) backups by dropping a cron
|
|
5
|
-
* file that default-exports {@link createBackupCron}. The heavy lifting —
|
|
6
|
-
* dump, upload, prune — reuses the same primitives as the CLI so behaviour
|
|
7
|
-
* is identical between a manual `rebase db backup` and an automated run.
|
|
8
|
-
*/
|
|
9
|
-
import fs from "fs";
|
|
10
|
-
import type { CronJobDefinition } from "@rebasepro/types";
|
|
11
|
-
import type { StorageController } from "@rebasepro/server";
|
|
12
|
-
import {
|
|
13
|
-
BackupDestination,
|
|
14
|
-
parseBackupDestination,
|
|
15
|
-
parseDbNameFromUrl,
|
|
16
|
-
resolveConnectionString
|
|
17
|
-
} from "./pg-tools";
|
|
18
|
-
// NOTE: `./backup-service` pulls in `execa` (ESM-only). It is imported
|
|
19
|
-
// lazily inside the handler so the pure `backupCronConfigFromEnv` parser can
|
|
20
|
-
// be unit-tested under CommonJS without loading it.
|
|
21
|
-
|
|
22
|
-
export interface BackupCronConfig {
|
|
23
|
-
/** Cron expression, e.g. `"0 3 * * *"` for 03:00 daily. */
|
|
24
|
-
schedule: string;
|
|
25
|
-
/** Postgres connection string. Defaults to `DATABASE_URL`. */
|
|
26
|
-
connectionString: string;
|
|
27
|
-
/** Where backups are written: a local path or an `s3://` / `gs://` URL. */
|
|
28
|
-
destination: BackupDestination;
|
|
29
|
-
/**
|
|
30
|
-
* Storage controller used for `s3`/`gcs` destinations. Reuse the one the
|
|
31
|
-
* backend already configured (S3/GCS/Local StorageController). Not needed
|
|
32
|
-
* for local destinations.
|
|
33
|
-
*/
|
|
34
|
-
storage?: StorageController;
|
|
35
|
-
/** Delete backups older than this many days. `0` disables pruning. */
|
|
36
|
-
retentionDays?: number;
|
|
37
|
-
/** Always keep at least this many recent backups regardless of age. */
|
|
38
|
-
keepMinimum?: number;
|
|
39
|
-
/** Schemas to exclude from the dump (defaults to Atlas revision schema). */
|
|
40
|
-
excludeSchemas?: string[];
|
|
41
|
-
/** Cron job display name. */
|
|
42
|
-
name?: string;
|
|
43
|
-
/** Whether the job is enabled. */
|
|
44
|
-
enabled?: boolean;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface EnvResolution {
|
|
48
|
-
/** Resolved config, present when a schedule is configured. */
|
|
49
|
-
config?: Omit<BackupCronConfig, "storage">;
|
|
50
|
-
/** True when `BACKUP_SCHEDULE` is unset — the cron should be a no-op. */
|
|
51
|
-
disabled?: boolean;
|
|
52
|
-
/** Human-readable reason the config could not be built. */
|
|
53
|
-
error?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Build backup-cron config purely from environment variables.
|
|
58
|
-
* Recognised keys:
|
|
59
|
-
* - `BACKUP_SCHEDULE` cron expression (required to enable)
|
|
60
|
-
* - `BACKUP_DESTINATION` local path or `s3://` / `gs://` URL (required)
|
|
61
|
-
* - `BACKUP_RETENTION_DAYS` integer days (optional)
|
|
62
|
-
* - `BACKUP_KEEP_MINIMUM` integer count (optional)
|
|
63
|
-
* - `DATABASE_URL` connection string
|
|
64
|
-
*
|
|
65
|
-
* Pure and side-effect free so it can be unit-tested without a database.
|
|
66
|
-
*/
|
|
67
|
-
export function backupCronConfigFromEnv(env: Record<string, string | undefined>): EnvResolution {
|
|
68
|
-
const schedule = env.BACKUP_SCHEDULE?.trim();
|
|
69
|
-
if (!schedule) {
|
|
70
|
-
return { disabled: true };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const connectionString = resolveConnectionString(env);
|
|
74
|
-
if (!connectionString) {
|
|
75
|
-
return { error: "BACKUP_SCHEDULE is set but DATABASE_URL is not configured." };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const destinationRaw = env.BACKUP_DESTINATION?.trim();
|
|
79
|
-
if (!destinationRaw) {
|
|
80
|
-
return { error: "BACKUP_SCHEDULE is set but BACKUP_DESTINATION is not configured." };
|
|
81
|
-
}
|
|
82
|
-
const destination = parseBackupDestination(destinationRaw);
|
|
83
|
-
|
|
84
|
-
const retentionDays = parseOptionalInt(env.BACKUP_RETENTION_DAYS);
|
|
85
|
-
if (retentionDays === "invalid") {
|
|
86
|
-
return { error: `BACKUP_RETENTION_DAYS must be an integer, got "${env.BACKUP_RETENTION_DAYS}".` };
|
|
87
|
-
}
|
|
88
|
-
const keepMinimum = parseOptionalInt(env.BACKUP_KEEP_MINIMUM);
|
|
89
|
-
if (keepMinimum === "invalid") {
|
|
90
|
-
return { error: `BACKUP_KEEP_MINIMUM must be an integer, got "${env.BACKUP_KEEP_MINIMUM}".` };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
config: {
|
|
95
|
-
schedule,
|
|
96
|
-
connectionString,
|
|
97
|
-
destination,
|
|
98
|
-
retentionDays: retentionDays ?? undefined,
|
|
99
|
-
keepMinimum: keepMinimum ?? undefined
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function parseOptionalInt(value: string | undefined): number | null | "invalid" {
|
|
105
|
-
if (value === undefined || value.trim() === "") return null;
|
|
106
|
-
const n = Number(value);
|
|
107
|
-
if (!Number.isInteger(n) || n < 0) return "invalid";
|
|
108
|
-
return n;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Create a {@link CronJobDefinition} that dumps the database, uploads the
|
|
113
|
-
* result to the configured destination, and prunes old backups. Object
|
|
114
|
-
* destinations require {@link BackupCronConfig.storage}.
|
|
115
|
-
*/
|
|
116
|
-
export function createBackupCron(config: BackupCronConfig): CronJobDefinition {
|
|
117
|
-
const dbName = parseDbNameFromUrl(config.connectionString) ?? "database";
|
|
118
|
-
const excludeSchemas = config.excludeSchemas ?? ["rebase"];
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
name: config.name ?? "Scheduled database backup",
|
|
122
|
-
schedule: config.schedule,
|
|
123
|
-
description: "Dumps the Postgres database and uploads it to the configured backup destination.",
|
|
124
|
-
enabled: config.enabled ?? true,
|
|
125
|
-
// Backups of a large database can take a while; allow up to an hour.
|
|
126
|
-
timeoutSeconds: 3600,
|
|
127
|
-
async handler({ log }) {
|
|
128
|
-
const { createDump, pruneBackups, uploadBackup, validateDump } = await import("./backup-service");
|
|
129
|
-
const { destination } = config;
|
|
130
|
-
|
|
131
|
-
if (destination.kind !== "local" && !config.storage) {
|
|
132
|
-
throw new Error(
|
|
133
|
-
`Backup destination is ${destination.kind} but no storage controller was provided. ` +
|
|
134
|
-
"Pass the backend's configured StorageController to createBackupCron({ storage })."
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
log(`Starting backup of "${dbName}"…`);
|
|
139
|
-
const outDir = destination.kind === "local" ? destination.path : undefined;
|
|
140
|
-
const dump = await createDump({
|
|
141
|
-
connectionString: config.connectionString,
|
|
142
|
-
dbName,
|
|
143
|
-
outDir,
|
|
144
|
-
excludeSchemas
|
|
145
|
-
});
|
|
146
|
-
log(`Dump created: ${dump.fileName} (${formatBytes(dump.sizeBytes)})`);
|
|
147
|
-
|
|
148
|
-
// Validate BEFORE pruning: a corrupt-but-exit-0 dump must never be
|
|
149
|
-
// the reason the last good backup gets deleted.
|
|
150
|
-
const check = await validateDump(dump.localFile);
|
|
151
|
-
if (!check.ok) {
|
|
152
|
-
// Clean up the bad temp file for object destinations.
|
|
153
|
-
if (destination.kind !== "local" && fs.existsSync(dump.localFile)) {
|
|
154
|
-
fs.unlinkSync(dump.localFile);
|
|
155
|
-
}
|
|
156
|
-
if (dump.globalsFile && destination.kind !== "local" && fs.existsSync(dump.globalsFile)) {
|
|
157
|
-
fs.unlinkSync(dump.globalsFile);
|
|
158
|
-
}
|
|
159
|
-
throw new Error(`New backup failed validation — skipping upload and pruning to protect existing backups. ${check.reason}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
let storedKey = dump.localFile;
|
|
163
|
-
try {
|
|
164
|
-
if (destination.kind !== "local") {
|
|
165
|
-
const uploaded = await uploadBackup(config.storage!, dump.localFile, destination);
|
|
166
|
-
storedKey = uploaded.storageUrl;
|
|
167
|
-
log(`Uploaded to ${uploaded.storageUrl}`);
|
|
168
|
-
// Upload the roles sidecar so a restore can recreate the
|
|
169
|
-
// roles the dump's GRANT/RLS statements depend on.
|
|
170
|
-
if (dump.globalsFile && fs.existsSync(dump.globalsFile)) {
|
|
171
|
-
const g = await uploadBackup(config.storage!, dump.globalsFile, destination);
|
|
172
|
-
log(`Uploaded roles sidecar to ${g.storageUrl}`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
} finally {
|
|
176
|
-
// For object-storage destinations the local dump was a temp
|
|
177
|
-
// file — remove it once uploaded (or on failure).
|
|
178
|
-
if (destination.kind !== "local" && fs.existsSync(dump.localFile)) {
|
|
179
|
-
fs.unlinkSync(dump.localFile);
|
|
180
|
-
}
|
|
181
|
-
if (dump.globalsFile && destination.kind !== "local" && fs.existsSync(dump.globalsFile)) {
|
|
182
|
-
fs.unlinkSync(dump.globalsFile);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
let pruned: string[] = [];
|
|
187
|
-
if (config.retentionDays && config.retentionDays > 0) {
|
|
188
|
-
pruned = await pruneBackups(
|
|
189
|
-
destination,
|
|
190
|
-
{ retentionDays: config.retentionDays, keepMinimum: config.keepMinimum },
|
|
191
|
-
config.storage
|
|
192
|
-
);
|
|
193
|
-
if (pruned.length > 0) {
|
|
194
|
-
log(`Pruned ${pruned.length} backup(s) older than ${config.retentionDays} day(s).`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
backup: storedKey,
|
|
200
|
-
sizeBytes: dump.sizeBytes,
|
|
201
|
-
pruned: pruned.length
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function formatBytes(bytes: number): string {
|
|
208
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
209
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
210
|
-
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
211
|
-
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
212
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure-ish orchestration for the backup/restore paths, kept free of `execa`
|
|
3
|
-
* and `pg` value imports so it can be unit-tested under jest (the impure
|
|
4
|
-
* edges — spawning processes, opening connections — live in
|
|
5
|
-
* `backup-service.ts`, which is vitest/runtime only).
|
|
6
|
-
*
|
|
7
|
-
* The functions here take their side-effecting dependency as an argument
|
|
8
|
-
* (a statement runner, an object deleter) so tests can inject fakes.
|
|
9
|
-
*/
|
|
10
|
-
import { globalsFileForDump, splitGlobalsStatements } from "./pg-tools";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Replay a `pg_dumpall --globals-only` script one statement at a time,
|
|
14
|
-
* tolerating per-statement failures. On a same-cluster restore the roles
|
|
15
|
-
* usually already exist (`CREATE ROLE` → "already exists") and on a managed
|
|
16
|
-
* provider an `ALTER ROLE <superuser>` may be refused; neither should abort
|
|
17
|
-
* recreation of the roles that *are* missing. Returns how many statements
|
|
18
|
-
* applied vs were skipped.
|
|
19
|
-
*
|
|
20
|
-
* `runStatement` executes one SQL statement and rejects on error.
|
|
21
|
-
*/
|
|
22
|
-
export async function applyGlobalsWith(
|
|
23
|
-
runStatement: (sql: string) => Promise<void>,
|
|
24
|
-
globalsSql: string,
|
|
25
|
-
log: (message: string) => void = () => {}
|
|
26
|
-
): Promise<{ applied: number; skipped: number }> {
|
|
27
|
-
let applied = 0;
|
|
28
|
-
let skipped = 0;
|
|
29
|
-
for (const statement of splitGlobalsStatements(globalsSql)) {
|
|
30
|
-
try {
|
|
31
|
-
await runStatement(statement);
|
|
32
|
-
applied++;
|
|
33
|
-
} catch (err) {
|
|
34
|
-
skipped++;
|
|
35
|
-
const firstLine = statement.split("\n")[0].slice(0, 80);
|
|
36
|
-
log(` • Skipped global: ${firstLine} (${err instanceof Error ? err.message : String(err)})`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return { applied, skipped };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Delete each pruned dump together with its `.globals.sql` roles sidecar, so
|
|
44
|
-
* pruning never orphans the roles file. The sidecar is best-effort — older
|
|
45
|
-
* backups predate it, so a missing-sidecar failure is swallowed while a
|
|
46
|
-
* failure deleting the dump itself propagates.
|
|
47
|
-
*
|
|
48
|
-
* `deleteObject` removes one key and rejects if it cannot (e.g. not found).
|
|
49
|
-
*/
|
|
50
|
-
export async function pruneWith(
|
|
51
|
-
keys: string[],
|
|
52
|
-
deleteObject: (key: string) => Promise<void>
|
|
53
|
-
): Promise<void> {
|
|
54
|
-
for (const key of keys) {
|
|
55
|
-
await deleteObject(key);
|
|
56
|
-
try {
|
|
57
|
-
await deleteObject(globalsFileForDump(key));
|
|
58
|
-
} catch {
|
|
59
|
-
// Sidecar may not exist for older backups — ignore.
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Remove a dump artifact abandoned by a failed tool run.
|
|
66
|
-
*
|
|
67
|
-
* `pg_dump` creates its `--file=` target before it finishes connecting, so any
|
|
68
|
-
* failure — a URL libpq rejects, a dropped connection, a full disk — leaves a
|
|
69
|
-
* 0-byte file behind. That corpse is not inert: `rebase db backups list` used
|
|
70
|
-
* to show it as an ordinary entry, and `selectBackupsToPrune` ranks by
|
|
71
|
-
* timestamp alone, so it occupies a protected `keepMinimum` slot and can push
|
|
72
|
-
* a real backup out of retention.
|
|
73
|
-
*
|
|
74
|
-
* Best-effort on purpose: the caller is already throwing, and a failed unlink
|
|
75
|
-
* must not replace the real diagnosis with an ENOENT/EPERM from the cleanup.
|
|
76
|
-
*
|
|
77
|
-
* Lives here rather than in `backup-service.ts` for the reason at the top of
|
|
78
|
-
* this file — that module's top-level `execa` import makes it unloadable under
|
|
79
|
-
* jest, so anything placed there cannot be unit-tested.
|
|
80
|
-
*
|
|
81
|
-
* `remove` deletes one file and throws if it cannot; `exists` reports presence.
|
|
82
|
-
*/
|
|
83
|
-
export function discardPartialDumpWith(
|
|
84
|
-
exists: (file: string) => boolean,
|
|
85
|
-
remove: (file: string) => void,
|
|
86
|
-
file: string
|
|
87
|
-
): void {
|
|
88
|
-
try {
|
|
89
|
-
if (exists(file)) remove(file);
|
|
90
|
-
} catch {
|
|
91
|
-
// Ignored: see above.
|
|
92
|
-
}
|
|
93
|
-
}
|