@rebasepro/server-postgres 0.20.1-canary.g4d882ca → 0.21.1-canary.g8c5a265
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/README.md +15 -13
- package/dist/PostgresBackendDriver.d.ts +36 -7
- package/dist/auth/services.d.ts +19 -1
- package/dist/backup/backup-cron.d.ts +28 -1
- package/dist/{backup-cli-DSpQyqcG.js → backup-cli-CkjsJEcu.js} +4 -3
- package/dist/backup-cli-CkjsJEcu.js.map +1 -0
- package/dist/{backup-service-DA7a6SUV.js → backup-service-BNLwvxuy.js} +2 -2
- package/dist/{backup-service-DA7a6SUV.js.map → backup-service-BNLwvxuy.js.map} +1 -1
- package/dist/cli.js +7 -7
- package/dist/column-plan-helpers-CpILzHJS.js.map +1 -1
- package/dist/{doctor-D5SrGJ5P.js → doctor-ByFWL_ET.js} +25 -6
- package/dist/doctor-ByFWL_ET.js.map +1 -0
- package/dist/{ensure-collection-policies-CHO0moXQ.js → ensure-collection-policies-CQGHln-y.js} +2 -2
- package/dist/{ensure-collection-policies-CHO0moXQ.js.map → ensure-collection-policies-CQGHln-y.js.map} +1 -1
- package/dist/{ensure-tables-CYMtuuOd.js → ensure-tables-BnEvEJPr.js} +2 -2
- package/dist/ensure-tables-BnEvEJPr.js.map +1 -0
- package/dist/history/HistoryService.d.ts +16 -2
- package/dist/history/ensure-history-table.d.ts +7 -1
- package/dist/index.es.js +1604 -1096
- package/dist/index.es.js.map +1 -1
- package/dist/plan-schema-Hgl62S-w.js.map +1 -1
- package/dist/{rls-bootstrap-sql-BlzsOUtz.js → rls-bootstrap-sql-BHA6jLtj.js} +4 -3
- package/dist/{rls-bootstrap-sql-BlzsOUtz.js.map → rls-bootstrap-sql-BHA6jLtj.js.map} +1 -1
- package/dist/{rls-enforcement-BV12vBwQ.js → rls-enforcement-C6Xk0lA6.js} +20 -20
- package/dist/{rls-enforcement-BV12vBwQ.js.map → rls-enforcement-C6Xk0lA6.js.map} +1 -1
- package/dist/schema/doctor-cli.js +2 -2
- package/dist/services/PersistService.d.ts +11 -0
- package/dist/services/RelationService.d.ts +39 -0
- package/dist/services/RelationWriteService.d.ts +32 -1
- package/dist/services/dataService.d.ts +2 -0
- package/dist/services/junction-writes.d.ts +58 -2
- package/dist/services/write-transaction-scope.d.ts +68 -0
- package/dist/types.d.ts +18 -0
- package/package.json +7 -7
- package/dist/backup-cli-DSpQyqcG.js.map +0 -1
- package/dist/doctor-D5SrGJ5P.js.map +0 -1
- package/dist/ensure-tables-CYMtuuOd.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,8 +9,9 @@ pnpm add @rebasepro/server-postgres
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
This package is ESM-only (`"type": "module"`, no CommonJS build), so it is
|
|
12
|
-
loaded with `import`.
|
|
13
|
-
|
|
12
|
+
loaded with `import`. It needs Node `>=22.22.0` (its `engines` floor), where
|
|
13
|
+
`require()` of it from a CJS file works too: Node has supported `require(esm)`
|
|
14
|
+
since 22.12.
|
|
14
15
|
|
|
15
16
|
### Allow `@ariga/atlas` to run its install script
|
|
16
17
|
|
|
@@ -41,7 +42,7 @@ not installed, installed with its script blocked, and on disk with only the
|
|
|
41
42
|
|
|
42
43
|
## What This Package Does
|
|
43
44
|
|
|
44
|
-
Implements the Rebase `DatabaseAdapter` / `BackendBootstrapper` interfaces for PostgreSQL. It provides connection pooling, a Drizzle-based data driver, Postgres LISTEN/NOTIFY realtime, auth table management,
|
|
45
|
+
Implements the Rebase `DatabaseAdapter` / `BackendBootstrapper` interfaces for PostgreSQL. It provides connection pooling, a Drizzle-based data driver, Postgres LISTEN/NOTIFY realtime, auth table management, entity history, schema generation, branching, read replicas, and WebSocket support. Plug it into `@rebasepro/server` via `createPostgresAdapter()` or `createPostgresBootstrapper()`.
|
|
45
46
|
|
|
46
47
|
## Key Exports
|
|
47
48
|
|
|
@@ -57,8 +58,8 @@ Implements the Rebase `DatabaseAdapter` / `BackendBootstrapper` interfaces for P
|
|
|
57
58
|
| `DatabasePoolManager` | Per-branch/per-tenant dynamic pool management (used with `ADMIN_CONNECTION_STRING`). |
|
|
58
59
|
| `PostgresCollectionRegistry` | Collection → Drizzle table registry with enum and relation tracking. |
|
|
59
60
|
| `BranchService` | Database branching (schema-level isolation). |
|
|
60
|
-
| `
|
|
61
|
-
| `createAuthSchema(schemaName?)` |
|
|
61
|
+
| `generateSchema(collections, options?)` | Generates Drizzle schema code from collection definitions. |
|
|
62
|
+
| `createAuthSchema(schemaName?)` | Drizzle tables for the auth system, in schema `rebase` by default: `users` (with `roles` as a `text[]` column), `refresh_tokens`, `password_reset_tokens`, `user_identities`, `mfa_factors`, `mfa_challenges`, `recovery_codes`, `magic_link_tokens`, `app_config`. |
|
|
62
63
|
|
|
63
64
|
## Quick Start
|
|
64
65
|
|
|
@@ -66,19 +67,20 @@ Implements the Rebase `DatabaseAdapter` / `BackendBootstrapper` interfaces for P
|
|
|
66
67
|
import { createPostgresDatabaseConnection } from "@rebasepro/server-postgres";
|
|
67
68
|
import { createPostgresAdapter } from "@rebasepro/server-postgres";
|
|
68
69
|
import { initializeRebaseBackend } from "@rebasepro/server";
|
|
69
|
-
|
|
70
|
+
// Written by `rebase schema generate`.
|
|
71
|
+
import { enums, relations, tables } from "./schema.generated";
|
|
72
|
+
|
|
73
|
+
const connectionString = process.env.DATABASE_URL;
|
|
74
|
+
if (!connectionString) throw new Error("DATABASE_URL is not set");
|
|
70
75
|
|
|
71
76
|
// Create connection
|
|
72
|
-
const { db, pool } = createPostgresDatabaseConnection(
|
|
73
|
-
process.env.DATABASE_URL,
|
|
74
|
-
schema
|
|
75
|
-
);
|
|
77
|
+
const { db, pool } = createPostgresDatabaseConnection(connectionString);
|
|
76
78
|
|
|
77
79
|
// Create adapter and pass to server
|
|
78
80
|
const database = createPostgresAdapter({
|
|
79
81
|
connection: db,
|
|
80
|
-
connectionString
|
|
81
|
-
schema: { tables
|
|
82
|
+
connectionString,
|
|
83
|
+
schema: { tables, enums, relations },
|
|
82
84
|
});
|
|
83
85
|
|
|
84
86
|
const backend = await initializeRebaseBackend({
|
|
@@ -103,7 +105,7 @@ process.on("SIGTERM", async () => {
|
|
|
103
105
|
| `max` | 20 |
|
|
104
106
|
| `idleTimeoutMillis` | 30,000 |
|
|
105
107
|
| `connectionTimeoutMillis` | 10,000 |
|
|
106
|
-
| `queryTimeout` |
|
|
108
|
+
| `queryTimeout` | 60,000 |
|
|
107
109
|
| `statementTimeout` | 30,000 |
|
|
108
110
|
| `keepAlive` | true |
|
|
109
111
|
|
|
@@ -3,7 +3,7 @@ import { BranchService } from "./services/BranchService.js";
|
|
|
3
3
|
import { RealtimeService } from "./services/realtimeService.js";
|
|
4
4
|
import { DatabasePoolManager } from "./databasePoolManager.js";
|
|
5
5
|
import { DrizzleClient } from "./interfaces.js";
|
|
6
|
-
import { DatabaseAdmin, DataDriver, DeleteProps, CollectionConfig, FetchCollectionProps, FetchOneProps, ListenCollectionProps, ListenOneProps,
|
|
6
|
+
import { DatabaseAdmin, DataDriver, DeleteProps, CollectionConfig, FetchCollectionProps, FetchOneProps, ListenCollectionProps, ListenOneProps, RebaseCallContext, RebaseServerClient, RebaseSdkData, RestFetchService, BatchWriteProps, SaveManyProps, SaveProps, UpdateManyProps, UpdateRelationPivotProps, DeleteManyProps, TableMetadata, User } from "@rebasepro/types";
|
|
7
7
|
import { PostgresCollectionRegistry } from "./collections/PostgresCollectionRegistry.js";
|
|
8
8
|
import { HistoryService } from "./history/HistoryService.js";
|
|
9
9
|
/**
|
|
@@ -15,10 +15,9 @@ import { HistoryService } from "./history/HistoryService.js";
|
|
|
15
15
|
* them. It is the only sanctioned way a statement that named a role runs
|
|
16
16
|
* without it — every other route now refuses.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* variable disagree with the rest.
|
|
18
|
+
* Any spelling of yes, through the platform's one parser. It was an exact
|
|
19
|
+
* `"true"` until that parser existed, deliberately, so that this variable would
|
|
20
|
+
* not be fixed alone and left disagreeing with the rest.
|
|
22
21
|
*/
|
|
23
22
|
export declare function isRoleSwitchingOptedOut(): boolean;
|
|
24
23
|
/**
|
|
@@ -58,7 +57,13 @@ export declare class PostgresBackendDriver implements DataDriver {
|
|
|
58
57
|
branchService?: BranchService;
|
|
59
58
|
user?: User;
|
|
60
59
|
data: RebaseSdkData;
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* The server singleton, attached by `initializeRebaseBackend` after boot —
|
|
62
|
+
* a driver exists before the client does. Typed as what is attached: a
|
|
63
|
+
* `RebaseServerClient` has no `data`, and callbacks read it as
|
|
64
|
+
* `context.client`.
|
|
65
|
+
*/
|
|
66
|
+
client?: RebaseServerClient;
|
|
62
67
|
/**
|
|
63
68
|
* Auto-set to `true` once a `SET LOCAL ROLE` has failed with insufficient
|
|
64
69
|
* privileges, so later statements refuse without spending the round trip
|
|
@@ -131,10 +136,17 @@ export declare class PostgresBackendDriver implements DataDriver {
|
|
|
131
136
|
* suite, because it is the kind of property that is easy to break from a
|
|
132
137
|
* distance and impossible to notice.
|
|
133
138
|
*
|
|
134
|
-
* Previously returned through `as
|
|
139
|
+
* Previously returned through `as RebaseCallContext`, which
|
|
135
140
|
* disabled checking for the whole object and let `driver` — documented in
|
|
136
141
|
* the callbacks guide — sit on the runtime context while absent from the
|
|
137
142
|
* contract. Both are declared now, so this is a plain typed return.
|
|
143
|
+
*
|
|
144
|
+
* `client` went through a narrower cast, `as RebaseCallContext["client"]`,
|
|
145
|
+
* and it lied twice. It said `RebaseClient`, `data` included, about the
|
|
146
|
+
* server singleton, which has no `data` — so `context.client.data` compiled
|
|
147
|
+
* and threw in production. And it dropped the `| undefined` of a client
|
|
148
|
+
* that is attached after construction. The type now leaves `data` off, and
|
|
149
|
+
* a driver that was never given a client refuses by name, at the read.
|
|
138
150
|
*/
|
|
139
151
|
private buildCallContext;
|
|
140
152
|
private resolveCollectionCallbacks;
|
|
@@ -211,6 +223,21 @@ export declare class PostgresBackendDriver implements DataDriver {
|
|
|
211
223
|
* with the last write winning, exactly as separate calls would.
|
|
212
224
|
*/
|
|
213
225
|
private bindToTransaction;
|
|
226
|
+
/**
|
|
227
|
+
* The callback context for work already running inside `tx` on behalf of
|
|
228
|
+
* `user` — for a caller that opened the user-scoped transaction itself.
|
|
229
|
+
*
|
|
230
|
+
* The realtime refetch is that caller: it applies the subscriber's auth
|
|
231
|
+
* context and role switch on its own connection. Its `afterRead` hooks used
|
|
232
|
+
* to get a context assembled by hand, and it was wrong in both directions:
|
|
233
|
+
* `data` was THIS driver's — the base one, on the owner connection, outside
|
|
234
|
+
* that transaction — so a hook reading related rows through `context.data`
|
|
235
|
+
* bypassed RLS on every subscription frame while the REST read of the same
|
|
236
|
+
* rows did not; and `client` and `storageSource` were absent, though the
|
|
237
|
+
* type promises both. This builds the context the REST path builds, bound to
|
|
238
|
+
* the transaction the rows came from.
|
|
239
|
+
*/
|
|
240
|
+
callContextWithin(tx: DrizzleClient, user: User): RebaseCallContext;
|
|
214
241
|
saveMany<M extends Record<string, unknown>>({ path, rows, collection, upsert, onConflict }: SaveManyProps<M>): Promise<Record<string, unknown>[]>;
|
|
215
242
|
/**
|
|
216
243
|
* Update many rows through the same pipeline as {@link save}, in one
|
|
@@ -259,6 +286,7 @@ export declare class PostgresBackendDriver implements DataDriver {
|
|
|
259
286
|
batchWrite<M extends Record<string, unknown>>({ operations }: BatchWriteProps<M>): Promise<(Record<string, unknown> | null)[]>;
|
|
260
287
|
delete<M extends Record<string, unknown>>({ row, collection, hard }: DeleteProps<M>): Promise<void>;
|
|
261
288
|
deleteAll(path: string): Promise<void>;
|
|
289
|
+
updateRelationPivot({ path, targetId, pivot }: UpdateRelationPivotProps): Promise<void>;
|
|
262
290
|
checkUniqueField(path: string, name: string, value: unknown, id?: string, collection?: CollectionConfig): Promise<boolean>;
|
|
263
291
|
count<M extends Record<string, unknown>>({ path, collection, filter, logical, searchString, vectorSearch, withDeleted }: FetchCollectionProps<M>): Promise<number>;
|
|
264
292
|
private getTargetDb;
|
|
@@ -370,6 +398,7 @@ export declare class AuthenticatedPostgresBackendDriver implements DataDriver {
|
|
|
370
398
|
batchWrite<M extends Record<string, unknown>>(props: BatchWriteProps<M>): Promise<(Record<string, unknown> | null)[]>;
|
|
371
399
|
delete<M extends Record<string, unknown>>(props: DeleteProps<M>): Promise<void>;
|
|
372
400
|
deleteAll(path: string): Promise<void>;
|
|
401
|
+
updateRelationPivot(props: UpdateRelationPivotProps): Promise<void>;
|
|
373
402
|
checkUniqueField(path: string, name: string, value: unknown, id?: string, collection?: CollectionConfig): Promise<boolean>;
|
|
374
403
|
count<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;
|
|
375
404
|
}
|
package/dist/auth/services.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
2
|
-
import type
|
|
2
|
+
import { type RebasePgTable } from "../types.js";
|
|
3
3
|
import { UserRepository, TokenRepository, MfaRepository, AuthRepository, UserData, CreateUserData, RoleData, CreateRoleData, RefreshTokenInfo, RefreshTokenSession, PasswordResetTokenInfo, MagicLinkTokenInfo, UserIdentityData, ListUsersOptions, PaginatedUsersResult, MfaFactor, MfaChallengeInfo, RoleData as Role } from "@rebasepro/server";
|
|
4
4
|
export type { Role };
|
|
5
5
|
export interface AuthSchemaTables {
|
|
@@ -133,6 +133,24 @@ export declare class RefreshTokenService {
|
|
|
133
133
|
/** The columns to read back, narrowed to the ones this table has. */
|
|
134
134
|
private selection;
|
|
135
135
|
createToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Build a {@link RefreshTokenInfo} out of a row of {@link selection}.
|
|
138
|
+
*
|
|
139
|
+
* `selection()` is assembled at runtime from the columns this table actually
|
|
140
|
+
* has, so drizzle types the row as an open record and nothing static
|
|
141
|
+
* connects it to the interface. Both call sites used to assert the
|
|
142
|
+
* connection — `row as unknown as RefreshTokenInfo` — which claims every
|
|
143
|
+
* optional field is present and correctly typed on a row where, by
|
|
144
|
+
* construction, some of them were never selected.
|
|
145
|
+
*
|
|
146
|
+
* Constructing it says the true thing instead: the five required fields come
|
|
147
|
+
* from columns `selection()` always includes, and each optional one is
|
|
148
|
+
* copied only when the row carries it. A host application's own
|
|
149
|
+
* `refresh_tokens` table predating session grouping is the case this whole
|
|
150
|
+
* class is shaped around, and it is exactly the case the assertion
|
|
151
|
+
* misdescribed.
|
|
152
|
+
*/
|
|
153
|
+
private static toInfo;
|
|
136
154
|
findByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
|
|
137
155
|
/**
|
|
138
156
|
* Record that a token was rotated away, keeping the row.
|
|
@@ -18,7 +18,11 @@ export interface BackupCronConfig {
|
|
|
18
18
|
retentionDays?: number;
|
|
19
19
|
/** Always keep at least this many recent backups regardless of age. */
|
|
20
20
|
keepMinimum?: number;
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Schemas to exclude from the dump. Defaults to none, the same as
|
|
23
|
+
* `rebase db backup` — see {@link createBackupCron} for why `rebase` in
|
|
24
|
+
* particular must stay in.
|
|
25
|
+
*/
|
|
22
26
|
excludeSchemas?: string[];
|
|
23
27
|
/** Cron job display name. */
|
|
24
28
|
name?: string;
|
|
@@ -49,5 +53,28 @@ export declare function backupCronConfigFromEnv(env: Record<string, string | und
|
|
|
49
53
|
* Create a {@link CronJobDefinition} that dumps the database, uploads the
|
|
50
54
|
* result to the configured destination, and prunes old backups. Object
|
|
51
55
|
* destinations require {@link BackupCronConfig.storage}.
|
|
56
|
+
*
|
|
57
|
+
* The dump excludes nothing unless `excludeSchemas` says otherwise, and that
|
|
58
|
+
* default is not this function's to set: the option goes to `createDump`
|
|
59
|
+
* untouched, so `buildPgDumpArgs` decides for the cron and `rebase db backup`
|
|
60
|
+
* alike. The cron used to carry its own default of `["rebase"]`, meant to
|
|
61
|
+
* leave out Atlas's revision table, and it left out a lot more. `rebase` is
|
|
62
|
+
* where the framework keeps
|
|
63
|
+
* everything that is not a collection: the auth tables (`users`, identities,
|
|
64
|
+
* refresh tokens, MFA factors, recovery codes, `app_config`, `schema_meta`),
|
|
65
|
+
* API keys, record history, the job queue, cron logs, channel history,
|
|
66
|
+
* branches and idempotency keys. It also holds the functions that every
|
|
67
|
+
* generated RLS policy and CDC trigger calls (`rebase.uid()`,
|
|
68
|
+
* `rebase.roles()`, `rebase.rebase_cdc_notify()`).
|
|
69
|
+
*
|
|
70
|
+
* None of that can be left for boot to rebuild. Boot recreates the tables
|
|
71
|
+
* and functions, but never the rows in them. And a dump that has a policy
|
|
72
|
+
* or trigger on a `public` table without the function it calls cannot be
|
|
73
|
+
* restored into an empty database: `pg_restore --exit-on-error` stops at
|
|
74
|
+
* the first such statement, and every collection's generated policies call
|
|
75
|
+
* `rebase.uid()`. So every scheduled backup lost every user account, and
|
|
76
|
+
* could not be restored anyway, while `rebase db backup` took a complete
|
|
77
|
+
* one. The revision table belongs in a backup too: without it, a restored
|
|
78
|
+
* database has tables but no record of the migrations that made them.
|
|
52
79
|
*/
|
|
53
80
|
export declare function createBackupCron(config: BackupCronConfig): CronJobDefinition;
|
|
@@ -2,9 +2,10 @@ import { createRequire as __createRequire } from "module";
|
|
|
2
2
|
__createRequire(import.meta.url);
|
|
3
3
|
import { a as __toESM, t as require___vite_browser_external } from "./__vite-browser-external-BnuHet1e.js";
|
|
4
4
|
import { n as outError, r as outWarn, t as out } from "./cli-output-CNdMql-L.js";
|
|
5
|
-
import { D as parseBackupDestination, P as withDatabaseName, T as globalsFileForDump, h as validateDump, i as createDump, j as resolveConnectionString, k as parseDbNameFromUrl, l as listBackups, m as uploadBackup, n as applyGlobals, o as discardPartialDump, p as restoreDump, s as ensureDatabaseExists, t as BackupToolError, u as preflight } from "./backup-service-
|
|
5
|
+
import { D as parseBackupDestination, P as withDatabaseName, T as globalsFileForDump, h as validateDump, i as createDump, j as resolveConnectionString, k as parseDbNameFromUrl, l as listBackups, m as uploadBackup, n as applyGlobals, o as discardPartialDump, p as restoreDump, s as ensureDatabaseExists, t as BackupToolError, u as preflight } from "./backup-service-BNLwvxuy.js";
|
|
6
6
|
import { t as chalk } from "./source-Br7L7GOI.js";
|
|
7
7
|
import { t as require_arg } from "./arg-Dni7MzLB.js";
|
|
8
|
+
import { parseEnvBoolean } from "@rebasepro/types";
|
|
8
9
|
import fs from "fs";
|
|
9
10
|
import path from "path";
|
|
10
11
|
import os from "os";
|
|
@@ -39,7 +40,7 @@ async function resolveStorageForDestination(dest, env) {
|
|
|
39
40
|
accessKeyId: env.S3_ACCESS_KEY_ID,
|
|
40
41
|
secretAccessKey: env.S3_SECRET_ACCESS_KEY,
|
|
41
42
|
endpoint: env.S3_ENDPOINT,
|
|
42
|
-
forcePathStyle: env.S3_FORCE_PATH_STYLE
|
|
43
|
+
forcePathStyle: parseEnvBoolean(env.S3_FORCE_PATH_STYLE)
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
function requireConnection() {
|
|
@@ -405,4 +406,4 @@ ${chalk.green.bold("Usage")}
|
|
|
405
406
|
//#endregion
|
|
406
407
|
export { backupCommand, backupsCommand, restoreCommand };
|
|
407
408
|
|
|
408
|
-
//# sourceMappingURL=backup-cli-
|
|
409
|
+
//# sourceMappingURL=backup-cli-CkjsJEcu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-cli-CkjsJEcu.js","names":[],"sources":["../src/backup/backup-cli.ts"],"sourcesContent":["/**\n * CLI handlers for `rebase db backup`, `rebase db restore`, and\n * `rebase db backups list`. Kept out of the main `cli.ts` dispatcher so the\n * backup surface stays self-contained.\n */\nimport arg from \"arg\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport readline from \"readline\";\nimport chalk from \"chalk\";\n// Aliased: `out` is already a local in two of the commands below (the `--out`\n// backup destination).\nimport { out as print, outWarn, outError } from \"../cli-output\";\nimport type { StorageController } from \"@rebasepro/server\";\nimport { parseEnvBoolean } from \"@rebasepro/types\";\nimport {\n BackupDestination,\n globalsFileForDump,\n parseBackupDestination,\n parseDbNameFromUrl,\n resolveConnectionString,\n withDatabaseName\n} from \"./pg-tools\";\nimport {\n applyGlobals,\n BackupToolError,\n createDump,\n discardPartialDump,\n ensureDatabaseExists,\n listBackups,\n preflight,\n restoreDump,\n uploadBackup,\n validateDump\n} from \"./backup-service\";\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\n/**\n * Build a StorageController for an object-storage destination from the same\n * `S3_*` env vars the backend uses. Returns `null` for local destinations.\n */\nasync function resolveStorageForDestination(\n dest: BackupDestination,\n env: Record<string, string | undefined>\n): Promise<StorageController | null> {\n if (dest.kind === \"local\") return null;\n if (dest.kind === \"gcs\") {\n const { GCSStorageController } = await import(\"@rebasepro/server\");\n return new GCSStorageController({ type: \"gcs\", bucket: dest.bucket });\n }\n // s3 (also covers R2/MinIO/Hetzner/GCS-interop via S3_ENDPOINT)\n if (!env.S3_ACCESS_KEY_ID || !env.S3_SECRET_ACCESS_KEY) {\n throw new BackupToolError(\n \"S3 destination requires S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY in the environment.\",\n \"Set the same S3_* variables your backend uses for storage.\"\n );\n }\n const { S3StorageController } = await import(\"@rebasepro/server\");\n return new S3StorageController({\n type: \"s3\",\n bucket: dest.bucket,\n region: env.S3_REGION || \"auto\",\n accessKeyId: env.S3_ACCESS_KEY_ID,\n secretAccessKey: env.S3_SECRET_ACCESS_KEY,\n endpoint: env.S3_ENDPOINT,\n // Unset stays unset, so the controller decides from the endpoint the\n // way it does for the runtime's own storage. `=== \"true\"` made it an\n // explicit `false`, and a MinIO backup addressed the bucket as a host.\n forcePathStyle: parseEnvBoolean(env.S3_FORCE_PATH_STYLE)\n });\n}\n\nfunction requireConnection(): string {\n const conn = resolveConnectionString(process.env);\n if (!conn) {\n outError(chalk.red(\"✗ DATABASE_URL is not set. Make sure your .env file is configured.\"));\n process.exit(1);\n }\n return conn;\n}\n\nasync function promptConfirm(question: string): Promise<boolean> {\n // Non-interactive shells (CI, pipes) can't answer — treat as \"no\".\n if (!process.stdin.isTTY) return false;\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer: string = await new Promise((resolve) => rl.question(question, resolve));\n return /^y(es)?$/i.test(answer.trim());\n } finally {\n rl.close();\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// rebase db backup\n// ─────────────────────────────────────────────────────────────────────────\nexport async function backupCommand(rawArgs: string[]): Promise<void> {\n const args = arg(\n {\n \"--out\": String,\n // The same alias `build` and `cloud env pull` carry. `--output` is\n // the canonical spelling in this CLI and this command took only\n // `--out`, so `rebase db backup --output ./backups` wrote to\n // ./backups *and* to the default directory — the flag was ignored\n // and its value became a positional.\n \"--output\": \"--out\",\n \"--exclude-schema\": [String],\n \"--no-owner\": Boolean,\n \"--enable-row-security\": Boolean,\n \"--row-security-role\": String,\n \"-o\": \"--out\"\n },\n { argv: rawArgs.slice(2), permissive: true }\n );\n\n if (args._.includes(\"--help\") || rawArgs.includes(\"--help\")) {\n printBackupHelp();\n return;\n }\n\n const connectionString = requireConnection();\n const dbName = parseDbNameFromUrl(connectionString) ?? \"database\";\n const out = args[\"--out\"] || process.env.BACKUP_DESTINATION || path.join(process.cwd(), \"backups\");\n const dest = parseBackupDestination(out);\n\n print(\"\");\n print(chalk.bold(\" 💾 Rebase DB Backup\"));\n print(chalk.gray(` Database: ${dbName}`));\n print(chalk.gray(` Destination: ${out}`));\n print(\"\");\n\n // Version pre-flight (doctor-style).\n const pf = await preflight(\"pg_dump\", connectionString);\n if (!pf.compatible) {\n outError(chalk.red(` ✗ ${pf.reason}`));\n process.exit(1);\n }\n print(chalk.gray(` Using pg_dump ${pf.toolMajor} against server ${pf.serverMajor}.`));\n\n // Opt-in, and loud. With row security on, pg_dump stops refusing to read\n // rows it cannot see and starts leaving them out — an exit-0 backup that\n // is quietly short. Anyone choosing that should know they chose it.\n const rowSecurity = args[\"--enable-row-security\"]\n ? { uid: \"rebase-db-backup\", roles: [args[\"--row-security-role\"] || \"admin\"] }\n : undefined;\n\n if (rowSecurity) {\n outWarn(\"\");\n outWarn(chalk.yellow(\" ⚠ Dumping with row-level security ON.\"));\n outWarn(chalk.gray(` Reading as roles [${rowSecurity.roles.join(\", \")}], which satisfies the generated`));\n outWarn(chalk.gray(\" `admin_full_access` policy. This backup contains exactly the rows those\"));\n outWarn(chalk.gray(\" policies admit — a table whose policies have no admin rule comes out short,\"));\n outWarn(chalk.gray(\" and pg_dump will not say so. Prefer granting the dumping role BYPASSRLS.\"));\n outWarn(\"\");\n }\n\n try {\n if (dest.kind === \"local\") {\n // Honour an explicit `…/name.dump` path; otherwise treat it as a\n // directory and auto-name the file.\n const explicitFile = dest.path.endsWith(\".dump\");\n const dump = await createDump({\n connectionString,\n dbName,\n outDir: explicitFile ? path.dirname(dest.path) : dest.path,\n fileName: explicitFile ? path.basename(dest.path) : undefined,\n excludeSchemas: args[\"--exclude-schema\"],\n noOwner: args[\"--no-owner\"],\n inheritStdio: true,\n rowSecurity\n });\n await assertDumpValid(dump.localFile);\n print(\"\");\n print(chalk.green(` ✓ Backup written to ${dump.localFile} (${formatBytes(dump.sizeBytes)})`));\n if (dump.globalsFile) {\n print(chalk.gray(` ✓ Roles captured to ${dump.globalsFile} (needed so RLS survives a restore).`));\n }\n } else {\n const storage = await resolveStorageForDestination(dest, process.env);\n const dump = await createDump({\n connectionString,\n dbName,\n excludeSchemas: args[\"--exclude-schema\"],\n noOwner: args[\"--no-owner\"],\n inheritStdio: true,\n rowSecurity\n });\n try {\n await assertDumpValid(dump.localFile);\n const uploaded = await uploadBackup(storage!, dump.localFile, dest);\n print(\"\");\n print(chalk.green(` ✓ Backup uploaded to ${uploaded.storageUrl} (${formatBytes(dump.sizeBytes)})`));\n // Upload the roles sidecar next to the dump so a restore can\n // recreate roles the dump's GRANT/RLS statements depend on.\n if (dump.globalsFile && fs.existsSync(dump.globalsFile)) {\n const globalsUpload = await uploadBackup(storage!, dump.globalsFile, dest);\n print(chalk.gray(` ✓ Roles uploaded to ${globalsUpload.storageUrl} (needed so RLS survives a restore).`));\n }\n print(chalk.gray(\" Ensure this bucket is private — backups may contain secrets and PII.\"));\n } finally {\n if (fs.existsSync(dump.localFile)) fs.unlinkSync(dump.localFile);\n if (dump.globalsFile && fs.existsSync(dump.globalsFile)) fs.unlinkSync(dump.globalsFile);\n }\n }\n print(\"\");\n } catch (err) {\n reportError(err);\n process.exit(1);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// rebase db restore <backup>\n// ─────────────────────────────────────────────────────────────────────────\nexport async function restoreCommand(rawArgs: string[]): Promise<void> {\n const args = arg(\n {\n \"--target-db\": String,\n \"--create-db\": Boolean,\n \"--clean\": Boolean,\n \"--no-owner\": Boolean,\n \"--continue-on-error\": Boolean,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n },\n { argv: rawArgs.slice(2), permissive: true }\n );\n\n const backupArg = args._[0];\n if (!backupArg || rawArgs.includes(\"--help\")) {\n printRestoreHelp();\n if (!backupArg && !rawArgs.includes(\"--help\")) process.exit(1);\n return;\n }\n\n const baseConnection = requireConnection();\n\n // Choose the target connection: an explicit --target-db (or --create-db's\n // implied fresh db) swaps the database name so the live one isn't clobbered.\n const targetDb = args[\"--target-db\"] ?? parseDbNameFromUrl(baseConnection) ?? undefined;\n const targetConnection = args[\"--target-db\"]\n ? withDatabaseName(baseConnection, args[\"--target-db\"])\n : baseConnection;\n\n print(\"\");\n print(chalk.bold(\" ♻️ Rebase DB Restore\"));\n print(chalk.gray(` Source: ${backupArg}`));\n print(chalk.gray(` Target: ${targetDb ?? \"(from DATABASE_URL)\"}`));\n print(\"\");\n\n // Resolve the local file to restore from (download object-storage keys).\n // Also resolve the `.globals.sql` roles sidecar so cluster roles can be\n // recreated before the restore — without them the dump's GRANT/RLS\n // statements fail and RLS is silently lost.\n let localFile: string;\n let globalsSql: string | null = null;\n let cleanupTemp = false;\n try {\n if (/^(s3|gs):\\/\\//.test(backupArg)) {\n const dest = parseBackupDestination(backupArg.replace(/\\/[^/]+$/, \"\"));\n const storage = await resolveStorageForDestination(dest, process.env);\n if (!storage) throw new BackupToolError(\"Could not resolve storage for the given URL.\");\n const key = backupArg.replace(/^(s3|gs):\\/\\/[^/]+\\//, \"\");\n const bucket = backupArg.replace(/^(s3|gs):\\/\\/([^/]+)\\/.*$/, \"$2\");\n const file = await storage.getObject(key, bucket);\n if (!file) throw new BackupToolError(`Backup not found in storage: ${backupArg}`);\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"rebase-restore-\"));\n localFile = path.join(tmpDir, path.basename(key));\n fs.writeFileSync(localFile, Buffer.from(await file.arrayBuffer()));\n cleanupTemp = true;\n const globalsObj = await storage.getObject(globalsFileForDump(key), bucket);\n if (globalsObj) globalsSql = Buffer.from(await globalsObj.arrayBuffer()).toString(\"utf-8\");\n } else {\n localFile = path.resolve(backupArg);\n if (!fs.existsSync(localFile)) {\n outError(chalk.red(` ✗ Backup file not found: ${localFile}`));\n process.exit(1);\n }\n const globalsPath = globalsFileForDump(localFile);\n if (fs.existsSync(globalsPath)) globalsSql = fs.readFileSync(globalsPath, \"utf-8\");\n }\n\n // Version pre-flight. Check against the base connection — the server\n // version is identical for every database, and the target may not\n // exist yet when --create-db is used.\n const pf = await preflight(\"pg_restore\", baseConnection);\n if (!pf.compatible) {\n outError(chalk.red(` ✗ ${pf.reason}`));\n process.exit(1);\n }\n\n // `--create-db` needs a name before anything else can be decided.\n if (args[\"--create-db\"] && !targetDb) {\n outError(chalk.red(\" ✗ --create-db requires a resolvable target database name (use --target-db).\"));\n process.exit(1);\n }\n\n // Destructive-action gate. Restores overwrite data; never run without\n // an explicit yes (interactive confirmation or --yes).\n //\n // Ahead of `--create-db`, not after it. Creating the database first\n // meant an aborted run had already changed the cluster, while printing\n // \"No changes were made\" — and it left an empty database behind that a\n // second, confirmed run then reported as \"already exists\". The gate is\n // now the first thing that can stop the command, so its own message is\n // true whichever way the answer goes.\n if (!args[\"--yes\"]) {\n outWarn(chalk.yellow(\n ` ⚠️ This will restore into \"${targetDb ?? \"the target database\"}\" and may overwrite existing data.`\n ));\n const confirmed = await promptConfirm(chalk.yellow(\" Type 'yes' to continue: \"));\n if (!confirmed) {\n print(chalk.gray(\" Aborted. No changes were made.\"));\n process.exit(1);\n }\n }\n\n // Create the target database when requested.\n if (args[\"--create-db\"]) {\n const created = await ensureDatabaseExists(baseConnection, targetDb!);\n print(chalk.gray(created ? ` ✓ Created database \"${targetDb}\".` : ` • Database \"${targetDb}\" already exists.`));\n }\n\n // Recreate cluster roles before restoring so GRANT/RLS statements in\n // the dump apply. Best-effort and idempotent (see applyGlobals).\n if (globalsSql) {\n print(chalk.gray(\" Recreating cluster roles from the backup's roles sidecar…\"));\n const { applied, skipped } = await applyGlobals(\n targetConnection,\n globalsSql,\n (m) => print(chalk.gray(m))\n );\n print(chalk.gray(` ✓ Roles: ${applied} applied, ${skipped} skipped (already present or not permitted).`));\n } else {\n outWarn(chalk.yellow(\" ⚠️ No roles sidecar (.globals.sql) accompanies this backup.\"));\n outWarn(chalk.yellow(\" If the dump grants to roles that don't exist (e.g. rebase_user), the restore\"));\n outWarn(chalk.yellow(\" will fail — recreate those roles first, or use a backup that includes its globals.\"));\n }\n\n await restoreDump({\n connectionString: targetConnection,\n inputFile: localFile,\n clean: args[\"--clean\"],\n noOwner: args[\"--no-owner\"],\n // Fail loudly by default so a skipped GRANT never leaves RLS off.\n exitOnError: !args[\"--continue-on-error\"],\n inheritStdio: true\n });\n\n print(\"\");\n print(chalk.green(` ✓ Restore completed into \"${targetDb ?? \"the target database\"}\".`));\n print(\"\");\n } catch (err) {\n reportError(err);\n process.exit(1);\n } finally {\n if (cleanupTemp && typeof localFile! === \"string\" && fs.existsSync(localFile!)) {\n fs.rmSync(path.dirname(localFile!), { recursive: true, force: true });\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// rebase db backups list\n// ─────────────────────────────────────────────────────────────────────────\nexport async function backupsCommand(rawArgs: string[]): Promise<void> {\n const action = rawArgs[2];\n if (!action || action === \"--help\") {\n printBackupsHelp();\n return;\n }\n if (action !== \"list\") {\n outError(chalk.red(`Unknown backups action: \"${action}\". Valid: list`));\n process.exit(1);\n }\n\n const args = arg({ \"--out\": String, \"--output\": \"--out\", \"-o\": \"--out\" }, { argv: rawArgs.slice(3), permissive: true });\n const out = args[\"--out\"] || process.env.BACKUP_DESTINATION || path.join(process.cwd(), \"backups\");\n const dest = parseBackupDestination(out);\n\n try {\n const storage = await resolveStorageForDestination(dest, process.env);\n const backups = await listBackups(dest, storage ?? undefined);\n print(\"\");\n if (backups.length === 0) {\n print(chalk.gray(` No backups found at ${out}.`));\n } else {\n print(chalk.bold(` 💾 ${backups.length} backup(s) at ${out}:`));\n print(\"\");\n for (const b of backups) {\n const when = b.createdAt ? b.createdAt.toISOString() : \"unknown date\";\n const name = dest.kind === \"local\" ? path.basename(b.key) : b.key;\n // An empty file is called out rather than listed as a peer of\n // the real ones. Older failures could leave a 0-byte dump here\n // (fixed at the source now), and retention protects the newest\n // by date whatever they contain — so a corpse left in place can\n // hold a `keepMinimum` slot against a backup that matters.\n const empty = b.sizeBytes === 0;\n const size = b.sizeBytes === undefined ? \"\" : ` — ${formatBytes(b.sizeBytes)}`;\n if (empty) {\n print(` ${chalk.red(\"○\")} ${chalk.bold(name)} ${chalk.gray(`— ${when}`)}${chalk.red(\" — EMPTY, not restorable\")}`);\n } else {\n print(` ${chalk.green(\"●\")} ${chalk.bold(name)} ${chalk.gray(`— ${when}${size}`)}`);\n }\n }\n if (backups.some(b => b.sizeBytes === 0)) {\n print(\"\");\n print(chalk.yellow(\" ⚠ Empty files above are leftovers from a failed backup. Delete them:\"));\n print(chalk.gray(\" they count as recent backups for retention but restore nothing.\"));\n }\n }\n print(\"\");\n } catch (err) {\n reportError(err);\n process.exit(1);\n }\n}\n\n/**\n * Verify a freshly written dump; abort the command if it looks corrupt.\n *\n * Discards the artifact on the way out. Refusing to *report* success was never\n * enough on its own: the file stayed on disk, `rebase db backups list` showed\n * it as an ordinary entry, and retention — which ranks by timestamp and never\n * looks at size — would protect it as one of the `keepMinimum` newest while\n * pruning a real backup underneath it. The roles sidecar goes too; the two are\n * uploaded and pruned as a pair, so half a pair is not a backup either.\n */\nasync function assertDumpValid(localFile: string): Promise<void> {\n const check = await validateDump(localFile);\n if (!check.ok) {\n discardPartialDump(globalsFileForDump(localFile));\n discardPartialDump(localFile);\n throw new BackupToolError(\n `The backup failed validation and was discarded: ${check.reason}`,\n \"The dump was corrupt or truncated, so nothing was kept. Investigate before relying on this destination.\"\n );\n }\n}\n\nfunction reportError(err: unknown): void {\n if (err instanceof BackupToolError) {\n outError(chalk.red(` ✗ ${err.message}`));\n if (err.hint) outError(chalk.gray(` ${err.hint}`));\n } else {\n outError(chalk.red(` ✗ ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\nfunction printBackupHelp(): void {\n print(`\n${chalk.bold(\"rebase db backup\")} — Create a database backup (pg_dump, custom format)\n\n${chalk.green.bold(\"Usage\")}\n rebase db backup [--out <path|s3://bucket/prefix>] [options]\n\n${chalk.green.bold(\"Options\")}\n ${chalk.blue(\"--out, -o\")} <dest> Local path or s3://…/gs://… URL (default: ./backups)\n ${chalk.blue(\"--exclude-schema\")} <s> Exclude a schema (repeatable)\n ${chalk.blue(\"--no-owner\")} Omit ownership commands from the dump\n ${chalk.blue(\"--enable-row-security\")} Dump as an admin subject instead of failing on RLS\n ${chalk.red(\"(may produce a partial dump — see below)\")}\n ${chalk.blue(\"--row-security-role\")} <r> Role to read as with the flag above (default: admin)\n\n${chalk.green.bold(\"Row-level security\")}\n On a managed Postgres the dumping role usually owns nothing and has no\n BYPASSRLS, so pg_dump refuses:\n\n ERROR: query would be affected by row-level security policy for table \"...\"\n\n That refusal is the safe behaviour. --enable-row-security replaces it by\n reading as an admin subject: Rebase sets app.uid/app.user_roles so the\n generated admin_full_access policy admits the dump. The dump then contains\n exactly what those policies admit ${chalk.red(\"and no error is raised for what they do not\")} —\n a table whose policies lack an admin rule comes out short, silently.\n\n Granting the dumping role BYPASSRLS is the option that keeps a backup\n meaning \"every row\".\n\n${chalk.green.bold(\"Notes\")}\n Backups may contain secrets and PII. Use private storage destinations and\n enable encryption-at-rest. See docs/backups.md.\n`);\n}\n\nfunction printRestoreHelp(): void {\n print(`\n${chalk.bold(\"rebase db restore\")} — Restore a database from a backup (pg_restore)\n\n${chalk.green.bold(\"Usage\")}\n rebase db restore <backup> [options]\n\n${chalk.green.bold(\"Arguments\")}\n <backup> Local .dump file, or s3://…/gs://… object key\n\n${chalk.green.bold(\"Options\")}\n ${chalk.blue(\"--target-db\")} <name> Restore into this database instead of DATABASE_URL's\n ${chalk.blue(\"--create-db\")} Create the target database first if it doesn't exist\n ${chalk.blue(\"--clean\")} Drop existing objects before recreating them\n ${chalk.blue(\"--no-owner\")} Ignore ownership from the dump\n ${chalk.blue(\"--continue-on-error\")} Log and continue past errors ${chalk.red(\"(may leave RLS un-enforced!)\")}\n ${chalk.blue(\"--yes, -y\")} Skip the interactive confirmation ${chalk.red(\"(destructive!)\")}\n\n${chalk.red.bold(\"Warning\")}\n Restore is destructive and never runs automatically. Without --yes it\n requires an interactive 'yes'. Prefer --create-db/--target-db to restore\n into a fresh database rather than overwriting a live one.\n\n By default the restore aborts on the first error (--exit-on-error) so a\n skipped GRANT never silently leaves RLS un-enforced. Roles are recreated\n from the backup's .globals.sql sidecar first; keep that file next to the\n dump. Use --continue-on-error only when you understand the consequences.\n`);\n}\n\nfunction printBackupsHelp(): void {\n print(`\n${chalk.bold(\"rebase db backups\")} — Manage stored backups\n\n${chalk.green.bold(\"Usage\")}\n rebase db backups list [--out <path|s3://bucket/prefix>]\n rebase db backup list [--out <path|s3://bucket/prefix>] ${chalk.gray(\"(the same thing)\")}\n`);\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
__createRequire(import.meta.url);
|
|
3
3
|
import { r as __exportAll } from "./__vite-browser-external-BnuHet1e.js";
|
|
4
|
-
import { A as execa, j as forLibpq, k as resolveLocalBin } from "./rls-bootstrap-sql-
|
|
4
|
+
import { A as execa, j as forLibpq, k as resolveLocalBin } from "./rls-bootstrap-sql-BHA6jLtj.js";
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import os from "os";
|
|
@@ -712,4 +712,4 @@ async function pruneBackups(dest, options, storage) {
|
|
|
712
712
|
//#endregion
|
|
713
713
|
export { parsePgToolMajor as A, checkToolServerCompatibility as C, parseBackupDestination as D, joinStorageKey as E, serverVersionNumToMajor as M, splitGlobalsStatements as N, parseBackupTimestamp as O, withDatabaseName as P, buildRowSecurityPgOptions as S, globalsFileForDump as T, buildBackupFilename as _, detectToolMajor as a, buildPgRestoreArgs as b, getServerVersionMajor as c, pruneBackups as d, resolvePgBinary as f, selectBackupsToPrune as g, validateDump as h, createDump as i, resolveConnectionString as j, parseDbNameFromUrl 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, buildPgDumpArgs as v, diagnoseRowSecurityDumpFailure as w, buildPgRestoreListArgs as x, buildPgDumpallGlobalsArgs as y };
|
|
714
714
|
|
|
715
|
-
//# sourceMappingURL=backup-service-
|
|
715
|
+
//# sourceMappingURL=backup-service-BNLwvxuy.js.map
|