@rebasepro/types 0.9.0 → 0.9.1-canary.0de22e0
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 +4 -4
- package/dist/controllers/auth.d.ts +6 -0
- package/dist/controllers/client.d.ts +21 -1
- package/dist/controllers/data.d.ts +44 -2
- package/dist/controllers/data_driver.d.ts +45 -3
- package/dist/controllers/email.d.ts +2 -2
- package/dist/controllers/registry.d.ts +5 -5
- package/dist/index.es.js +19 -1
- package/dist/index.es.js.map +1 -1
- package/dist/types/auth_adapter.d.ts +25 -3
- package/dist/types/backend.d.ts +55 -1
- package/dist/types/backup.d.ts +20 -0
- package/dist/types/collections.d.ts +34 -19
- package/dist/types/cron.d.ts +2 -2
- package/dist/types/database_adapter.d.ts +17 -1
- package/dist/types/entity_callbacks.d.ts +3 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/policy.d.ts +48 -2
- package/dist/types/properties.d.ts +13 -0
- package/dist/types/translations.d.ts +5 -1
- package/dist/types/user_management_delegate.d.ts +8 -2
- package/dist/types/websockets.d.ts +77 -0
- package/dist/users/user.d.ts +1 -1
- package/package.json +5 -6
- package/src/controllers/auth.tsx +6 -0
- package/src/controllers/client.ts +22 -2
- package/src/controllers/data.ts +42 -2
- package/src/controllers/data_driver.ts +47 -3
- package/src/controllers/email.ts +2 -2
- package/src/controllers/registry.ts +5 -5
- package/src/types/auth_adapter.ts +25 -3
- package/src/types/backend.ts +59 -1
- package/src/types/backup.ts +26 -0
- package/src/types/collections.ts +35 -19
- package/src/types/cron.ts +2 -2
- package/src/types/database_adapter.ts +15 -1
- package/src/types/entity_callbacks.ts +3 -3
- package/src/types/index.ts +1 -0
- package/src/types/policy.ts +50 -1
- package/src/types/properties.ts +14 -0
- package/src/types/translations.ts +5 -1
- package/src/types/user_management_delegate.ts +8 -2
- package/src/types/websockets.ts +76 -0
- package/src/users/user.ts +1 -1
- package/dist/index.umd.js +0 -591
- package/dist/index.umd.js.map +0 -1
|
@@ -3,6 +3,7 @@ import type { RebaseSdkData } from "./data";
|
|
|
3
3
|
import type { EmailService } from "./email";
|
|
4
4
|
import type { StorageSource } from "./storage";
|
|
5
5
|
import type { CronJobStatus, CronJobLogEntry } from "../types/cron";
|
|
6
|
+
import type { BackupInfo, BackupDestinationKind } from "../types/backup";
|
|
6
7
|
import type { ApiKeysAPI } from "../types/api_keys";
|
|
7
8
|
import type { StorageSourceDefinition } from "../types/storage_source";
|
|
8
9
|
|
|
@@ -142,7 +143,7 @@ export interface AdminAPI {
|
|
|
142
143
|
createUser(data: { email: string; displayName?: string; password?: string; roles?: string[]; metadata?: Record<string, any> }): Promise<{ user: AdminUser }>;
|
|
143
144
|
updateUser(userId: string, data: { email?: string; displayName?: string; password?: string; roles?: string[]; metadata?: Record<string, any> }): Promise<{ user: AdminUser }>;
|
|
144
145
|
deleteUser(userId: string): Promise<{ success: boolean }>;
|
|
145
|
-
resetPassword(userId: string, options?: { password?: string }): Promise<{ user: AdminUser; temporaryPassword?: string; invitationSent?: boolean }>;
|
|
146
|
+
resetPassword(userId: string, options?: { password?: string }): Promise<{ user: AdminUser; temporaryPassword?: string; invitationSent?: boolean; emailDeliveryFailed?: boolean }>;
|
|
146
147
|
listRoles(): Promise<{ roles: Array<{ id: string; name: string }> }>;
|
|
147
148
|
bootstrap(): Promise<{ success: boolean; message: string; user: { uid: string; roles: string[] } }>;
|
|
148
149
|
}
|
|
@@ -161,6 +162,19 @@ export interface CronAPI {
|
|
|
161
162
|
toggleJob(jobId: string, enabled: boolean): Promise<{ job: CronJobStatus }>;
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
// ─── Backups API ─────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Client-side database-backup management interface.
|
|
169
|
+
* @group Backups
|
|
170
|
+
*/
|
|
171
|
+
export interface BackupsAPI {
|
|
172
|
+
/** List available backups at the configured destination, newest first. */
|
|
173
|
+
list(): Promise<{ backups: BackupInfo[]; destinationKind: BackupDestinationKind; configured: boolean }>;
|
|
174
|
+
/** Fetch a backup's bytes for download (authenticated). */
|
|
175
|
+
download(key: string): Promise<Blob>;
|
|
176
|
+
}
|
|
177
|
+
|
|
164
178
|
// ─── Functions API ───────────────────────────────────────────────────────────
|
|
165
179
|
|
|
166
180
|
/**
|
|
@@ -294,6 +308,9 @@ export interface RebaseClient<DB = unknown> {
|
|
|
294
308
|
/** Cron job management API */
|
|
295
309
|
cron?: CronAPI;
|
|
296
310
|
|
|
311
|
+
/** Database backup management API */
|
|
312
|
+
backups?: BackupsAPI;
|
|
313
|
+
|
|
297
314
|
/** Custom backend functions API */
|
|
298
315
|
functions?: FunctionsAPI;
|
|
299
316
|
|
|
@@ -333,7 +350,7 @@ export interface RebaseClient<DB = unknown> {
|
|
|
333
350
|
|
|
334
351
|
/**
|
|
335
352
|
* The server-side Rebase surface — the shape of the `rebase` singleton exported
|
|
336
|
-
* from `@rebasepro/server
|
|
353
|
+
* from `@rebasepro/server`.
|
|
337
354
|
*
|
|
338
355
|
* Narrows {@link RebaseClient} to the guarantees that always hold on the server:
|
|
339
356
|
* the admin-scoped {@link dataAsAdmin} accessor, raw {@link sql}, and the
|
|
@@ -409,6 +426,9 @@ export interface RebaseBrowserClient<DB = unknown> {
|
|
|
409
426
|
/** Cron job management API */
|
|
410
427
|
cron?: CronAPI;
|
|
411
428
|
|
|
429
|
+
/** Database backup management API */
|
|
430
|
+
backups?: BackupsAPI;
|
|
431
|
+
|
|
412
432
|
/** Custom backend functions API */
|
|
413
433
|
functions?: FunctionsAPI;
|
|
414
434
|
|
package/src/controllers/data.ts
CHANGED
|
@@ -161,6 +161,14 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
|
|
|
161
161
|
*/
|
|
162
162
|
create(data: Partial<EntityValues<M>>, id?: string | number): Promise<Entity<M>>;
|
|
163
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Create many records in a single transaction.
|
|
166
|
+
*
|
|
167
|
+
* See {@link SDKCollectionClient.createMany}. Optional: not every driver can
|
|
168
|
+
* write in bulk, and callers should fall back to `create` per record.
|
|
169
|
+
*/
|
|
170
|
+
createMany?(data: Partial<EntityValues<M>>[], options?: { upsert?: boolean }): Promise<Entity<M>[]>;
|
|
171
|
+
|
|
164
172
|
/**
|
|
165
173
|
* Update an existing record by ID.
|
|
166
174
|
* @returns The updated entity
|
|
@@ -294,11 +302,43 @@ export interface SDKCollectionClient<
|
|
|
294
302
|
/**
|
|
295
303
|
* Create a new record.
|
|
296
304
|
* @param data The record data to create (the collection's `Insert` shape).
|
|
297
|
-
* @param id Optional specific
|
|
305
|
+
* @param id Optional specific id, sent as an `id` column. This is for tables
|
|
306
|
+
* whose key *is* `id`: the value goes in as that column. For a table keyed
|
|
307
|
+
* on anything else (a `sku`, a composite key), there is no `id` column to
|
|
308
|
+
* receive it — put the key in `data` instead, where it belongs among the
|
|
309
|
+
* columns.
|
|
298
310
|
* @returns The created row
|
|
299
311
|
*/
|
|
300
312
|
create(data: I, id?: string | number): Promise<M>;
|
|
301
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Write many records in a single request and a single transaction.
|
|
316
|
+
*
|
|
317
|
+
* Built for imports and ETL, where one call per row means one HTTP round
|
|
318
|
+
* trip and one transaction per row. Every record still runs the normal
|
|
319
|
+
* pipeline — callbacks, relations, row-level security — and the batch is
|
|
320
|
+
* all-or-nothing: if any record is rejected, none of them land and the
|
|
321
|
+
* error names the offending index.
|
|
322
|
+
*
|
|
323
|
+
* A record carrying its primary key updates that row; one without inserts.
|
|
324
|
+
* With `{ upsert: true }` each record is written as INSERT ... ON CONFLICT
|
|
325
|
+
* DO UPDATE on the primary key instead, which is what makes a re-runnable
|
|
326
|
+
* import idempotent.
|
|
327
|
+
*
|
|
328
|
+
* Batches are capped server-side (1000 rows by default) because one batch
|
|
329
|
+
* holds its locks for the whole transaction — chunk larger jobs.
|
|
330
|
+
*
|
|
331
|
+
* @returns The written rows, in the order given.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* for (const chunk of chunks(rows, 1000)) {
|
|
336
|
+
* await client.data.products.createMany(chunk, { upsert: true });
|
|
337
|
+
* }
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
createMany(data: I[], options?: { upsert?: boolean }): Promise<M[]>;
|
|
341
|
+
|
|
302
342
|
/**
|
|
303
343
|
* Update an existing record by ID.
|
|
304
344
|
* @param data The fields to update (the collection's `Update` shape).
|
|
@@ -386,7 +426,7 @@ export type RebaseData<DB = unknown> = {
|
|
|
386
426
|
* - The frontend SDK client (`client.data.products.find()`)
|
|
387
427
|
* - Backend framework callbacks & scripts (`context.data.products.find()`)
|
|
388
428
|
*
|
|
389
|
-
* Every accessor returns flat rows (
|
|
429
|
+
* Every accessor returns flat rows (the table's columns) via
|
|
390
430
|
* {@link SDKCollectionClient} — access fields directly (`row.title`), never
|
|
391
431
|
* `row.values.title`. The admin CMS uses {@link RebaseData} (Entity) instead.
|
|
392
432
|
*
|
|
@@ -77,6 +77,31 @@ export interface SaveProps<M extends Record<string, unknown> = Record<string, un
|
|
|
77
77
|
previousValues?: Partial<EntityValues<M>>;
|
|
78
78
|
collection?: CollectionConfig<M>;
|
|
79
79
|
status: EntityStatus;
|
|
80
|
+
/**
|
|
81
|
+
* Write the row with INSERT ... ON CONFLICT DO UPDATE on the primary key
|
|
82
|
+
* instead of choosing between insert and update up front.
|
|
83
|
+
*
|
|
84
|
+
* One statement, so it does not lose the race a read-then-write can, and it
|
|
85
|
+
* succeeds whether or not the row is already there — what a re-runnable
|
|
86
|
+
* import needs. Requires every primary key column to be present; without
|
|
87
|
+
* them there is no conflict target and the row is inserted normally.
|
|
88
|
+
*/
|
|
89
|
+
upsert?: boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
export interface SaveManyProps<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
96
|
+
path: string;
|
|
97
|
+
/**
|
|
98
|
+
* The rows to write. A row carrying its primary key updates (or, with
|
|
99
|
+
* `upsert`, inserts-or-updates) that row; one without inserts.
|
|
100
|
+
*/
|
|
101
|
+
rows: Partial<EntityValues<M>>[];
|
|
102
|
+
collection?: CollectionConfig<M>;
|
|
103
|
+
/** Apply every row as INSERT ... ON CONFLICT DO UPDATE. See {@link SaveProps.upsert}. */
|
|
104
|
+
upsert?: boolean;
|
|
80
105
|
}
|
|
81
106
|
|
|
82
107
|
/**
|
|
@@ -154,6 +179,20 @@ export interface DataDriver {
|
|
|
154
179
|
*/
|
|
155
180
|
save<M extends Record<string, unknown> = Record<string, unknown>>(props: SaveProps<M>): Promise<Record<string, unknown>>;
|
|
156
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Save many rows as one unit of work.
|
|
184
|
+
*
|
|
185
|
+
* Every row runs the same pipeline as {@link save} — callbacks, relations
|
|
186
|
+
* and row-level security all still apply — but they share a single
|
|
187
|
+
* transaction, so the batch either lands whole or not at all. That, and the
|
|
188
|
+
* single round trip, is what makes importing tens of thousands of rows
|
|
189
|
+
* viable without dropping to raw SQL.
|
|
190
|
+
*
|
|
191
|
+
* Optional: drivers that cannot do this leave it undefined and callers fall
|
|
192
|
+
* back to `save` per row.
|
|
193
|
+
*/
|
|
194
|
+
saveMany?<M extends Record<string, unknown> = Record<string, unknown>>(props: SaveManyProps<M>): Promise<Record<string, unknown>[]>;
|
|
195
|
+
|
|
157
196
|
/**
|
|
158
197
|
* Delete a entity
|
|
159
198
|
* @param props
|
|
@@ -252,9 +291,14 @@ export interface DataDriver {
|
|
|
252
291
|
* REST-optimised fetch service exposed by drivers that support
|
|
253
292
|
* eager-loading of relations via `include`.
|
|
254
293
|
*
|
|
255
|
-
* The methods return flattened rows
|
|
256
|
-
*
|
|
257
|
-
*
|
|
294
|
+
* The methods return flattened rows — exactly the table's columns, under their
|
|
295
|
+
* own names and with the types the database returned — and included relations
|
|
296
|
+
* inlined as plain nested rows. This is the shape served to app developers
|
|
297
|
+
* through the REST API / SDK client.
|
|
298
|
+
*
|
|
299
|
+
* No synthesized `id`: identity is a primary key, which may be named anything
|
|
300
|
+
* and span several columns, so an address is derived by whoever needs one (see
|
|
301
|
+
* `buildCompositeId`) rather than written into the row on top of the data.
|
|
258
302
|
*
|
|
259
303
|
* @group DataDriver
|
|
260
304
|
*/
|
package/src/controllers/email.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Email service types — portable interface shared by RebaseClient and server
|
|
2
|
+
* Email service types — portable interface shared by RebaseClient and server.
|
|
3
3
|
*
|
|
4
|
-
* The concrete SMTP implementation lives in `@rebasepro/server
|
|
4
|
+
* The concrete SMTP implementation lives in `@rebasepro/server/email`.
|
|
5
5
|
* This file provides only the consumer-facing contract so that it can be
|
|
6
6
|
* referenced from `RebaseClient` without dragging in nodemailer.
|
|
7
7
|
*/
|
|
@@ -7,7 +7,7 @@ import type { AppView, NavigationGroupMapping } from "./navigation";
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Options to enable the built-in collection editor.
|
|
10
|
-
* When provided to `<
|
|
10
|
+
* When provided to `<RebaseAdmin>`, the editor is auto-wired as a native feature.
|
|
11
11
|
*/
|
|
12
12
|
export interface CollectionEditorOptions {
|
|
13
13
|
/**
|
|
@@ -21,7 +21,7 @@ export interface CollectionEditorOptions {
|
|
|
21
21
|
pathSuggestions?: string[];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export interface
|
|
24
|
+
export interface RebaseAdminConfig<EC extends CollectionConfig = CollectionConfig> {
|
|
25
25
|
collections?: EC[] | CollectionConfigsBuilder<EC>;
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -68,7 +68,7 @@ export interface RebaseCMSConfig<EC extends CollectionConfig = CollectionConfig>
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export interface RebaseStudioConfig {
|
|
71
|
-
tools?: ("sql" | "js" | "rls" | "schema" | "storage" | "cron" | "schema-visualizer" | "branches" | "api" | "logs" | "api-keys")[];
|
|
71
|
+
tools?: ("sql" | "js" | "rls" | "schema" | "storage" | "cron" | "schema-visualizer" | "branches" | "backups" | "api" | "logs" | "api-keys")[];
|
|
72
72
|
homePage?: ReactNode;
|
|
73
73
|
devViews?: AppView[];
|
|
74
74
|
}
|
|
@@ -79,12 +79,12 @@ export interface RebaseAuthConfig {
|
|
|
79
79
|
|
|
80
80
|
export interface RebaseRegistryController {
|
|
81
81
|
// Current state
|
|
82
|
-
cmsConfig:
|
|
82
|
+
cmsConfig: RebaseAdminConfig | null;
|
|
83
83
|
studioConfig: RebaseStudioConfig | null;
|
|
84
84
|
authConfig: RebaseAuthConfig | null;
|
|
85
85
|
|
|
86
86
|
// Registration functions
|
|
87
|
-
registerCMS: (config:
|
|
87
|
+
registerCMS: (config: RebaseAdminConfig) => void;
|
|
88
88
|
unregisterCMS: () => void;
|
|
89
89
|
|
|
90
90
|
registerStudio: (config: RebaseStudioConfig) => void;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @example Custom auth
|
|
19
19
|
* ```ts
|
|
20
|
-
* import { createCustomAuthAdapter } from "@rebasepro/server
|
|
20
|
+
* import { createCustomAuthAdapter } from "@rebasepro/server";
|
|
21
21
|
*
|
|
22
22
|
* initializeRebaseBackend({
|
|
23
23
|
* auth: createCustomAuthAdapter({
|
|
@@ -85,8 +85,25 @@ export interface AuthAdapterCapabilities {
|
|
|
85
85
|
emailPasswordLogin: boolean;
|
|
86
86
|
/** Supports new user registration. */
|
|
87
87
|
registration: boolean;
|
|
88
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Supports the end-user password reset flow (emailing a reset link).
|
|
90
|
+
*
|
|
91
|
+
* This is about *self-service* reset, so it is typically tied to whether an
|
|
92
|
+
* email service is configured. It says nothing about whether an admin can
|
|
93
|
+
* reset someone else's password — see `adminPasswordReset`.
|
|
94
|
+
*/
|
|
89
95
|
passwordReset: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Whether the adapter exposes `POST /admin/users/:userId/reset-password`,
|
|
98
|
+
* letting an admin reset another user's password.
|
|
99
|
+
*
|
|
100
|
+
* Independent of `passwordReset`: the built-in adapter supports this even
|
|
101
|
+
* with no email service configured (it returns a one-time temporary
|
|
102
|
+
* password instead of sending a link). Adapters that mount their own admin
|
|
103
|
+
* routes must set this to `true` only once that route actually exists —
|
|
104
|
+
* the admin UI hides the "Reset Password" action when it is `false`.
|
|
105
|
+
*/
|
|
106
|
+
adminPasswordReset: boolean;
|
|
90
107
|
/** Supports session listing/revocation. */
|
|
91
108
|
sessionManagement: boolean;
|
|
92
109
|
/** Supports profile updates (display name, photo). */
|
|
@@ -218,6 +235,11 @@ export interface UserCreationFinalizeResult {
|
|
|
218
235
|
temporaryPassword?: string;
|
|
219
236
|
/** Whether an invitation email was sent. */
|
|
220
237
|
invitationSent: boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Whether an email service was configured but delivery failed, causing the
|
|
240
|
+
* fallback to `temporaryPassword`. Absent when no email service is configured.
|
|
241
|
+
*/
|
|
242
|
+
emailDeliveryFailed?: boolean;
|
|
221
243
|
}
|
|
222
244
|
|
|
223
245
|
// ─── Auth Response Transform ─────────────────────────────────────────────────
|
|
@@ -298,7 +320,7 @@ export interface AuthAdapter {
|
|
|
298
320
|
/**
|
|
299
321
|
* Verify an incoming request and extract the authenticated user.
|
|
300
322
|
*
|
|
301
|
-
* This replaces the hardcoded JWT verification in server
|
|
323
|
+
* This replaces the hardcoded JWT verification in server's middleware.
|
|
302
324
|
* Each adapter implements its own token verification strategy:
|
|
303
325
|
* - Built-in: verify Rebase JWT
|
|
304
326
|
* - Clerk: call Clerk's `verifyToken()`
|
package/src/types/backend.ts
CHANGED
|
@@ -245,6 +245,42 @@ export interface SingleSubscriptionConfig {
|
|
|
245
245
|
id: string | number;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Opt-in retention for one set of broadcast channels.
|
|
250
|
+
*
|
|
251
|
+
* Retention is configured on the server and nowhere else. A channel is created
|
|
252
|
+
* by whoever names it, so letting a client ask for its own history depth would
|
|
253
|
+
* let any visitor commit the backend to unbounded storage; and presence-only or
|
|
254
|
+
* notification-only channels — the overwhelming majority — must not pay for a
|
|
255
|
+
* feature they never use. With no rules configured nothing is written, no table
|
|
256
|
+
* is created, and broadcast behaves exactly as it did before history existed.
|
|
257
|
+
*/
|
|
258
|
+
export interface ChannelRetentionRule {
|
|
259
|
+
/**
|
|
260
|
+
* Channel name to match. Either exact (`"doc:42"`) or a trailing-`*` prefix
|
|
261
|
+
* (`"doc:*"`). Deliberately not a full glob or RegExp: this decides what
|
|
262
|
+
* gets written to disk, and a rule whose blast radius is not obvious at a
|
|
263
|
+
* glance is the wrong shape for that.
|
|
264
|
+
*/
|
|
265
|
+
match: string;
|
|
266
|
+
/** Keep at most this many of the most recent messages per channel. */
|
|
267
|
+
limit?: number;
|
|
268
|
+
/**
|
|
269
|
+
* Keep messages for at most this long. Accepts a millisecond count or a
|
|
270
|
+
* short duration string (`"30s"`, `"15m"`, `"24h"`, `"7d"`).
|
|
271
|
+
*/
|
|
272
|
+
ttl?: number | string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Server-side realtime options. */
|
|
276
|
+
export interface RealtimeChannelsConfig {
|
|
277
|
+
/**
|
|
278
|
+
* Retention rules, most specific first — the first match wins. Omitted or
|
|
279
|
+
* empty means no channel retains anything.
|
|
280
|
+
*/
|
|
281
|
+
channels?: ChannelRetentionRule[];
|
|
282
|
+
}
|
|
283
|
+
|
|
248
284
|
/**
|
|
249
285
|
* Abstract realtime provider interface.
|
|
250
286
|
* Handles real-time subscriptions and notifications for entity changes.
|
|
@@ -380,10 +416,24 @@ export interface SQLAdmin {
|
|
|
380
416
|
fetchAvailableDatabases?(): Promise<string[]>;
|
|
381
417
|
|
|
382
418
|
/**
|
|
383
|
-
* Fetch the available database roles.
|
|
419
|
+
* Fetch the available *native PostgreSQL* database roles (from `pg_roles`).
|
|
420
|
+
*
|
|
421
|
+
* These are connection-level roles — what the SQL editor can `SET ROLE` to,
|
|
422
|
+
* and what `SecurityRule.pgRoles` targets. They are NOT application roles;
|
|
423
|
+
* for those use {@link fetchApplicationRoles}.
|
|
384
424
|
*/
|
|
385
425
|
fetchAvailableRoles?(): Promise<string[]>;
|
|
386
426
|
|
|
427
|
+
/**
|
|
428
|
+
* Fetch the *application-level* roles in use in this project.
|
|
429
|
+
*
|
|
430
|
+
* These are the strings stored on the users table's `roles` column and
|
|
431
|
+
* exposed to policies as `auth.roles()` — what `SecurityRule.roles`
|
|
432
|
+
* matches against. Distinct from {@link fetchAvailableRoles}; the two are
|
|
433
|
+
* not interchangeable.
|
|
434
|
+
*/
|
|
435
|
+
fetchApplicationRoles?(): Promise<string[]>;
|
|
436
|
+
|
|
387
437
|
/**
|
|
388
438
|
* Fetch the current database name.
|
|
389
439
|
*/
|
|
@@ -736,6 +786,14 @@ export interface InitializedDriver {
|
|
|
736
786
|
/** A collection registry to register schema / tables into. */
|
|
737
787
|
collectionRegistry?: CollectionRegistryInterface;
|
|
738
788
|
|
|
789
|
+
/**
|
|
790
|
+
* Collections the driver derived from the live database schema.
|
|
791
|
+
*
|
|
792
|
+
* Set by drivers that introspect in `baas` mode; the server serves these
|
|
793
|
+
* instead of collections loaded from config files.
|
|
794
|
+
*/
|
|
795
|
+
collections?: import("./collections").CollectionConfig[];
|
|
796
|
+
|
|
739
797
|
/** The underlying database connection (for lifecycle management). */
|
|
740
798
|
connection?: DatabaseConnection;
|
|
741
799
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup type definitions shared across server, client, and studio.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Where a backup lives — a local path or an object-storage bucket. */
|
|
6
|
+
export type BackupDestinationKind = "local" | "s3" | "gcs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A single backup as surfaced by the admin API / Studio Backups panel.
|
|
10
|
+
*/
|
|
11
|
+
export interface BackupInfo {
|
|
12
|
+
/** Storage key (object storage) or absolute file path (local). */
|
|
13
|
+
key: string;
|
|
14
|
+
|
|
15
|
+
/** Display name — the file's basename. */
|
|
16
|
+
name: string;
|
|
17
|
+
|
|
18
|
+
/** Size in bytes, when known. */
|
|
19
|
+
sizeBytes?: number;
|
|
20
|
+
|
|
21
|
+
/** ISO timestamp the backup was created, when recoverable. */
|
|
22
|
+
createdAt?: string;
|
|
23
|
+
|
|
24
|
+
/** The kind of destination this backup was read from. */
|
|
25
|
+
destinationKind: BackupDestinationKind;
|
|
26
|
+
}
|
package/src/types/collections.ts
CHANGED
|
@@ -179,24 +179,23 @@ export interface BaseCollectionConfig<M extends Record<string, unknown> = Record
|
|
|
179
179
|
auth?: boolean | AuthCollectionConfig;
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
|
-
* Opt out of the framework's default Row Level Security policies
|
|
183
|
-
* authentication collections.
|
|
182
|
+
* Opt out of the framework's default Row Level Security policies.
|
|
184
183
|
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* `admin` role
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
184
|
+
* The schema generator automatically injects, for every collection, a
|
|
185
|
+
* baseline SELECT policy granting the trusted server context and the
|
|
186
|
+
* `admin` role read access (reads run under a restricted role, so RLS
|
|
187
|
+
* default-denies without it). For auth collections it additionally injects
|
|
188
|
+
* a self-read policy (`id = auth.uid()`) and an admin-only write gate
|
|
189
|
+
* (INSERT/UPDATE/DELETE require the `admin` role or the trusted server
|
|
190
|
+
* context), making privileged columns such as `roles` safe by default.
|
|
192
191
|
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
192
|
+
* Author-defined `securityRules` are permissive and broaden access on top
|
|
193
|
+
* of these defaults. Set this flag to `true` to remove the defaults
|
|
195
194
|
* entirely and take full responsibility for the collection's RLS.
|
|
196
195
|
*
|
|
197
196
|
* @default false
|
|
198
197
|
*/
|
|
199
|
-
|
|
198
|
+
disableDefaultPolicies?: boolean;
|
|
200
199
|
|
|
201
200
|
|
|
202
201
|
/**
|
|
@@ -383,6 +382,18 @@ export interface BaseCollectionConfig<M extends Record<string, unknown> = Record
|
|
|
383
382
|
*/
|
|
384
383
|
history?: boolean;
|
|
385
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Whether a write naming a field this collection does not declare is
|
|
387
|
+
* rejected with a 400. Defaults to `true`.
|
|
388
|
+
*
|
|
389
|
+
* Set to `false` to let unknown keys through to the database, which is what
|
|
390
|
+
* happened before this existed: a typo reached the INSERT and came back as
|
|
391
|
+
* a Postgres error about a column, or — where a column really does exist
|
|
392
|
+
* that the config never declared, populated by a trigger or a default —
|
|
393
|
+
* quietly worked. The second case is the reason for the escape hatch.
|
|
394
|
+
*/
|
|
395
|
+
strictWrites?: boolean;
|
|
396
|
+
|
|
386
397
|
/**
|
|
387
398
|
* Should local changes be backed up in local storage, to prevent data loss on
|
|
388
399
|
* accidental navigations.
|
|
@@ -1060,9 +1071,14 @@ export interface SecurityRuleBase {
|
|
|
1060
1071
|
* **Shortcut.** Restrict this rule to users that have one of these
|
|
1061
1072
|
* application-level roles.
|
|
1062
1073
|
*
|
|
1063
|
-
* **Important:** These are NOT native PostgreSQL database roles
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1074
|
+
* **Important:** These are NOT native PostgreSQL database roles — names
|
|
1075
|
+
* like `public`, `anon` or `authenticated` belong to {@link pgRoles} and
|
|
1076
|
+
* produce a condition no user can satisfy if used here. These are
|
|
1077
|
+
* application roles managed by Rebase, stored as an inline `roles TEXT[]`
|
|
1078
|
+
* column on the users table, and injected into each transaction as
|
|
1079
|
+
* `app.user_roles` — which `auth.roles()` reads.
|
|
1080
|
+
*
|
|
1081
|
+
* There is no roles registry: a role exists once it is assigned to a user.
|
|
1066
1082
|
*
|
|
1067
1083
|
* Generates a safe array-overlap condition — the user passes if they hold
|
|
1068
1084
|
* *any* of the listed roles:
|
|
@@ -1094,10 +1110,10 @@ export interface SecurityRuleBase {
|
|
|
1094
1110
|
* every database connection). This is correct for most setups where
|
|
1095
1111
|
* a single database role is used for all connections.
|
|
1096
1112
|
*
|
|
1097
|
-
* **Important:** These are NOT the same as the application-level
|
|
1098
|
-
* (admin, editor, viewer, etc.) — those are enforced in the
|
|
1099
|
-
* CHECK clauses via `auth.roles()`. This field controls the
|
|
1100
|
-
* `TO` clause in `CREATE POLICY ... TO role_name`.
|
|
1113
|
+
* **Important:** These are NOT the same as the application-level
|
|
1114
|
+
* {@link roles} (admin, editor, viewer, etc.) — those are enforced in the
|
|
1115
|
+
* USING/WITH CHECK clauses via `auth.roles()`. This field controls the
|
|
1116
|
+
* PostgreSQL `TO` clause in `CREATE POLICY ... TO role_name`.
|
|
1101
1117
|
*
|
|
1102
1118
|
* Use this if you have dedicated PostgreSQL roles (e.g. `app_read`,
|
|
1103
1119
|
* `app_write`) and want policies to target specific ones.
|
package/src/types/cron.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { RebaseClient } from "../controllers/client";
|
|
|
4
4
|
* Cron Job type definitions for Rebase.
|
|
5
5
|
*
|
|
6
6
|
* These types define the shape of cron job definitions, their runtime
|
|
7
|
-
* status, and execution log entries — used across server
|
|
7
|
+
* status, and execution log entries — used across server, client,
|
|
8
8
|
* and studio packages.
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -62,7 +62,7 @@ export interface CronJobContext {
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* The server-side {@link RebaseClient}. This is the **same singleton**
|
|
65
|
-
* exposed as `rebase` (imported from `@rebasepro/server
|
|
65
|
+
* exposed as `rebase` (imported from `@rebasepro/server`) and as
|
|
66
66
|
* `context` in collection callbacks — it is only named `client` here.
|
|
67
67
|
*
|
|
68
68
|
* Its data plane (`client.data`) runs with **admin privileges and bypasses
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
12
|
-
* import { createPostgresAdapter } from "@rebasepro/server-
|
|
12
|
+
* import { createPostgresAdapter } from "@rebasepro/server-postgres";
|
|
13
13
|
*
|
|
14
14
|
* initializeRebaseBackend({
|
|
15
15
|
* database: createPostgresAdapter({ connection: db, schema }),
|
|
@@ -118,4 +118,18 @@ export interface DatabaseAdapterInitConfig {
|
|
|
118
118
|
collections: CollectionConfig[];
|
|
119
119
|
/** The shared collection registry to register into. */
|
|
120
120
|
collectionRegistry: CollectionRegistryInterface;
|
|
121
|
+
/**
|
|
122
|
+
* How the server is being run — see `RebaseBackendConfig.mode`.
|
|
123
|
+
*
|
|
124
|
+
* In `"baas"` mode `collections` is empty by design: a driver that can
|
|
125
|
+
* describe its own schema should introspect the database and report the
|
|
126
|
+
* collections it found back on `InitializedDriver.collections`. Drivers
|
|
127
|
+
* that cannot introspect may ignore this.
|
|
128
|
+
*/
|
|
129
|
+
mode?: "cms" | "baas";
|
|
130
|
+
/**
|
|
131
|
+
* `baas`-mode options — see `RebaseBackendConfig.baas`. Drivers that
|
|
132
|
+
* introspect should honour `unprotectedTables`.
|
|
133
|
+
*/
|
|
134
|
+
baas?: { unprotectedTables?: "exclude" | "serve" };
|
|
121
135
|
}
|
|
@@ -91,7 +91,7 @@ export interface AfterReadProps<M extends Record<string, unknown> = Record<strin
|
|
|
91
91
|
path: string;
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Fetched row (flat —
|
|
94
|
+
* Fetched row (flat — the table's columns)
|
|
95
95
|
*/
|
|
96
96
|
row: Record<string, unknown>
|
|
97
97
|
|
|
@@ -185,7 +185,7 @@ export interface BeforeDeleteProps<M extends Record<string, unknown> = Record<st
|
|
|
185
185
|
id: string | number;
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
|
-
* Deleted row (flat —
|
|
188
|
+
* Deleted row (flat — the table's columns)
|
|
189
189
|
*/
|
|
190
190
|
row: Record<string, unknown>;
|
|
191
191
|
|
|
@@ -217,7 +217,7 @@ export interface AfterDeleteProps<M extends Record<string, unknown> = Record<str
|
|
|
217
217
|
id: string | number;
|
|
218
218
|
|
|
219
219
|
/**
|
|
220
|
-
* Deleted row (flat —
|
|
220
|
+
* Deleted row (flat — the table's columns)
|
|
221
221
|
*/
|
|
222
222
|
row: Record<string, unknown>;
|
|
223
223
|
|
package/src/types/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from "./entity_views";
|
|
|
26
26
|
export * from "./data_source";
|
|
27
27
|
export * from "./storage_source";
|
|
28
28
|
export * from "./cron";
|
|
29
|
+
export * from "./backup";
|
|
29
30
|
export * from "./component_ref";
|
|
30
31
|
export * from "./auth_adapter";
|
|
31
32
|
export * from "./database_adapter";
|