@rebasepro/types 0.24.0 → 0.24.1-canary.gcb918fc
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/call_context.d.ts +8 -4
- package/dist/controllers/client.d.ts +68 -10
- package/dist/controllers/data.d.ts +412 -76
- package/dist/controllers/data_driver.d.ts +85 -1
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/storage-references.d.ts +114 -0
- package/dist/controllers/storage.d.ts +20 -79
- package/dist/index.es.js +140 -12
- package/dist/index.es.js.map +1 -1
- package/dist/types/auth_adapter.d.ts +32 -1
- package/dist/types/backend.d.ts +168 -4
- package/dist/types/backup.d.ts +19 -0
- package/dist/types/cron.d.ts +22 -7
- package/dist/types/database_adapter.d.ts +32 -6
- package/dist/types/entities.d.ts +11 -0
- package/dist/types/history.d.ts +15 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/project_manifest.d.ts +8 -0
- package/dist/types/properties.d.ts +28 -2
- package/dist/types/register.d.ts +43 -0
- package/dist/types/relations.d.ts +37 -1
- package/dist/types/resource_kinds.d.ts +7 -1
- package/dist/types/storage_authorize.d.ts +5 -0
- package/dist/types/websockets.d.ts +32 -1
- package/package.json +1 -1
|
@@ -303,6 +303,23 @@ export interface UserCreationPrepareResult {
|
|
|
303
303
|
/** Whether an invitation was sent (only relevant when hookHandledEmail is true). */
|
|
304
304
|
invitationSent: boolean;
|
|
305
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* What the door creating a user knows about its caller, for
|
|
308
|
+
* `AuthAdapter.prepareUserCreation()`.
|
|
309
|
+
*
|
|
310
|
+
* @group Auth
|
|
311
|
+
*/
|
|
312
|
+
export interface UserCreationOptions {
|
|
313
|
+
/**
|
|
314
|
+
* Whether the caller may waive the password policy with
|
|
315
|
+
* `skipPasswordPolicy: true` in the body. The doors set it for an
|
|
316
|
+
* administrator (the service key signs in as one) and for nobody else, so
|
|
317
|
+
* an adapter that reads the flag is taking an administrator at their word —
|
|
318
|
+
* an import of accounts whose passwords were set under another system's
|
|
319
|
+
* rules. Absent, the flag waives nothing.
|
|
320
|
+
*/
|
|
321
|
+
mayWaivePasswordPolicy?: boolean;
|
|
322
|
+
}
|
|
306
323
|
/**
|
|
307
324
|
* What a create body for an auth collection may name beyond the collection's
|
|
308
325
|
* own declared fields — see `AuthAdapter.describeUserCreationContract()`.
|
|
@@ -322,6 +339,16 @@ export interface UserCreationWriteContract {
|
|
|
322
339
|
* deletes it before the row is ever built.
|
|
323
340
|
*/
|
|
324
341
|
extraFields: string[];
|
|
342
|
+
/**
|
|
343
|
+
* Each body's `prepareUserCreation` touches nothing but its own result —
|
|
344
|
+
* no hook, no email, no write — so a bulk create may prepare several at
|
|
345
|
+
* once. The built-in adapter's path with no `onCreateUser`, no
|
|
346
|
+
* `onAdminCreateUser` and the default `hashPassword` is: it hashes a
|
|
347
|
+
* password and normalizes an email, and a 1,000-row bulk spent half a
|
|
348
|
+
* minute hashing one password at a time. Leave it unset when a hook runs:
|
|
349
|
+
* preparations then run one at a time, in the order the rows were given.
|
|
350
|
+
*/
|
|
351
|
+
independent?: boolean;
|
|
325
352
|
}
|
|
326
353
|
/**
|
|
327
354
|
* Result of `AuthAdapter.finalizeUserCreation()`.
|
|
@@ -505,11 +532,15 @@ export interface AuthAdapter {
|
|
|
505
532
|
*
|
|
506
533
|
* If not implemented, the collection saves values as-is (no password hashing).
|
|
507
534
|
*
|
|
535
|
+
* A chosen `password` is held to the password policy unless the body says
|
|
536
|
+
* `skipPasswordPolicy: true` and `options.mayWaivePasswordPolicy` is set.
|
|
537
|
+
*
|
|
508
538
|
* @param values - Raw request body from the client.
|
|
509
539
|
* @param collectionAuth - The parsed `AuthCollectionConfig` from the collection (if `auth` is an object).
|
|
540
|
+
* @param options - What the door knows about its caller.
|
|
510
541
|
* @returns Processed values ready for `driver.save()`, plus metadata for the post-save step.
|
|
511
542
|
*/
|
|
512
|
-
prepareUserCreation?(values: Record<string, unknown>, collectionAuth?: unknown): Promise<UserCreationPrepareResult>;
|
|
543
|
+
prepareUserCreation?(values: Record<string, unknown>, collectionAuth?: unknown, options?: UserCreationOptions): Promise<UserCreationPrepareResult>;
|
|
513
544
|
/**
|
|
514
545
|
* Describe what a create body for this auth collection is allowed to name,
|
|
515
546
|
* so unknown-field validation can run on it.
|
package/dist/types/backend.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { AuthAdapter } from "./auth_adapter.js";
|
|
|
6
6
|
import type { HistoryConfig } from "../controllers/client.js";
|
|
7
7
|
import type { ChannelBusSetting } from "./channel_bus.js";
|
|
8
8
|
import type { SchemaEditingAdmin } from "./schema_editing.js";
|
|
9
|
+
import type { AccessModel } from "./scopes.js";
|
|
9
10
|
/**
|
|
10
11
|
* Abstract database connection interface.
|
|
11
12
|
* Represents a connection to any database system.
|
|
@@ -252,6 +253,52 @@ export interface RealtimeChannelsConfig {
|
|
|
252
253
|
* Defaults to 1000. `REALTIME_MAX_SUBSCRIPTIONS_PER_SOCKET` wins over it.
|
|
253
254
|
*/
|
|
254
255
|
maxSubscriptionsPerSocket?: number;
|
|
256
|
+
/**
|
|
257
|
+
* How many sockets one user (one identity: a signed-in user, an API key's
|
|
258
|
+
* user, an impersonated user) may hold open on one server instance. The
|
|
259
|
+
* next one's `AUTHENTICATE` is refused with `TOO_MANY_SOCKETS` and the
|
|
260
|
+
* socket closed with 4002; the SDK keeps retrying with backoff, so it gets
|
|
261
|
+
* in once another closes. A positive whole number, checked at boot.
|
|
262
|
+
* Unset (the default) is no ceiling. `REALTIME_MAX_SOCKETS_PER_USER` wins
|
|
263
|
+
* over it.
|
|
264
|
+
*/
|
|
265
|
+
maxSocketsPerUser?: number;
|
|
266
|
+
/**
|
|
267
|
+
* The longest a change waits for the refetch that delivers it, in ms. A
|
|
268
|
+
* refetch waits for 300 ms without a change, and at most this long under a
|
|
269
|
+
* steady stream of writes. Defaults to 1000. A positive whole number,
|
|
270
|
+
* checked at boot. `REALTIME_REFETCH_MAX_WAIT_MS` wins over it.
|
|
271
|
+
*/
|
|
272
|
+
refetchMaxWaitMs?: number;
|
|
273
|
+
/**
|
|
274
|
+
* How long a big list subscription's total may be reused before it is
|
|
275
|
+
* counted again, in ms. Unset (the default), every frame counts. Frames
|
|
276
|
+
* that reuse it carry `meta.totalAsOf`. `REALTIME_RECOUNT_INTERVAL_MS`
|
|
277
|
+
* wins over it.
|
|
278
|
+
*/
|
|
279
|
+
recountIntervalMs?: number;
|
|
280
|
+
/**
|
|
281
|
+
* The smallest last total at which {@link recountIntervalMs} applies;
|
|
282
|
+
* smaller lists are counted on every frame. Defaults to 100 000.
|
|
283
|
+
* `REALTIME_RECOUNT_MIN_ROWS` wins over it.
|
|
284
|
+
*/
|
|
285
|
+
recountMinRows?: number;
|
|
286
|
+
/**
|
|
287
|
+
* How changes are captured for realtime. `auto` (the default) installs
|
|
288
|
+
* database-level capture where the connection can and falls back to
|
|
289
|
+
* announcing the API's own writes where it cannot; `trigger` asks for
|
|
290
|
+
* capture and warns when it is refused; `wal` is `trigger` until WAL
|
|
291
|
+
* streaming ships; `off` announces the API's own writes only.
|
|
292
|
+
* `REALTIME_CDC` wins over it.
|
|
293
|
+
*/
|
|
294
|
+
cdc?: "auto" | "wal" | "trigger" | "off";
|
|
295
|
+
/**
|
|
296
|
+
* The URL path the realtime socket accepts upgrades on. Defaults to the
|
|
297
|
+
* one the server derives from where it is mounted — `/` for a server at
|
|
298
|
+
* `/api`, which is where the SDK dials. Set it when clients dial elsewhere
|
|
299
|
+
* (a `websocketUrl` with a path). See {@link RealtimeSocketOptions.path}.
|
|
300
|
+
*/
|
|
301
|
+
path?: string;
|
|
255
302
|
}
|
|
256
303
|
/**
|
|
257
304
|
* Abstract realtime provider interface.
|
|
@@ -445,8 +492,19 @@ export interface SqlScriptResult {
|
|
|
445
492
|
tables: SqlScriptTable[];
|
|
446
493
|
/** The last statement's command: `SELECT`, `UPDATE`, `CREATE TABLE` … */
|
|
447
494
|
command?: string;
|
|
448
|
-
/**
|
|
495
|
+
/**
|
|
496
|
+
* How many rows the last statement returned or changed, when its command
|
|
497
|
+
* reports a count — or, for a {@link truncated} result, how many it
|
|
498
|
+
* returned, of which {@link rows} holds the first.
|
|
499
|
+
*/
|
|
449
500
|
rowCount?: number;
|
|
501
|
+
/**
|
|
502
|
+
* The last statement returned more than a run keeps, and {@link rows}
|
|
503
|
+
* holds only its first rows. The Studio console's door keeps at most
|
|
504
|
+
* 10,000 rows, or 32 Mi characters of values, of one result: a run that
|
|
505
|
+
* held every row of a million-row table took the server down with it.
|
|
506
|
+
*/
|
|
507
|
+
truncated?: boolean;
|
|
450
508
|
/** What the database said while the script ran, in order. */
|
|
451
509
|
notices: SqlScriptNotice[];
|
|
452
510
|
/**
|
|
@@ -457,6 +515,22 @@ export interface SqlScriptResult {
|
|
|
457
515
|
*/
|
|
458
516
|
effectiveRole?: string;
|
|
459
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* A query's result being read a batch at a time — see `SQLAdmin.openSqlCursor`.
|
|
520
|
+
*
|
|
521
|
+
* @group Admin
|
|
522
|
+
*/
|
|
523
|
+
export interface SqlCursor {
|
|
524
|
+
/** The result's column names, in order. */
|
|
525
|
+
readonly columns: string[];
|
|
526
|
+
/**
|
|
527
|
+
* The next rows, each value the text the database wrote for it and `null`
|
|
528
|
+
* for NULL — `null` once there are none left.
|
|
529
|
+
*/
|
|
530
|
+
read(): Promise<(string | null)[][] | null>;
|
|
531
|
+
/** End the read and give the session back. Safe to call more than once. */
|
|
532
|
+
close(): Promise<void>;
|
|
533
|
+
}
|
|
460
534
|
/**
|
|
461
535
|
* Administrative operations for SQL-based databases (PostgreSQL, MySQL, etc.).
|
|
462
536
|
* Used by the SQL Editor, RLS Editor, and schema browser.
|
|
@@ -472,12 +546,19 @@ export interface SQLAdmin {
|
|
|
472
546
|
* before it is reused. For SQL a person wrote (the Studio editor), which
|
|
473
547
|
* may `SET ROLE` and must not leave that on a pooled connection the
|
|
474
548
|
* server's own queries use next.
|
|
549
|
+
*
|
|
550
|
+
* `maxResultBytes` refuses a result whose rows take more than that many
|
|
551
|
+
* bytes, with an error whose `code` is `RESULT_TOO_LARGE`, rather than
|
|
552
|
+
* return it — never a part of it. On a session of its own the read stops
|
|
553
|
+
* there; elsewhere the rows are measured once read. The WebSocket
|
|
554
|
+
* `EXECUTE_SQL` door sets it for every caller.
|
|
475
555
|
*/
|
|
476
556
|
executeSql(sql: string, options?: {
|
|
477
557
|
database?: string;
|
|
478
558
|
role?: string;
|
|
479
559
|
params?: unknown[];
|
|
480
560
|
isolateSession?: boolean;
|
|
561
|
+
maxResultBytes?: number;
|
|
481
562
|
}): Promise<Record<string, unknown>[]>;
|
|
482
563
|
/**
|
|
483
564
|
* Run a script a person wrote — the Studio SQL console — and describe what
|
|
@@ -490,11 +571,35 @@ export interface SQLAdmin {
|
|
|
490
571
|
* no other. A script that leaves a transaction open is refused, and the
|
|
491
572
|
* transaction rolled back: nothing outlives the run to be committed or
|
|
492
573
|
* rolled back by a later one.
|
|
574
|
+
*
|
|
575
|
+
* Aborting `signal` cancels the run: the statement in progress is stopped
|
|
576
|
+
* (`pg_cancel_backend` on a Postgres server; the in-process development
|
|
577
|
+
* database cannot be interrupted, and the run ends on its own), and the
|
|
578
|
+
* promise rejects.
|
|
493
579
|
*/
|
|
494
580
|
runSqlScript?(sql: string, options?: {
|
|
495
581
|
database?: string;
|
|
496
582
|
role?: string;
|
|
583
|
+
signal?: AbortSignal;
|
|
497
584
|
}): Promise<SqlScriptResult>;
|
|
585
|
+
/**
|
|
586
|
+
* Read the whole result of ONE query a person wrote, a batch at a time —
|
|
587
|
+
* the Studio SQL console's "Download full result as CSV", which the
|
|
588
|
+
* console's 10,000-row cap would otherwise leave no way to get.
|
|
589
|
+
*
|
|
590
|
+
* Through a server-side cursor, in a read-only transaction, on a session
|
|
591
|
+
* of its own, as `role`: a write is refused by the database, and a second
|
|
592
|
+
* statement by the protocol. Each batch is read when the previous one has
|
|
593
|
+
* been consumed, so memory holds one batch whatever the result's size;
|
|
594
|
+
* every read runs under the session's `statement_timeout`. The session is
|
|
595
|
+
* reset and returned when the cursor is closed — which the caller must do,
|
|
596
|
+
* on success, failure or a reader that went away.
|
|
597
|
+
*/
|
|
598
|
+
openSqlCursor?(sql: string, options?: {
|
|
599
|
+
database?: string;
|
|
600
|
+
role?: string;
|
|
601
|
+
batchSize?: number;
|
|
602
|
+
}): Promise<SqlCursor>;
|
|
498
603
|
/**
|
|
499
604
|
* Fetch the available databases on the server.
|
|
500
605
|
*/
|
|
@@ -520,6 +625,21 @@ export interface SQLAdmin {
|
|
|
520
625
|
* Fetch the current database name.
|
|
521
626
|
*/
|
|
522
627
|
fetchCurrentDatabase?(): Promise<string | undefined>;
|
|
628
|
+
/**
|
|
629
|
+
* Hold a `LISTEN` on `channel`, on a connection of its own that stays open
|
|
630
|
+
* and comes back after a drop, and call `onNotify` with each payload — what
|
|
631
|
+
* wakes the job worker when another process enqueues, instead of a poll
|
|
632
|
+
* every two seconds.
|
|
633
|
+
*
|
|
634
|
+
* Resolves once listening, with the stop. Rejects when no such connection
|
|
635
|
+
* can be had — an in-process database, a first connect that fails — so the
|
|
636
|
+
* caller can fall back to polling. `onReconnect` is called each time a
|
|
637
|
+
* dropped connection is listening again: whatever was sent meanwhile is
|
|
638
|
+
* lost. `channel` must be a plain identifier.
|
|
639
|
+
*/
|
|
640
|
+
listen?(channel: string, onNotify: (payload: string) => void, options?: {
|
|
641
|
+
onReconnect?: () => void;
|
|
642
|
+
}): Promise<() => Promise<void>>;
|
|
523
643
|
}
|
|
524
644
|
/**
|
|
525
645
|
* Administrative operations for document-based databases (MongoDB, Firestore, etc.).
|
|
@@ -778,6 +898,24 @@ export interface RealtimeSocketOptions {
|
|
|
778
898
|
} | {
|
|
779
899
|
message: string;
|
|
780
900
|
}>;
|
|
901
|
+
/**
|
|
902
|
+
* Verify a session token presented to `AUTHENTICATE` with the backend's own
|
|
903
|
+
* keys, when the socket has no auth adapter to ask: who it names, or null
|
|
904
|
+
* when it does not verify. The server passes its backend's; absent, the
|
|
905
|
+
* driver falls back to the process default.
|
|
906
|
+
*/
|
|
907
|
+
verifyAccessToken?: (token: string) => Promise<{
|
|
908
|
+
uid: string;
|
|
909
|
+
roles?: string[];
|
|
910
|
+
isAnonymous?: boolean;
|
|
911
|
+
claims?: Record<string, unknown>;
|
|
912
|
+
} | null>;
|
|
913
|
+
/**
|
|
914
|
+
* The backend's access model — what a session's roles hold on the socket's
|
|
915
|
+
* admin frames. The server passes its backend's; absent, the driver falls
|
|
916
|
+
* back to the process default.
|
|
917
|
+
*/
|
|
918
|
+
accessModel?: AccessModel;
|
|
781
919
|
/**
|
|
782
920
|
* The largest frame accepted, in bytes — the data API's body limit. `0` or
|
|
783
921
|
* less for none. Defaults to the server's default body limit.
|
|
@@ -799,6 +937,29 @@ export interface RealtimeSocketOptions {
|
|
|
799
937
|
* identity that has since signed out, been revoked, demoted or deleted.
|
|
800
938
|
*/
|
|
801
939
|
identityRecheckIntervalMs?: number;
|
|
940
|
+
/**
|
|
941
|
+
* How often a socket that asked for heartbeats (`?rebase_caps=heartbeat`)
|
|
942
|
+
* is sent one, in ms (default 30 000). The SDK redials after two missed.
|
|
943
|
+
*/
|
|
944
|
+
heartbeatIntervalMs?: number;
|
|
945
|
+
/**
|
|
946
|
+
* How many sockets one identity may hold open on this server; the next
|
|
947
|
+
* one's `AUTHENTICATE` is refused with `TOO_MANY_SOCKETS` and the socket
|
|
948
|
+
* closed (4002). Unset for no ceiling. See `realtime.maxSocketsPerUser`.
|
|
949
|
+
*/
|
|
950
|
+
maxSocketsPerUser?: number;
|
|
951
|
+
/**
|
|
952
|
+
* The URL path the socket accepts upgrades on (default `/`). The SDK dials
|
|
953
|
+
* its `baseUrl` with no extra segment, so for a server mounted at `/api`
|
|
954
|
+
* this is `/`, and for one at `/app/api` it is `/app`. A trailing `/` is
|
|
955
|
+
* ignored, and so is the query string.
|
|
956
|
+
*
|
|
957
|
+
* An upgrade to any other path is not this socket's: it is left untouched
|
|
958
|
+
* for another `upgrade` listener on the same `http.Server` — a host app's
|
|
959
|
+
* own WebSocket server — or, when the socket's listener is the only one,
|
|
960
|
+
* answered `404` and closed, so the client is not left hanging.
|
|
961
|
+
*/
|
|
962
|
+
path?: string;
|
|
802
963
|
}
|
|
803
964
|
/**
|
|
804
965
|
* A `BackendBootstrapper` encapsulates all driver-specific initialization logic.
|
|
@@ -876,8 +1037,11 @@ export interface BackendBootstrapper {
|
|
|
876
1037
|
*/
|
|
877
1038
|
initializeRealtime?(config: unknown, driverResult: InitializedDriver): Promise<RealtimeProvider | undefined>;
|
|
878
1039
|
/**
|
|
879
|
-
*
|
|
880
|
-
*
|
|
1040
|
+
* Never called: the server mounts no route on a bootstrapper's behalf. A
|
|
1041
|
+
* driver that needs HTTP routes exports a route factory, and the app
|
|
1042
|
+
* mounts it where it chooses.
|
|
1043
|
+
*
|
|
1044
|
+
* @deprecated Never called. Will be removed in a future release.
|
|
881
1045
|
*/
|
|
882
1046
|
mountRoutes?(app: unknown, basePath: string, driverResult: InitializedDriver): void;
|
|
883
1047
|
/**
|
|
@@ -1029,7 +1193,7 @@ export interface InitializedDriver {
|
|
|
1029
1193
|
connection?: DatabaseConnection;
|
|
1030
1194
|
/**
|
|
1031
1195
|
* Opaque handle that the bootstrapper can use in subsequent hooks
|
|
1032
|
-
* (e.g., `initializeAuth`, `
|
|
1196
|
+
* (e.g., `initializeAuth`, `getAdmin`) to access driver internals.
|
|
1033
1197
|
* Not used by the coordinator.
|
|
1034
1198
|
*/
|
|
1035
1199
|
internals?: unknown;
|
package/dist/types/backup.d.ts
CHANGED
|
@@ -87,6 +87,25 @@ export interface BackupScheduleStatus {
|
|
|
87
87
|
*/
|
|
88
88
|
historyError?: string;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* A short-lived link to one backup's bytes, from `POST /admin/backups/download-url`.
|
|
92
|
+
*
|
|
93
|
+
* The URL needs no `Authorization` header — the token in it stands in for one,
|
|
94
|
+
* for this backup only — so a browser can be sent to it and stream the dump to
|
|
95
|
+
* disk instead of holding it in the page.
|
|
96
|
+
*/
|
|
97
|
+
export interface BackupDownloadLink {
|
|
98
|
+
/**
|
|
99
|
+
* `…/admin/backups/download?key=…&token=…`. The server answers it as a
|
|
100
|
+
* path on itself; the SDK's `downloadUrl()` answers it absolute, on the
|
|
101
|
+
* client's own base URL.
|
|
102
|
+
*/
|
|
103
|
+
url: string;
|
|
104
|
+
/** The token in {@link url}, on its own. */
|
|
105
|
+
token: string;
|
|
106
|
+
/** Seconds until the link stops working (60). */
|
|
107
|
+
expiresIn: number;
|
|
108
|
+
}
|
|
90
109
|
/** What the backup listing (`GET /admin/backups`) answers. */
|
|
91
110
|
export interface BackupListing {
|
|
92
111
|
/** Backups at the destination, newest first. */
|
package/dist/types/cron.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RebaseServerClient } from "../controllers/client.js";
|
|
2
|
+
import type { RegisteredDatabase } from "./register.js";
|
|
2
3
|
/**
|
|
3
4
|
* Cron Job type definitions for Rebase.
|
|
4
5
|
*
|
|
@@ -10,7 +11,7 @@ import type { RebaseServerClient } from "../controllers/client.js";
|
|
|
10
11
|
* A cron job definition file exports this shape as its default export.
|
|
11
12
|
* See the example cron files in `app/backend/crons/` for usage.
|
|
12
13
|
*/
|
|
13
|
-
export interface CronJobDefinition {
|
|
14
|
+
export interface CronJobDefinition<DB = RegisteredDatabase> {
|
|
14
15
|
schedule: string;
|
|
15
16
|
/**
|
|
16
17
|
* IANA time zone the schedule is read in, e.g. `"Europe/Madrid"`.
|
|
@@ -84,20 +85,21 @@ export interface CronJobDefinition {
|
|
|
84
85
|
* Receives a context object with the data driver and logger.
|
|
85
86
|
* May return arbitrary JSON-serialisable data stored in the log.
|
|
86
87
|
*/
|
|
87
|
-
handler: (ctx: CronJobContext) => Promise<unknown> | unknown;
|
|
88
|
+
handler: (ctx: CronJobContext<DB>) => Promise<unknown> | unknown;
|
|
88
89
|
}
|
|
89
90
|
/**
|
|
90
91
|
* Context passed to each cron handler invocation.
|
|
91
92
|
*/
|
|
92
|
-
export interface CronJobContext {
|
|
93
|
+
export interface CronJobContext<DB = RegisteredDatabase> {
|
|
93
94
|
/** The job's unique ID (derived from filename). */
|
|
94
95
|
jobId: string;
|
|
95
96
|
/** The current scheduled tick timestamp. */
|
|
96
97
|
scheduledAt: Date;
|
|
97
98
|
/**
|
|
98
|
-
* A simple logger scoped to this job run. Each line is
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* A simple logger scoped to this job run. Each line is written to the
|
|
100
|
+
* server log at `info`, with a `cron` field holding the job ID, and kept
|
|
101
|
+
* with the run's log entry — the first 500 lines or 64 KB of them,
|
|
102
|
+
* whichever comes first, then one line saying how many more there were.
|
|
101
103
|
*/
|
|
102
104
|
log: (...args: unknown[]) => void;
|
|
103
105
|
/**
|
|
@@ -156,7 +158,7 @@ export interface CronJobContext {
|
|
|
156
158
|
* }
|
|
157
159
|
* });
|
|
158
160
|
*/
|
|
159
|
-
rebase: RebaseServerClient
|
|
161
|
+
rebase: RebaseServerClient<DB>;
|
|
160
162
|
}
|
|
161
163
|
export type CronJobRunState = "idle" | "running" | "success" | "error" | "disabled";
|
|
162
164
|
/**
|
|
@@ -244,3 +246,16 @@ export interface CronJobLogEntry {
|
|
|
244
246
|
/** Whether this was a manual trigger. */
|
|
245
247
|
manual?: boolean;
|
|
246
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* The answer to a manual trigger made with `?async=1`
|
|
251
|
+
* (`client.cron.triggerJob(id, { async: true })`): the run has started and
|
|
252
|
+
* carries on after the answer. Its outcome is in the run history, as the entry
|
|
253
|
+
* with `manual: true` and this `startedAt`.
|
|
254
|
+
*/
|
|
255
|
+
export interface CronJobStarted {
|
|
256
|
+
accepted: true;
|
|
257
|
+
/** ISO timestamp the run started at — the `startedAt` of its log entry. */
|
|
258
|
+
startedAt: string;
|
|
259
|
+
/** The job's status as the run began. */
|
|
260
|
+
job: CronJobStatus;
|
|
261
|
+
}
|
|
@@ -171,9 +171,11 @@ export interface DatabaseAdapter {
|
|
|
171
171
|
*/
|
|
172
172
|
getAdmin?(driverResult: InitializedDriver): DatabaseAdmin | undefined;
|
|
173
173
|
/**
|
|
174
|
-
*
|
|
174
|
+
* Never called: the server mounts no route on an adapter's behalf. A
|
|
175
|
+
* driver that needs HTTP routes exports a route factory, and the app
|
|
176
|
+
* mounts it where it chooses.
|
|
175
177
|
*
|
|
176
|
-
*
|
|
178
|
+
* @deprecated Never called. Will be removed in a future release.
|
|
177
179
|
*/
|
|
178
180
|
mountRoutes?(app: unknown, basePath: string, driverResult: InitializedDriver): void;
|
|
179
181
|
/**
|
|
@@ -196,8 +198,29 @@ export interface DatabaseAdapterInitConfig {
|
|
|
196
198
|
* name none when this is the default.
|
|
197
199
|
*/
|
|
198
200
|
dataSourceKey?: string;
|
|
199
|
-
/**
|
|
200
|
-
|
|
201
|
+
/**
|
|
202
|
+
* The backend's shared collection registry. No bundled driver reads it —
|
|
203
|
+
* each builds and returns its own on `InitializedDriver.collectionRegistry`
|
|
204
|
+
* — so a caller opening a driver on its own (a script, a test) leaves it out.
|
|
205
|
+
*/
|
|
206
|
+
collectionRegistry?: CollectionRegistryInterface;
|
|
207
|
+
/**
|
|
208
|
+
* Whether opening the driver may change the database (default `true`).
|
|
209
|
+
*
|
|
210
|
+
* The server's boot owns its schema, so the driver provisions what it needs
|
|
211
|
+
* while it opens: the restricted role requests run as under RLS, the
|
|
212
|
+
* branch-metadata table, channel-history tables, change-capture triggers.
|
|
213
|
+
*
|
|
214
|
+
* `false` opens it with no DDL of any kind — what a script, a REPL or a
|
|
215
|
+
* test that only reads and writes rows wants, and what a process that does
|
|
216
|
+
* not own the schema must ask for. A connection that would bypass
|
|
217
|
+
* row-level security still sends a user's requests through the restricted
|
|
218
|
+
* role; when an earlier boot never created that role, those requests fail
|
|
219
|
+
* rather than run unfiltered. Change capture is not installed
|
|
220
|
+
* (`realtime.provision` reads as `false`); whether change events are
|
|
221
|
+
* consumed is still `realtime.subscribe`.
|
|
222
|
+
*/
|
|
223
|
+
provision?: boolean;
|
|
201
224
|
/**
|
|
202
225
|
* Whether this driver should describe its own schema.
|
|
203
226
|
*
|
|
@@ -251,9 +274,12 @@ export interface DatabaseAdapterInitConfig {
|
|
|
251
274
|
* runtime otherwise refuses to boot without.
|
|
252
275
|
*
|
|
253
276
|
* Absent means both — every caller that predates this field is a
|
|
254
|
-
* single-process deployment, where both are true.
|
|
277
|
+
* single-process deployment, where both are true. `false` is a process
|
|
278
|
+
* that takes no part in realtime at all: nothing installed, nothing
|
|
279
|
+
* consumed, and its writes not announced to the processes that serve
|
|
280
|
+
* realtime (a script, a REPL).
|
|
255
281
|
*/
|
|
256
|
-
realtime?: {
|
|
282
|
+
realtime?: false | {
|
|
257
283
|
/**
|
|
258
284
|
* Consume change events: open the `LISTEN` connection, start CDC or the
|
|
259
285
|
* app-level fallback. False for a process that serves no websockets.
|
package/dist/types/entities.d.ts
CHANGED
|
@@ -32,6 +32,17 @@ export interface Entity<M extends Record<string, unknown> = Record<string, unkno
|
|
|
32
32
|
* and a record fetched by id never has one.
|
|
33
33
|
*/
|
|
34
34
|
searchMatches?: SearchMatch[];
|
|
35
|
+
/**
|
|
36
|
+
* The version of the row this entity was read at: the `ETag` the read
|
|
37
|
+
* reported, for a `findById`, a `PATCH` answer or a live row frame. A
|
|
38
|
+
* form saves with it as `If-Match`, so a write made against a version
|
|
39
|
+
* someone has since replaced is refused instead of reverting their change.
|
|
40
|
+
*
|
|
41
|
+
* Absent for a row from a list, from a cache, or from a server or data
|
|
42
|
+
* source that does not report versions — a save then is unconditional,
|
|
43
|
+
* as it always was.
|
|
44
|
+
*/
|
|
45
|
+
etag?: string;
|
|
35
46
|
/**
|
|
36
47
|
* Which driver this entity belongs to (e.g., 'postgres', 'firestore').
|
|
37
48
|
* If not specified, the default driver is assumed.
|
package/dist/types/history.d.ts
CHANGED
|
@@ -27,8 +27,20 @@ export interface EntityHistoryEntry {
|
|
|
27
27
|
action: "create" | "update" | "delete";
|
|
28
28
|
/** Which fields changed. `null` for creates and deletes. */
|
|
29
29
|
changed_fields: string[] | null;
|
|
30
|
+
/** The row after the change; for a delete, the row that was deleted. */
|
|
30
31
|
values: Record<string, unknown> | null;
|
|
32
|
+
/**
|
|
33
|
+
* On an update, what the changed fields held before it. `null` for creates
|
|
34
|
+
* and deletes. Which fields it holds depends on {@link format}.
|
|
35
|
+
*/
|
|
31
36
|
previous_values: Record<string, unknown> | null;
|
|
37
|
+
/**
|
|
38
|
+
* How the entry was stored. Absent or `1`: `previous_values` is the whole
|
|
39
|
+
* row before the change. `2`: it holds the `changed_fields` only — a field
|
|
40
|
+
* that is absent from it was absent before — and every other field is
|
|
41
|
+
* unchanged, so it is in `values`.
|
|
42
|
+
*/
|
|
43
|
+
format?: 1 | 2;
|
|
32
44
|
updated_by: string | null;
|
|
33
45
|
/** ISO-8601. A driver storing a native date converts on read. */
|
|
34
46
|
updated_at: string;
|
|
@@ -46,7 +58,9 @@ export interface RecordHistoryParams {
|
|
|
46
58
|
updatedBy?: string | null;
|
|
47
59
|
}
|
|
48
60
|
/**
|
|
49
|
-
* How much history to keep.
|
|
61
|
+
* How much history to keep. Both rules are applied to a row after each write
|
|
62
|
+
* to it; `ttlDays` is also applied to every row by an hourly sweep, so the
|
|
63
|
+
* history of a row nobody writes again (a deleted one) still ages out.
|
|
50
64
|
* @group Backend
|
|
51
65
|
*/
|
|
52
66
|
export interface HistoryRetentionConfig {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -83,6 +83,14 @@ export interface RebaseBackendAppConfig {
|
|
|
83
83
|
* its default export. Default `collections/users`.
|
|
84
84
|
*/
|
|
85
85
|
usersCollection?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Type server-side data from the generated `Database`. When `true`, every
|
|
88
|
+
* `rebase generate-sdk` — `rebase dev`'s included, and the first one on a
|
|
89
|
+
* fresh clone — writes the types and the `Register` declaration to
|
|
90
|
+
* `<config>/generated/`. `rebase generate-sdk --register` sets it.
|
|
91
|
+
* Default `false`.
|
|
92
|
+
*/
|
|
93
|
+
registerDatabase?: boolean;
|
|
86
94
|
/**
|
|
87
95
|
* `runtime: "custom"` only. Dockerfile path relative to the repository root.
|
|
88
96
|
* Default `Dockerfile`.
|
|
@@ -5,6 +5,12 @@ import type { ColorKey, ColorScheme } from "./chips.js";
|
|
|
5
5
|
import type { AuthState } from "../controllers/auth_state.js";
|
|
6
6
|
import type { AfterReadProps, BeforeSaveProps } from "./entity_callbacks.js";
|
|
7
7
|
import type { User } from "../users/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* A SQL expression, written in template form: ``"sql`gen_random_uuid()`"``.
|
|
10
|
+
* The `sql` and backticks are markup; the text between them is the SQL.
|
|
11
|
+
* @group Entity properties
|
|
12
|
+
*/
|
|
13
|
+
export type SqlExpression = `sql\`${string}\``;
|
|
8
14
|
/**
|
|
9
15
|
* Callbacks/Hooks for individual property fields
|
|
10
16
|
* @group Entity properties
|
|
@@ -372,6 +378,25 @@ export interface BaseProperty<CustomProps = unknown> {
|
|
|
372
378
|
* ```
|
|
373
379
|
*/
|
|
374
380
|
access?: FieldAccess;
|
|
381
|
+
/**
|
|
382
|
+
* The database fills this column when a create leaves it empty: a
|
|
383
|
+
* `NOT NULL DEFAULT <expression>` column such as `gen_random_uuid()`,
|
|
384
|
+
* `nextval(…)` or `now()`, whose value no property can state.
|
|
385
|
+
*
|
|
386
|
+
* A `validation.required` field with it may be left out of a create, by
|
|
387
|
+
* the admin form and by the API alike, and a create that sends it as `null`
|
|
388
|
+
* leaves it to the database rather than storing `NULL`. It is still
|
|
389
|
+
* required when a stored record is edited. The generated SDK's `Insert`
|
|
390
|
+
* type makes the field optional. Defaults to `false`.
|
|
391
|
+
*
|
|
392
|
+
* Give the expression, in the template form `isId` takes
|
|
393
|
+
* (``databaseDefault: "sql`gen_random_uuid()`"``), and the schema planner
|
|
394
|
+
* writes it as the column's `DEFAULT`, so `rebase db push` keeps it. `true`
|
|
395
|
+
* declares a DEFAULT someone else wrote and the planner does not write
|
|
396
|
+
* one, so a push plans dropping it. "Import from table" and
|
|
397
|
+
* `rebase schema introspect` set the expression they read.
|
|
398
|
+
*/
|
|
399
|
+
databaseDefault?: boolean | SqlExpression;
|
|
375
400
|
/**
|
|
376
401
|
* Use this to define dynamic properties that change based on certain conditions
|
|
377
402
|
* or on the entity's values. For example, you can make a field read-only if
|
|
@@ -421,8 +446,9 @@ export interface StringProperty extends BaseProperty {
|
|
|
421
446
|
*/
|
|
422
447
|
defaultValue?: string;
|
|
423
448
|
/**
|
|
424
|
-
* Optional database column type. If not set, it
|
|
425
|
-
*
|
|
449
|
+
* Optional database column type. If not set, it is `text` — or `uuid` for an `isId: "uuid"` key.
|
|
450
|
+
* `validation.max` does not bound a `text` column; declare `varchar` (or `char`) to get a
|
|
451
|
+
* width, which is then taken from `validation.max` (255 when it states none).
|
|
426
452
|
*/
|
|
427
453
|
columnType?: "varchar" | "text" | "char" | "uuid";
|
|
428
454
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project-wide registry of generated types, filled by module augmentation.
|
|
3
|
+
*
|
|
4
|
+
* Empty by default, and every server-side data surface is untyped while it is:
|
|
5
|
+
* `context.data`, `rebase.dataAsAdmin`, a cron's `ctx.rebase` and a function's
|
|
6
|
+
* `ctx.rebase` accept any collection by any name and hand back open records.
|
|
7
|
+
*
|
|
8
|
+
* A project that generated its types with `rebase generate-sdk` registers its
|
|
9
|
+
* `Database` once, in any file the TypeScript program includes:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* // src/rebase-env.d.ts — or the top of any module file
|
|
13
|
+
* import type { Database } from "./generated/database.types";
|
|
14
|
+
*
|
|
15
|
+
* declare module "@rebasepro/types" {
|
|
16
|
+
* interface Register {
|
|
17
|
+
* database: Database;
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* From then on every one of those surfaces is typed from it: rows, filters,
|
|
23
|
+
* sorts, `include`, and the inputs `create` and `update` accept. Nothing about
|
|
24
|
+
* the runtime changes; the registration is a declaration.
|
|
25
|
+
*
|
|
26
|
+
* A single function or cron can still name its own type instead —
|
|
27
|
+
* `defineFunction<Database>(…)`, `defineCron<Database>({…})` — which wins over
|
|
28
|
+
* the registration.
|
|
29
|
+
*
|
|
30
|
+
* @group Data
|
|
31
|
+
*/
|
|
32
|
+
export interface Register {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The `Database` a project registered on {@link Register}, or `unknown` when it
|
|
36
|
+
* registered none — which is what keeps an unregistered project's server-side
|
|
37
|
+
* data untyped, exactly as it was before the registry existed.
|
|
38
|
+
*
|
|
39
|
+
* @group Data
|
|
40
|
+
*/
|
|
41
|
+
export type RegisteredDatabase = Register extends {
|
|
42
|
+
database: infer DB;
|
|
43
|
+
} ? DB : unknown;
|