@rebasepro/types 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/client.d.ts +61 -17
- package/dist/controllers/collection_registry.d.ts +17 -0
- package/dist/controllers/data.d.ts +161 -49
- package/dist/controllers/data_driver.d.ts +10 -0
- package/dist/controllers/storage.d.ts +132 -13
- package/dist/errors.d.ts +15 -1
- package/dist/index.es.js +1094 -37
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +1 -1
- package/dist/types/api_keys.d.ts +68 -36
- package/dist/types/auth_adapter.d.ts +99 -1
- package/dist/types/backend.d.ts +222 -3
- package/dist/types/backup.d.ts +83 -0
- package/dist/types/collection_patch.d.ts +74 -0
- package/dist/types/collections.d.ts +23 -0
- package/dist/types/cron.d.ts +44 -5
- package/dist/types/database_adapter.d.ts +6 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/postgres_introspection.d.ts +10 -0
- package/dist/types/project_manifest.d.ts +65 -1
- package/dist/types/properties.d.ts +11 -0
- package/dist/types/schema_editing.d.ts +40 -14
- package/dist/types/scopes.d.ts +272 -0
- package/dist/types/security_rules.d.ts +28 -1
- package/dist/types/storage_authorize.d.ts +5 -1
- package/dist/users/user.d.ts +7 -0
- package/package.json +2 -2
|
@@ -49,7 +49,7 @@ export type AdminCollectionKey = typeof ADMIN_COLLECTION_KEYS[number];
|
|
|
49
49
|
*
|
|
50
50
|
* @group Models
|
|
51
51
|
*/
|
|
52
|
-
export declare const ADMIN_PROPERTY_KEYS: readonly ["canAddElements", "clearable", "columnWidth", "customProps", "disabled", "expanded", "Field", "Filter", "filterOperators", "fixedFilter", "format", "hideFromCollection", "includeEntityLink", "includeId", "markdown", "minimalistView", "multiline", "Preview", "previewAsTag", "previewProperties", "readOnly", "renderInForm", "sortable", "span", "spreadChildren", "urlPreview", "widget"];
|
|
52
|
+
export declare const ADMIN_PROPERTY_KEYS: readonly ["canAddElements", "clearable", "columnWidth", "customProps", "disabled", "expanded", "Field", "filledByServer", "Filter", "filterOperators", "fixedFilter", "format", "hideFromCollection", "includeEntityLink", "includeId", "markdown", "minimalistView", "multiline", "Preview", "previewAsTag", "previewProperties", "readOnly", "renderInForm", "sortable", "span", "spreadChildren", "urlPreview", "widget"];
|
|
53
53
|
/** A key of a property's `admin` block. @group Models */
|
|
54
54
|
export type AdminPropertyKey = typeof ADMIN_PROPERTY_KEYS[number];
|
|
55
55
|
/**
|
package/dist/types/api_keys.d.ts
CHANGED
|
@@ -1,49 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* API keys — long-lived bearer credentials for scripts, CI, agents and
|
|
3
|
+
* third-party integrations.
|
|
4
4
|
*
|
|
5
|
-
* The wire contract lives here because all three sides need it
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* The wire contract lives here because all three sides need it:
|
|
6
|
+
* `@rebasepro/server` implements the routes, `@rebasepro/client` calls them,
|
|
7
|
+
* and {@link ApiKeysAPI} types the SDK surface. The database row itself
|
|
8
|
+
* (which carries `key_hash`) stays in the server package: nothing off the
|
|
9
|
+
* server may see it.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
* server package: nothing off the server may see it.
|
|
11
|
+
* What a key may do is a list of scopes — see `scopes.ts`.
|
|
12
12
|
*/
|
|
13
|
+
import type { ScopeSummary } from "./scopes.js";
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
* operations.
|
|
15
|
+
* Who a key acts as.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* - `"service"` — the project's own machine identity, `api-key:<id>`. It is no
|
|
18
|
+
* person: it runs as the RLS roles it was given (`service` always, plus any
|
|
19
|
+
* in {@link ApiKeyMasked.roles}). Managed by holders of `keys:write`.
|
|
20
|
+
* - `"personal"` — its owner. It runs as the owner's account, with the owner's
|
|
21
|
+
* roles as they are *now*, and can never hold a scope the owner does not.
|
|
22
|
+
* Managed by the owner, when the app enables `auth.personalKeys`.
|
|
21
23
|
*
|
|
22
24
|
* @group Models
|
|
23
25
|
*/
|
|
24
|
-
export
|
|
25
|
-
/** Collection slug, `"functions"`/`"functions/<name>"`, or `"*"` for everything. */
|
|
26
|
-
collection: string;
|
|
27
|
-
/** Allowed operations on the collection. */
|
|
28
|
-
operations: ("read" | "write" | "delete")[];
|
|
29
|
-
}
|
|
26
|
+
export type ApiKeyKind = "service" | "personal";
|
|
30
27
|
/**
|
|
31
|
-
* An API key with the secret
|
|
28
|
+
* An API key with the secret masked — what list / get / update return.
|
|
32
29
|
* @group Models
|
|
33
30
|
*/
|
|
34
31
|
export interface ApiKeyMasked {
|
|
35
32
|
id: string;
|
|
36
33
|
name: string;
|
|
34
|
+
kind: ApiKeyKind;
|
|
37
35
|
/** First 12 characters of the plaintext key, for display only. */
|
|
38
36
|
key_prefix: string;
|
|
39
|
-
permissions: ApiKeyPermission[];
|
|
40
37
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
* What the key may do, as `resource:action[:target]` scope strings —
|
|
39
|
+
* `data:read:posts`, `functions:invoke`, `logs:read`.
|
|
40
|
+
*/
|
|
41
|
+
scopes: string[];
|
|
42
|
+
/**
|
|
43
|
+
* The RLS roles a service key runs as, beside `service`. `["admin"]` reads
|
|
44
|
+
* every row through the default admin policies. Always empty on a personal
|
|
45
|
+
* key, which runs as its owner's live roles.
|
|
45
46
|
*/
|
|
46
|
-
|
|
47
|
+
roles: string[];
|
|
48
|
+
/** The account a personal key acts as. Null on a service key. */
|
|
49
|
+
owner_uid: string | null;
|
|
47
50
|
/**
|
|
48
51
|
* Requests per 15-minute window. `null` means "no per-key override" — the
|
|
49
52
|
* data rate limiter then applies its default API-key limit (1000/window
|
|
@@ -67,32 +70,44 @@ export interface ApiKeyWithSecret extends ApiKeyMasked {
|
|
|
67
70
|
key: string;
|
|
68
71
|
}
|
|
69
72
|
/**
|
|
70
|
-
* Payload for creating a
|
|
73
|
+
* Payload for creating a service key.
|
|
71
74
|
* @group Models
|
|
72
75
|
*/
|
|
73
76
|
export interface CreateApiKeyRequest {
|
|
74
77
|
name: string;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
admin
|
|
78
|
+
/** At least one. `keys:*` is refused, and so is any scope the creator does not hold. */
|
|
79
|
+
scopes: string[];
|
|
80
|
+
/** RLS roles beside `service`. A creator may only give roles they hold, unless they are an admin. */
|
|
81
|
+
roles?: string[];
|
|
78
82
|
/** Requests per 15-minute window. Omit or `null` for the server default. */
|
|
79
83
|
rate_limit?: number | null;
|
|
80
84
|
/** ISO-8601 expiration timestamp. Omit for no expiration. */
|
|
81
85
|
expires_at?: string | null;
|
|
82
86
|
}
|
|
83
87
|
/**
|
|
84
|
-
* Payload for updating
|
|
88
|
+
* Payload for updating a service key. Only the fields provided change.
|
|
85
89
|
* @group Models
|
|
86
90
|
*/
|
|
87
91
|
export interface UpdateApiKeyRequest {
|
|
88
92
|
name?: string;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
admin?: boolean;
|
|
93
|
+
scopes?: string[];
|
|
94
|
+
roles?: string[];
|
|
92
95
|
rate_limit?: number | null;
|
|
93
96
|
expires_at?: string | null;
|
|
94
97
|
}
|
|
95
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* Payload for creating a personal key. It acts as the caller, so it carries no
|
|
100
|
+
* roles and no rate-limit override.
|
|
101
|
+
* @group Models
|
|
102
|
+
*/
|
|
103
|
+
export interface CreatePersonalKeyRequest {
|
|
104
|
+
name: string;
|
|
105
|
+
/** At least one, and none the caller does not hold. `keys:*` is refused. */
|
|
106
|
+
scopes: string[];
|
|
107
|
+
/** ISO-8601 expiration timestamp. Omit for no expiration. */
|
|
108
|
+
expires_at?: string | null;
|
|
109
|
+
}
|
|
110
|
+
/** The project's service keys. Requires `keys:read` / `keys:write`. @group Models */
|
|
96
111
|
export interface ApiKeysAPI {
|
|
97
112
|
listKeys(): Promise<{
|
|
98
113
|
keys: ApiKeyMasked[];
|
|
@@ -110,3 +125,20 @@ export interface ApiKeysAPI {
|
|
|
110
125
|
success: boolean;
|
|
111
126
|
}>;
|
|
112
127
|
}
|
|
128
|
+
/** The signed-in person's own keys, when the app enables them. @group Models */
|
|
129
|
+
export interface PersonalKeysAPI {
|
|
130
|
+
listKeys(): Promise<{
|
|
131
|
+
keys: ApiKeyMasked[];
|
|
132
|
+
}>;
|
|
133
|
+
createKey(data: CreatePersonalKeyRequest): Promise<{
|
|
134
|
+
key: ApiKeyWithSecret;
|
|
135
|
+
}>;
|
|
136
|
+
revokeKey(id: string): Promise<{
|
|
137
|
+
success: boolean;
|
|
138
|
+
}>;
|
|
139
|
+
/** Every scope the backend knows, described, and the ones the caller holds. */
|
|
140
|
+
listScopes(): Promise<{
|
|
141
|
+
scopes: ScopeSummary[];
|
|
142
|
+
held: string[];
|
|
143
|
+
}>;
|
|
144
|
+
}
|
|
@@ -53,6 +53,18 @@ export interface MountableRouter {
|
|
|
53
53
|
/** The routes the sub-app declares. Only its presence is contractual. */
|
|
54
54
|
routes: readonly unknown[];
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* The request header that asks for a data-plane request to run as another
|
|
58
|
+
* user, named by uid.
|
|
59
|
+
*
|
|
60
|
+
* The server honours it only on a signed-in administrator's own session —
|
|
61
|
+
* never on an API key or the service key — and only through an adapter that
|
|
62
|
+
* implements {@link AuthAdapter.resolveUser}. Everywhere else a request that
|
|
63
|
+
* carries it is refused, never run as its caller.
|
|
64
|
+
*
|
|
65
|
+
* @group Auth
|
|
66
|
+
*/
|
|
67
|
+
export declare const IMPERSONATE_HEADER = "x-rebase-impersonate";
|
|
56
68
|
/**
|
|
57
69
|
* The normalized user object returned by `AuthAdapter.verifyRequest()`.
|
|
58
70
|
*
|
|
@@ -72,7 +84,11 @@ export interface AuthenticatedUser {
|
|
|
72
84
|
photoUrl?: string | null;
|
|
73
85
|
/** Role identifiers the user holds. */
|
|
74
86
|
roles: string[];
|
|
75
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Whether `roles` includes `admin`. Informational — every authorization
|
|
89
|
+
* decision reads `roles` and the scopes they hold, so an adapter that
|
|
90
|
+
* wants a user treated as an administrator gives them the `admin` role.
|
|
91
|
+
*/
|
|
76
92
|
isAdmin: boolean;
|
|
77
93
|
/**
|
|
78
94
|
* Whether this session is a GUEST — anonymous sign-in rather than an
|
|
@@ -90,6 +106,12 @@ export interface AuthenticatedUser {
|
|
|
90
106
|
rawToken?: string;
|
|
91
107
|
/** Extra claims/metadata from the auth provider. */
|
|
92
108
|
claims?: Record<string, unknown>;
|
|
109
|
+
/**
|
|
110
|
+
* What this credential may do, when it is narrower than its person — set
|
|
111
|
+
* for an API key. Absent means everything the user's roles hold
|
|
112
|
+
* (`scopesForRoles`).
|
|
113
|
+
*/
|
|
114
|
+
scopes?: string[];
|
|
93
115
|
}
|
|
94
116
|
/**
|
|
95
117
|
* Feature flags advertised by an auth adapter.
|
|
@@ -171,6 +193,26 @@ export interface AuthAdapterCapabilities {
|
|
|
171
193
|
*/
|
|
172
194
|
needsSetup?: boolean;
|
|
173
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* What `GET /api/auth/config` answers: the auth adapter's capabilities, plus
|
|
198
|
+
* the optional features of the backend around it.
|
|
199
|
+
*
|
|
200
|
+
* The admin panel reads this document before anything else, so it is where
|
|
201
|
+
* the panel learns that a feature is off, without first asking for that
|
|
202
|
+
* feature and getting a refusal.
|
|
203
|
+
*
|
|
204
|
+
* @group Auth
|
|
205
|
+
*/
|
|
206
|
+
export interface AuthConfigDocument extends AuthAdapterCapabilities {
|
|
207
|
+
/**
|
|
208
|
+
* Whether this backend serves file storage. When it is `false`, no storage
|
|
209
|
+
* backend is configured: `GET /storage/sources` lists nothing and every
|
|
210
|
+
* other `/storage` route answers 501 `STORAGE_NOT_CONFIGURED`. Absent from
|
|
211
|
+
* a backend that predates the field, so a client must ask
|
|
212
|
+
* `GET /storage/sources` there.
|
|
213
|
+
*/
|
|
214
|
+
storage?: boolean;
|
|
215
|
+
}
|
|
174
216
|
/**
|
|
175
217
|
* Options for paginated user listing.
|
|
176
218
|
* @group Auth
|
|
@@ -217,6 +259,11 @@ export interface AuthCreateUserData {
|
|
|
217
259
|
displayName?: string;
|
|
218
260
|
photoUrl?: string;
|
|
219
261
|
metadata?: Record<string, unknown>;
|
|
262
|
+
/**
|
|
263
|
+
* Store the address as verified: whoever creates the account named it
|
|
264
|
+
* (an operator, an administrator), so nobody needs to prove it.
|
|
265
|
+
*/
|
|
266
|
+
emailVerified?: boolean;
|
|
220
267
|
}
|
|
221
268
|
/**
|
|
222
269
|
* User management operations for the admin panel.
|
|
@@ -390,6 +437,23 @@ export interface AuthAdapter {
|
|
|
390
437
|
* @returns The authenticated user, or `null` if the token is invalid.
|
|
391
438
|
*/
|
|
392
439
|
verifyToken?(token: string): Promise<AuthenticatedUser | null>;
|
|
440
|
+
/**
|
|
441
|
+
* The identity a verified request from this account would carry right
|
|
442
|
+
* now, with no credential involved: its uid, its roles as they are now,
|
|
443
|
+
* its guest flag, and the custom claims a token minted for it now would
|
|
444
|
+
* hold. `null` when no active account has this uid — none at all, or one
|
|
445
|
+
* that is disabled.
|
|
446
|
+
*
|
|
447
|
+
* This is what lets an administrator run a request as another user (the
|
|
448
|
+
* {@link IMPERSONATE_HEADER} header). The server calls it only after it
|
|
449
|
+
* has decided the caller may do that, and it calls it for the caller too,
|
|
450
|
+
* so the decision rests on the caller's roles as they are now rather than
|
|
451
|
+
* on the ones their token claims.
|
|
452
|
+
*
|
|
453
|
+
* Optional. An adapter without it cannot be impersonated through, and a
|
|
454
|
+
* request carrying the header is refused rather than run as its caller.
|
|
455
|
+
*/
|
|
456
|
+
resolveUser?(uid: string): Promise<AuthenticatedUser | null>;
|
|
393
457
|
/**
|
|
394
458
|
* User CRUD for the admin panel's user management UI.
|
|
395
459
|
* Optional — if not provided, user management UI is hidden.
|
|
@@ -490,6 +554,40 @@ export interface AuthAdapter {
|
|
|
490
554
|
id: string;
|
|
491
555
|
values: Record<string, unknown>;
|
|
492
556
|
}, clearPassword?: string): Promise<UserCreationFinalizeResult>;
|
|
557
|
+
/**
|
|
558
|
+
* Check, and put in stored form, updates to rows of the auth collection
|
|
559
|
+
* that arrive through the data API — `PATCH /<users>/:id`, `PATCH /bulk`,
|
|
560
|
+
* `_batch`, the realtime socket.
|
|
561
|
+
*
|
|
562
|
+
* Those rows are the users, so an update to one is user administration,
|
|
563
|
+
* and has to hold to what the admin user routes hold to: no update that
|
|
564
|
+
* leaves the project without an administrator, and an email stored the
|
|
565
|
+
* way sign-in looks it up. Throws to refuse; the updates are judged
|
|
566
|
+
* together, so a bulk demotion of every admin is refused even though each
|
|
567
|
+
* row alone would pass.
|
|
568
|
+
*
|
|
569
|
+
* If not implemented, the values are written as they arrived.
|
|
570
|
+
*
|
|
571
|
+
* @returns Each update's values, as they should be written, in order.
|
|
572
|
+
*/
|
|
573
|
+
prepareUserUpdates?(updates: ReadonlyArray<{
|
|
574
|
+
uid: string;
|
|
575
|
+
values: Record<string, unknown>;
|
|
576
|
+
}>): Promise<Record<string, unknown>[]>;
|
|
577
|
+
/**
|
|
578
|
+
* Check a deletion of these users through the data API before any row goes,
|
|
579
|
+
* and run the hooks that may veto it (`beforeUserDelete`). Throws to
|
|
580
|
+
* refuse — for one that would leave the project without an administrator,
|
|
581
|
+
* among others.
|
|
582
|
+
*
|
|
583
|
+
* If not implemented, the rows are deleted as any other.
|
|
584
|
+
*/
|
|
585
|
+
prepareUserDeletions?(uids: readonly string[]): Promise<void>;
|
|
586
|
+
/**
|
|
587
|
+
* After those users' rows are deleted through the data API: end their
|
|
588
|
+
* sessions and run the after-delete hooks (`afterUserDelete`).
|
|
589
|
+
*/
|
|
590
|
+
finalizeUserDeletions?(uids: readonly string[]): Promise<void>;
|
|
493
591
|
/**
|
|
494
592
|
* A static secret key for server-to-server / script authentication.
|
|
495
593
|
*
|
package/dist/types/backend.d.ts
CHANGED
|
@@ -246,6 +246,12 @@ export interface RealtimeChannelsConfig {
|
|
|
246
246
|
* Defaults to `{ type: "memory" }` — i.e. they don't.
|
|
247
247
|
*/
|
|
248
248
|
bus?: ChannelBusSetting;
|
|
249
|
+
/**
|
|
250
|
+
* How many subscriptions one socket may hold; the next is refused with
|
|
251
|
+
* `TOO_MANY_SUBSCRIPTIONS`. A positive whole number, checked at boot.
|
|
252
|
+
* Defaults to 1000. `REALTIME_MAX_SUBSCRIPTIONS_PER_SOCKET` wins over it.
|
|
253
|
+
*/
|
|
254
|
+
maxSubscriptionsPerSocket?: number;
|
|
249
255
|
}
|
|
250
256
|
/**
|
|
251
257
|
* Abstract realtime provider interface.
|
|
@@ -293,6 +299,25 @@ export interface RealtimeProvider {
|
|
|
293
299
|
* Called during graceful shutdown before closing database connections.
|
|
294
300
|
*/
|
|
295
301
|
stopListening?(): Promise<void>;
|
|
302
|
+
/**
|
|
303
|
+
* The long-lived connections realtime depends on, for `/health`. A change
|
|
304
|
+
* feed that has gone quiet — a half-open LISTEN connection — loses every
|
|
305
|
+
* external and cross-instance change while writes through this instance
|
|
306
|
+
* still look live, so it is reported rather than inferred.
|
|
307
|
+
*/
|
|
308
|
+
health?(): RealtimeListenerHealth[];
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* One long-lived realtime connection, as `/health` reports it.
|
|
312
|
+
* @group Backend
|
|
313
|
+
*/
|
|
314
|
+
export interface RealtimeListenerHealth {
|
|
315
|
+
/** What it carries — `"cdc"`, `"cross-instance"`, `"channel-bus"`. */
|
|
316
|
+
name: string;
|
|
317
|
+
/** Listening on a connection that answered its last heartbeat. */
|
|
318
|
+
connected: boolean;
|
|
319
|
+
/** When (epoch ms) it went down, while it is down. */
|
|
320
|
+
downSince?: number;
|
|
296
321
|
}
|
|
297
322
|
/**
|
|
298
323
|
* Abstract collection registry interface.
|
|
@@ -341,6 +366,97 @@ export interface DataTransformer {
|
|
|
341
366
|
*/
|
|
342
367
|
deserializeFromDatabase<M extends Record<string, unknown>>(data: Record<string, unknown>, collection: CollectionConfig): Promise<M>;
|
|
343
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* The table column a value of a {@link SqlScriptResult} was read from, as the
|
|
371
|
+
* database itself reported it — not as the query's text suggests.
|
|
372
|
+
*
|
|
373
|
+
* @group Admin
|
|
374
|
+
*/
|
|
375
|
+
export interface SqlScriptColumnSource {
|
|
376
|
+
schema: string;
|
|
377
|
+
table: string;
|
|
378
|
+
column: string;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* One column of a {@link SqlScriptResult}, in result order.
|
|
382
|
+
*
|
|
383
|
+
* @group Admin
|
|
384
|
+
*/
|
|
385
|
+
export interface SqlScriptColumn {
|
|
386
|
+
/** The name the result gives it. Two columns of one result may share it. */
|
|
387
|
+
name: string;
|
|
388
|
+
/** Its type, as the database names it: `integer`, `text[]`, `timestamp with time zone`. */
|
|
389
|
+
type?: string;
|
|
390
|
+
/**
|
|
391
|
+
* Where the database says the value came from: a plain reference to a
|
|
392
|
+
* column of a table or view, through any number of subqueries.
|
|
393
|
+
*
|
|
394
|
+
* Absent for everything no stored row holds — an expression, a cast that
|
|
395
|
+
* changes the type, a literal, an aggregate, a function's output, a
|
|
396
|
+
* `UNION`.
|
|
397
|
+
*/
|
|
398
|
+
source?: SqlScriptColumnSource;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* A table or view some column of a {@link SqlScriptResult} came from.
|
|
402
|
+
*
|
|
403
|
+
* @group Admin
|
|
404
|
+
*/
|
|
405
|
+
export interface SqlScriptTable {
|
|
406
|
+
schema: string;
|
|
407
|
+
table: string;
|
|
408
|
+
/** What the relation is. Only a `table` or a `partitioned table` holds rows that can be updated by key. */
|
|
409
|
+
kind: "table" | "partitioned table" | "view" | "materialized view" | "foreign table" | "other";
|
|
410
|
+
/** Its primary key columns, in key order. Empty when it has none. */
|
|
411
|
+
primaryKey: string[];
|
|
412
|
+
/**
|
|
413
|
+
* Other tables inherit this one (by `INHERITS`, not as partitions). A row
|
|
414
|
+
* read from it may live in one of them, and a primary key is not unique
|
|
415
|
+
* across them.
|
|
416
|
+
*/
|
|
417
|
+
hasInheritors: boolean;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Something the database said while a script ran: `there is no transaction in
|
|
421
|
+
* progress` for a ROLLBACK with nothing to end, a `RAISE NOTICE`.
|
|
422
|
+
*
|
|
423
|
+
* @group Admin
|
|
424
|
+
*/
|
|
425
|
+
export interface SqlScriptNotice {
|
|
426
|
+
severity: string;
|
|
427
|
+
message: string;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* What a SQL script a person wrote returned. See {@link SQLAdmin.runSqlScript}.
|
|
431
|
+
*
|
|
432
|
+
* @group Admin
|
|
433
|
+
*/
|
|
434
|
+
export interface SqlScriptResult {
|
|
435
|
+
/**
|
|
436
|
+
* The last statement's rows, every value as the text the database wrote
|
|
437
|
+
* for it and `null` for SQL NULL — so a value written back is the value
|
|
438
|
+
* that was read, whatever its type. Keyed by column name: of two columns
|
|
439
|
+
* that share a name, the row holds the last.
|
|
440
|
+
*/
|
|
441
|
+
rows: Record<string, string | null>[];
|
|
442
|
+
/** The last statement's columns, in order. */
|
|
443
|
+
columns: SqlScriptColumn[];
|
|
444
|
+
/** The tables and views {@link SqlScriptColumn.source} names. */
|
|
445
|
+
tables: SqlScriptTable[];
|
|
446
|
+
/** The last statement's command: `SELECT`, `UPDATE`, `CREATE TABLE` … */
|
|
447
|
+
command?: string;
|
|
448
|
+
/** How many rows the last statement returned or changed, when its command reports a count. */
|
|
449
|
+
rowCount?: number;
|
|
450
|
+
/** What the database said while the script ran, in order. */
|
|
451
|
+
notices: SqlScriptNotice[];
|
|
452
|
+
/**
|
|
453
|
+
* The database role the script ran as, when it asked for one — said by
|
|
454
|
+
* the transport that ran it. The role asked for, unless the server has
|
|
455
|
+
* role switching turned off (`DISABLE_DB_ROLE_SWITCHING`) and runs every
|
|
456
|
+
* statement as the connection owner, who is named here instead.
|
|
457
|
+
*/
|
|
458
|
+
effectiveRole?: string;
|
|
459
|
+
}
|
|
344
460
|
/**
|
|
345
461
|
* Administrative operations for SQL-based databases (PostgreSQL, MySQL, etc.).
|
|
346
462
|
* Used by the SQL Editor, RLS Editor, and schema browser.
|
|
@@ -350,12 +466,35 @@ export interface DataTransformer {
|
|
|
350
466
|
export interface SQLAdmin {
|
|
351
467
|
/**
|
|
352
468
|
* Execute raw SQL against the database.
|
|
469
|
+
*
|
|
470
|
+
* `isolateSession` runs it on a connection of its own and resets that
|
|
471
|
+
* connection's session state — role, session authorization, settings —
|
|
472
|
+
* before it is reused. For SQL a person wrote (the Studio editor), which
|
|
473
|
+
* may `SET ROLE` and must not leave that on a pooled connection the
|
|
474
|
+
* server's own queries use next.
|
|
353
475
|
*/
|
|
354
476
|
executeSql(sql: string, options?: {
|
|
355
477
|
database?: string;
|
|
356
478
|
role?: string;
|
|
357
479
|
params?: unknown[];
|
|
480
|
+
isolateSession?: boolean;
|
|
358
481
|
}): Promise<Record<string, unknown>[]>;
|
|
482
|
+
/**
|
|
483
|
+
* Run a script a person wrote — the Studio SQL console — and describe what
|
|
484
|
+
* it returned.
|
|
485
|
+
*
|
|
486
|
+
* On a session of its own, reset afterwards, as `role` for every statement
|
|
487
|
+
* of it. Values come back as the database's text, and each column says
|
|
488
|
+
* which table column it was read from, when the database says so: what
|
|
489
|
+
* the console needs to write a cell back to the row it came from and to
|
|
490
|
+
* no other. A script that leaves a transaction open is refused, and the
|
|
491
|
+
* transaction rolled back: nothing outlives the run to be committed or
|
|
492
|
+
* rolled back by a later one.
|
|
493
|
+
*/
|
|
494
|
+
runSqlScript?(sql: string, options?: {
|
|
495
|
+
database?: string;
|
|
496
|
+
role?: string;
|
|
497
|
+
}): Promise<SqlScriptResult>;
|
|
359
498
|
/**
|
|
360
499
|
* Fetch the available databases on the server.
|
|
361
500
|
*/
|
|
@@ -426,6 +565,12 @@ export interface SchemaAdmin {
|
|
|
426
565
|
export interface BranchInfo {
|
|
427
566
|
/** Branch name (without prefix). */
|
|
428
567
|
name: string;
|
|
568
|
+
/**
|
|
569
|
+
* The PostgreSQL database the branch is — what to connect to, and what to
|
|
570
|
+
* name as the source when copying it. As the branch's record says, never
|
|
571
|
+
* derived from `name` again.
|
|
572
|
+
*/
|
|
573
|
+
database: string;
|
|
429
574
|
/** The database this branch was created from. */
|
|
430
575
|
parentDatabase: string;
|
|
431
576
|
/** When the branch was created. */
|
|
@@ -579,6 +724,82 @@ export interface BackendInstance extends BackendLifecycle {
|
|
|
579
724
|
* Factory function type for creating backend instances
|
|
580
725
|
*/
|
|
581
726
|
export type BackendFactory<TConfig extends BackendConfig = BackendConfig> = (config: TConfig) => BackendInstance;
|
|
727
|
+
/**
|
|
728
|
+
* A caller of the data API as its rate limiter buckets one outside an HTTP
|
|
729
|
+
* request: a realtime socket's frame, counted in the same bucket the same
|
|
730
|
+
* person's HTTP requests are.
|
|
731
|
+
* @group Backend
|
|
732
|
+
*/
|
|
733
|
+
export interface DataRateLimitCaller {
|
|
734
|
+
/**
|
|
735
|
+
* The signed-in user's uid. Absent, or the anonymous principal, buckets
|
|
736
|
+
* the caller by address at the anonymous allowance.
|
|
737
|
+
*/
|
|
738
|
+
uid?: string;
|
|
739
|
+
/**
|
|
740
|
+
* The API key the connection authenticated with. Its frames count in the
|
|
741
|
+
* key's own bucket at the key's own `rate_limit`, the bucket its HTTP
|
|
742
|
+
* requests count in, rather than as `uid`.
|
|
743
|
+
*/
|
|
744
|
+
apiKey?: {
|
|
745
|
+
id: string;
|
|
746
|
+
rate_limit: number | null;
|
|
747
|
+
};
|
|
748
|
+
/**
|
|
749
|
+
* A header of the request that opened the connection, by lower-case name:
|
|
750
|
+
* the proxy headers an address is read from when proxies are declared.
|
|
751
|
+
*/
|
|
752
|
+
header(name: string): string | undefined;
|
|
753
|
+
/** The address the connection comes from. */
|
|
754
|
+
socketAddress?: string;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* What the realtime socket shares with the HTTP data API: its request limits,
|
|
758
|
+
* so a frame carries the ones an HTTP request to the same rows does, and its
|
|
759
|
+
* API-key verification, so a key means the same thing on both.
|
|
760
|
+
* @group Backend
|
|
761
|
+
*/
|
|
762
|
+
export interface RealtimeSocketOptions {
|
|
763
|
+
/**
|
|
764
|
+
* Verify an `rk_` API key presented to `AUTHENTICATE`: the identity it acts
|
|
765
|
+
* as and the scopes it holds, or why it does not authenticate. Absent when
|
|
766
|
+
* the deployment has no API-key store, and then keys cannot authenticate
|
|
767
|
+
* the socket.
|
|
768
|
+
*/
|
|
769
|
+
resolveApiKey?: (token: string) => Promise<{
|
|
770
|
+
uid: string;
|
|
771
|
+
roles: string[];
|
|
772
|
+
scopes: string[];
|
|
773
|
+
/** The key itself: its id and `rate_limit` decide which rate-limit bucket its frames count in. */
|
|
774
|
+
apiKey?: {
|
|
775
|
+
id: string;
|
|
776
|
+
rate_limit: number | null;
|
|
777
|
+
};
|
|
778
|
+
} | {
|
|
779
|
+
message: string;
|
|
780
|
+
}>;
|
|
781
|
+
/**
|
|
782
|
+
* The largest frame accepted, in bytes — the data API's body limit. `0` or
|
|
783
|
+
* less for none. Defaults to the server's default body limit.
|
|
784
|
+
*/
|
|
785
|
+
maxPayload?: number;
|
|
786
|
+
/**
|
|
787
|
+
* Count one data request from `caller` in the data API's per-caller
|
|
788
|
+
* buckets and say whether it is allowed; `null` for a caller who is not
|
|
789
|
+
* limited. Absent when the deployment has rate limiting off.
|
|
790
|
+
*/
|
|
791
|
+
dataRateLimit?: (caller: DataRateLimitCaller) => Promise<{
|
|
792
|
+
allowed: boolean;
|
|
793
|
+
retryAfterMs: number;
|
|
794
|
+
} | null>;
|
|
795
|
+
/**
|
|
796
|
+
* How often a socket that only listens has its identity re-read, in ms
|
|
797
|
+
* (default 30 000). A socket that sends frames is re-checked before each
|
|
798
|
+
* one; this bounds how long a subscription keeps receiving rows as an
|
|
799
|
+
* identity that has since signed out, been revoked, demoted or deleted.
|
|
800
|
+
*/
|
|
801
|
+
identityRecheckIntervalMs?: number;
|
|
802
|
+
}
|
|
582
803
|
/**
|
|
583
804
|
* A `BackendBootstrapper` encapsulates all driver-specific initialization logic.
|
|
584
805
|
*
|
|
@@ -784,7 +1005,7 @@ export interface BackendBootstrapper {
|
|
|
784
1005
|
/**
|
|
785
1006
|
* Initialize WebSocket server for realtime operations.
|
|
786
1007
|
*/
|
|
787
|
-
initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: import("../controllers/data_driver.js").DataDriver, config?: unknown, authAdapter?: AuthAdapter): Promise<void> | void;
|
|
1008
|
+
initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: import("../controllers/data_driver.js").DataDriver, config?: unknown, authAdapter?: AuthAdapter, limits?: RealtimeSocketOptions): Promise<void> | void;
|
|
788
1009
|
}
|
|
789
1010
|
/**
|
|
790
1011
|
* Result of `BackendBootstrapper.initializeDriver()`.
|
|
@@ -820,8 +1041,6 @@ export interface InitializedDriver {
|
|
|
820
1041
|
export interface BootstrappedAuth {
|
|
821
1042
|
/** User management service. */
|
|
822
1043
|
userService: unknown;
|
|
823
|
-
/** Role management service (optional, roles are now simple strings). */
|
|
824
|
-
roleService?: unknown;
|
|
825
1044
|
/** Email service (optional). */
|
|
826
1045
|
emailService?: unknown;
|
|
827
1046
|
/** Combined Auth Repository for unified token and user management. */
|
package/dist/types/backup.d.ts
CHANGED
|
@@ -25,3 +25,86 @@ export interface BackupInfo {
|
|
|
25
25
|
*/
|
|
26
26
|
globalsKey?: string;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* How one run of the scheduled backup went, read from the cron's run history.
|
|
30
|
+
*/
|
|
31
|
+
export interface BackupRunOutcome {
|
|
32
|
+
/** ISO timestamp the run started. */
|
|
33
|
+
startedAt: string;
|
|
34
|
+
/** ISO timestamp the run ended. */
|
|
35
|
+
finishedAt: string;
|
|
36
|
+
/** Whether the run produced a backup. */
|
|
37
|
+
success: boolean;
|
|
38
|
+
/** Why it did not, when it failed — e.g. `Could not find the 'pg_dump' binary.` */
|
|
39
|
+
error?: string;
|
|
40
|
+
/** True when someone triggered the run by hand rather than the schedule. */
|
|
41
|
+
manual: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The deployment's scheduled backup job — the cron that default-exports
|
|
45
|
+
* `createBackupCron` — and the outcome of its last run.
|
|
46
|
+
*
|
|
47
|
+
* Shown by the Backups panel so a backup that fails every night is visible
|
|
48
|
+
* where the backups are listed, rather than only in the cron history.
|
|
49
|
+
*/
|
|
50
|
+
export interface BackupScheduleStatus {
|
|
51
|
+
/** The cron job's id, which is its file's name. */
|
|
52
|
+
jobId: string;
|
|
53
|
+
/** The job's display name. */
|
|
54
|
+
name: string;
|
|
55
|
+
/** Its cron expression. */
|
|
56
|
+
schedule: string;
|
|
57
|
+
/** False when the job is paused (or declared `enabled: false`), or refused. */
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* True when the job is off because its own definition says
|
|
61
|
+
* `enabled: false` — the documented backup cron file exports it that way
|
|
62
|
+
* while `BACKUP_SCHEDULE` is unset — and not because someone paused it.
|
|
63
|
+
* Resuming it in Cron Jobs would run that definition as written.
|
|
64
|
+
*/
|
|
65
|
+
disabledInCode?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Why the scheduler refused the job — an invalid schedule, timezone or
|
|
68
|
+
* timeout. A refused job is not registered and never runs; the cron file
|
|
69
|
+
* has to change.
|
|
70
|
+
*/
|
|
71
|
+
refused?: string;
|
|
72
|
+
/** ISO timestamp of the next scheduled run, when one is armed. */
|
|
73
|
+
nextRunAt?: string;
|
|
74
|
+
/**
|
|
75
|
+
* The most recent scheduled run, absent when the schedule has never run
|
|
76
|
+
* it — or when its run history could not be read, which
|
|
77
|
+
* {@link historyError} says. A run someone started by hand is not one:
|
|
78
|
+
* see {@link lastManualRun}.
|
|
79
|
+
*/
|
|
80
|
+
lastRun?: BackupRunOutcome;
|
|
81
|
+
/** A run started by hand ("Run Now") since {@link lastRun}, when there is one. */
|
|
82
|
+
lastManualRun?: BackupRunOutcome;
|
|
83
|
+
/**
|
|
84
|
+
* Why the job's run history could not be read. Whether it ran, and how it
|
|
85
|
+
* went, is then unknown: `lastRun` is absent for that reason, not because
|
|
86
|
+
* the job never ran.
|
|
87
|
+
*/
|
|
88
|
+
historyError?: string;
|
|
89
|
+
}
|
|
90
|
+
/** What the backup listing (`GET /admin/backups`) answers. */
|
|
91
|
+
export interface BackupListing {
|
|
92
|
+
/** Backups at the destination, newest first. */
|
|
93
|
+
backups: BackupInfo[];
|
|
94
|
+
/** The kind of destination they were read from. */
|
|
95
|
+
destinationKind: BackupDestinationKind;
|
|
96
|
+
/** False when `BACKUP_DESTINATION` is unset. */
|
|
97
|
+
configured: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* The scheduled backup job, or `null` when the deployment registers none.
|
|
100
|
+
* Absent from a server that predates the field.
|
|
101
|
+
*/
|
|
102
|
+
schedule?: BackupScheduleStatus | null;
|
|
103
|
+
/**
|
|
104
|
+
* True when the destination is a local path and the scheduled backup runs
|
|
105
|
+
* in another process (the worker of a split deployment). The backups
|
|
106
|
+
* listed are the ones on this process's disk; the scheduled runs write to
|
|
107
|
+
* theirs, which is the same directory only when both mount it.
|
|
108
|
+
*/
|
|
109
|
+
localDiskOfThisProcess?: boolean;
|
|
110
|
+
}
|