@rebasepro/types 0.17.3 → 0.18.1
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 -0
- package/dist/call_context.d.ts +20 -0
- package/dist/controllers/client.d.ts +36 -4
- package/dist/controllers/data.d.ts +120 -10
- package/dist/errors.d.ts +83 -4
- package/dist/index.es.js +522 -160
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +2 -2
- package/dist/types/auth_adapter.d.ts +41 -6
- package/dist/types/backend.d.ts +48 -0
- package/dist/types/collections.d.ts +25 -1
- package/dist/types/cron.d.ts +34 -0
- package/dist/types/database_adapter.d.ts +39 -0
- package/dist/types/entity_callbacks.d.ts +14 -1
- package/dist/types/filter-operators.d.ts +24 -1
- package/dist/types/policy.d.ts +29 -1
- package/dist/types/properties.d.ts +216 -3
- package/dist/types/relations.d.ts +65 -7
- package/dist/types/resource_kinds.d.ts +173 -17
- package/dist/types/resources.d.ts +108 -7
- package/dist/types/rls-functions.d.ts +11 -0
- package/dist/types/storage_source.d.ts +12 -23
- package/package.json +24 -23
- package/src/call_context.ts +0 -120
- package/src/controllers/auth_state.ts +0 -24
- package/src/controllers/client.ts +0 -494
- package/src/controllers/collection_registry.ts +0 -62
- package/src/controllers/data.ts +0 -1012
- package/src/controllers/data_driver.ts +0 -576
- package/src/controllers/effective_role.ts +0 -4
- package/src/controllers/email.ts +0 -91
- package/src/controllers/index.ts +0 -11
- package/src/controllers/storage.ts +0 -252
- package/src/errors.ts +0 -119
- package/src/index.ts +0 -5
- package/src/types/admin_block.ts +0 -209
- package/src/types/api_keys.ts +0 -108
- package/src/types/auth_adapter.ts +0 -580
- package/src/types/backend.ts +0 -987
- package/src/types/backup.ts +0 -26
- package/src/types/channel_bus.ts +0 -202
- package/src/types/chips.ts +0 -34
- package/src/types/collection_contract.ts +0 -278
- package/src/types/collections.ts +0 -763
- package/src/types/component_ref.ts +0 -92
- package/src/types/cron.ts +0 -213
- package/src/types/data_source.ts +0 -357
- package/src/types/database_adapter.ts +0 -267
- package/src/types/entities.ts +0 -226
- package/src/types/entity_callbacks.ts +0 -229
- package/src/types/filter-operators.ts +0 -444
- package/src/types/history.ts +0 -66
- package/src/types/index.ts +0 -36
- package/src/types/indexes.ts +0 -180
- package/src/types/policy.ts +0 -328
- package/src/types/postgres_introspection.ts +0 -101
- package/src/types/project_manifest.ts +0 -598
- package/src/types/properties.ts +0 -1368
- package/src/types/relations.ts +0 -417
- package/src/types/resource_kinds.ts +0 -390
- package/src/types/resources.ts +0 -368
- package/src/types/rls-functions.ts +0 -98
- package/src/types/schema_editing.ts +0 -157
- package/src/types/schema_version.ts +0 -112
- package/src/types/search.ts +0 -247
- package/src/types/security_rules.ts +0 -344
- package/src/types/storage_authorize.ts +0 -77
- package/src/types/storage_source.ts +0 -248
- package/src/types/websockets.ts +0 -117
- package/src/users/index.ts +0 -2
- package/src/users/user.ts +0 -69
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*
|
|
30
30
|
* @group Models
|
|
31
31
|
*/
|
|
32
|
-
export declare const ADMIN_COLLECTION_KEYS: readonly ["Actions", "additionalFields", "alwaysApplyDefaultValues", "components", "customViews", "defaultEntityAction", "defaultFilter", "defaultSelectedView", "defaultSize", "defaultViewMode", "disableDefaultActions", "display", "enabledViews", "entityActions", "entityViews", "exportable", "filterPresets", "fixedFilter", "form", "formAutoSave", "formView", "group", "hideFromEntityViews", "hideFromNavigation", "hideIdFromCollection", "hideIdFromForm", "icon", "includeJsonView", "inlineEditing", "kanban", "listProperties", "localChangesBackup", "openEntityMode", "orderProperty", "pagination", "previewProperties", "propertiesOrder", "selectionController", "selectionEnabled", "sideDialogWidth", "sort"];
|
|
32
|
+
export declare const ADMIN_COLLECTION_KEYS: readonly ["Actions", "additionalFields", "alwaysApplyDefaultValues", "browserCallbacks", "components", "customViews", "defaultEntityAction", "defaultFilter", "defaultSelectedView", "defaultSize", "defaultViewMode", "disableDefaultActions", "display", "enabledViews", "entityActions", "entityViews", "exportable", "filterPresets", "fixedFilter", "form", "formAutoSave", "formView", "group", "hideFromEntityViews", "hideFromNavigation", "hideIdFromCollection", "hideIdFromForm", "icon", "includeJsonView", "inlineEditing", "kanban", "listProperties", "localChangesBackup", "openEntityMode", "orderProperty", "pagination", "previewProperties", "propertiesOrder", "selectionController", "selectionEnabled", "sideDialogWidth", "sort"];
|
|
33
33
|
/** A key of a collection's `admin` block. @group Models */
|
|
34
34
|
export type AdminCollectionKey = typeof ADMIN_COLLECTION_KEYS[number];
|
|
35
35
|
/**
|
|
@@ -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", "hideFromCollection", "includeEntityLink", "includeId", "markdown", "minimalistView", "multiline", "Preview", "previewAsTag", "previewProperties", "readOnly", "sortable", "span", "spreadChildren", "urlPreview", "widget"];
|
|
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"];
|
|
53
53
|
/** A key of a property's `admin` block. @group Models */
|
|
54
54
|
export type AdminPropertyKey = typeof ADMIN_PROPERTY_KEYS[number];
|
|
55
55
|
/**
|
|
@@ -29,7 +29,30 @@
|
|
|
29
29
|
*
|
|
30
30
|
* @group Auth
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* A sub-app an adapter hands back for the framework to mount.
|
|
34
|
+
*
|
|
35
|
+
* Structural on purpose. This was `Hono<any, any, any>`, and that one
|
|
36
|
+
* `import type { Hono } from "hono"` was the whole reason `@rebasepro/types`
|
|
37
|
+
* peer-depended on hono — which npm and pnpm auto-install, so **every browser
|
|
38
|
+
* app that installed `@rebasepro/client` got a 2.8 MB server framework in its
|
|
39
|
+
* lockfile and its security scanners**, for a type used by two optional methods
|
|
40
|
+
* that a browser app can never call.
|
|
41
|
+
*
|
|
42
|
+
* The shape is the same duck-type the function loader already validates at
|
|
43
|
+
* runtime (`isHonoLike`: a `fetch` method and a `routes` array), and a real
|
|
44
|
+
* `Hono` satisfies it — asserted in `auth_adapter.test.ts`, which does import
|
|
45
|
+
* hono, because a structural type is only worth having if something proves the
|
|
46
|
+
* real thing still fits.
|
|
47
|
+
*
|
|
48
|
+
* @group Auth
|
|
49
|
+
*/
|
|
50
|
+
export interface MountableRouter {
|
|
51
|
+
/** Handle a request. Hono, Elysia and a hand-rolled router all have this. */
|
|
52
|
+
fetch: (request: Request) => Response | Promise<Response>;
|
|
53
|
+
/** The routes the sub-app declares. Only its presence is contractual. */
|
|
54
|
+
routes: readonly unknown[];
|
|
55
|
+
}
|
|
33
56
|
/**
|
|
34
57
|
* The normalized user object returned by `AuthAdapter.verifyRequest()`.
|
|
35
58
|
*
|
|
@@ -51,6 +74,18 @@ export interface AuthenticatedUser {
|
|
|
51
74
|
roles: string[];
|
|
52
75
|
/** Whether the user has admin privileges. */
|
|
53
76
|
isAdmin: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Whether this session is a GUEST — anonymous sign-in rather than an
|
|
79
|
+
* account.
|
|
80
|
+
*
|
|
81
|
+
* Optional, and absent means "not a guest", so an external adapter that
|
|
82
|
+
* has no such concept keeps behaving exactly as it did. When present it
|
|
83
|
+
* reaches the database as `rebase.is_anonymous()`, which is what lets a
|
|
84
|
+
* policy say "a signed-in person, not somebody who pressed Continue as
|
|
85
|
+
* guest" — two things that were the same principal inside every rule,
|
|
86
|
+
* because anonymous sign-in mints a real user row with a real uid.
|
|
87
|
+
*/
|
|
88
|
+
isAnonymous?: boolean;
|
|
54
89
|
/** Raw bearer token from the request (for forwarding). */
|
|
55
90
|
rawToken?: string;
|
|
56
91
|
/** Extra claims/metadata from the auth provider. */
|
|
@@ -363,19 +398,19 @@ export interface AuthAdapter {
|
|
|
363
398
|
* - External adapter: typically returns `undefined` (auth is handled externally).
|
|
364
399
|
* - Custom adapter: user mounts their own routes.
|
|
365
400
|
*
|
|
366
|
-
* The return type
|
|
367
|
-
*
|
|
368
|
-
*
|
|
401
|
+
* The return type is the structural {@link MountableRouter} rather than
|
|
402
|
+
* `Hono`, so this package needs no hono dependency. A real `Hono<HonoEnv>`
|
|
403
|
+
* satisfies it, and implementations are free to use their own env.
|
|
369
404
|
*
|
|
370
405
|
* @returns A Hono sub-app with auth routes, or `undefined` to skip route mounting.
|
|
371
406
|
*/
|
|
372
|
-
createAuthRoutes?():
|
|
407
|
+
createAuthRoutes?(): MountableRouter | undefined;
|
|
373
408
|
/**
|
|
374
409
|
* Mount admin routes (e.g. password reset for users).
|
|
375
410
|
*
|
|
376
411
|
* @returns A Hono sub-app with admin routes, or `undefined` to skip.
|
|
377
412
|
*/
|
|
378
|
-
createAdminRoutes?():
|
|
413
|
+
createAdminRoutes?(): MountableRouter | undefined;
|
|
379
414
|
/**
|
|
380
415
|
* Advertise what this auth adapter supports.
|
|
381
416
|
*
|
package/dist/types/backend.d.ts
CHANGED
|
@@ -637,6 +637,27 @@ export interface BackendBootstrapper {
|
|
|
637
637
|
* Return admin capabilities for this driver.
|
|
638
638
|
*/
|
|
639
639
|
getAdmin?(driverResult: InitializedDriver): DatabaseAdmin | undefined;
|
|
640
|
+
/**
|
|
641
|
+
* Ask the database whether it is there, before anything else touches it.
|
|
642
|
+
*
|
|
643
|
+
* Boot's first database call is not `initializeDriver` — it is the schema
|
|
644
|
+
* provisioning that runs ahead of it, and a driver's connection diagnosis
|
|
645
|
+
* therefore never got the chance to run. A stopped database produced
|
|
646
|
+
* `Failed query: [redacted]` and a stack through drizzle internals: no host,
|
|
647
|
+
* no port, no `ECONNREFUSED`, and no hint about starting the thing.
|
|
648
|
+
*
|
|
649
|
+
* Implementations MUST issue the cheapest round trip they have (`SELECT 1`),
|
|
650
|
+
* MUST throw an error whose message names the host, the port and the
|
|
651
|
+
* driver's own reason, and MAY log a fuller diagnosis first. They MUST NOT
|
|
652
|
+
* throw for a reachable database that merely answered something unexpected —
|
|
653
|
+
* the caller treats a throw as fatal.
|
|
654
|
+
*
|
|
655
|
+
* `driverResult` is optional for the same reason as
|
|
656
|
+
* {@link ensureCollectionSchema}: this runs before `initializeDriver`, so an
|
|
657
|
+
* adapter that was constructed with its own connection has to fall back to
|
|
658
|
+
* it.
|
|
659
|
+
*/
|
|
660
|
+
verifyConnection?(driverResult?: InitializedDriver): Promise<void>;
|
|
640
661
|
/**
|
|
641
662
|
* Bring the database's collection tables up to date, additively.
|
|
642
663
|
*
|
|
@@ -680,6 +701,33 @@ export interface BackendBootstrapper {
|
|
|
680
701
|
ensureCollectionPolicies?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
|
|
681
702
|
applied: number;
|
|
682
703
|
}>;
|
|
704
|
+
/**
|
|
705
|
+
* Create the RLS helper functions on this source's database. See
|
|
706
|
+
* `DatabaseAdapter.ensureRlsRuntime`; needed on every source that is not
|
|
707
|
+
* the default, whose helpers arrive with the auth tables.
|
|
708
|
+
*/
|
|
709
|
+
ensureRlsRuntime?(driverResult?: InitializedDriver): Promise<void>;
|
|
710
|
+
/**
|
|
711
|
+
* Re-check, after the schema exists, that requests will actually be
|
|
712
|
+
* constrained by the database's own authorization.
|
|
713
|
+
*
|
|
714
|
+
* A driver that isolates user requests by switching to a restricted role has
|
|
715
|
+
* to decide at connect time whether the switch is needed — and on a fresh
|
|
716
|
+
* database that question is asked before there is anything to answer with.
|
|
717
|
+
* The process then creates the schema, becomes its owner, and an owner is
|
|
718
|
+
* exempt from the policies on what it owns. So the answer that was true when
|
|
719
|
+
* the driver initialized can be false by the time it serves a request.
|
|
720
|
+
*
|
|
721
|
+
* This is where a driver asks again. It runs once, after collection tables,
|
|
722
|
+
* auth tables and policies are all in place, and it MUST fail rather than
|
|
723
|
+
* serve when the answer changed and cannot be acted on: booting anyway
|
|
724
|
+
* produces exactly the unenforced server this exists to prevent.
|
|
725
|
+
*
|
|
726
|
+
* Optional, because it is only meaningful for drivers whose isolation
|
|
727
|
+
* depends on state the schema affects. A driver with nothing to re-check
|
|
728
|
+
* omits it.
|
|
729
|
+
*/
|
|
730
|
+
finalizeSecurityPosture?(driverResult: InitializedDriver): Promise<void>;
|
|
683
731
|
/**
|
|
684
732
|
* Read the collections schema version this database was last provisioned
|
|
685
733
|
* from, or `null` when nothing has ever stamped it.
|
|
@@ -76,6 +76,15 @@ export interface BaseCollectionConfig<M extends Record<string, unknown> = Record
|
|
|
76
76
|
*
|
|
77
77
|
* // A direct-transport Firestore data source registered as "analytics"
|
|
78
78
|
* { slug: "events", dataSource: "analytics" }
|
|
79
|
+
*
|
|
80
|
+
* // The same, spelled once — `defineCollection` accepts the handle
|
|
81
|
+
* // `database("analytics")` returned and records its key here.
|
|
82
|
+
* import { analytics } from "../resources";
|
|
83
|
+
* defineCollection({ slug: "events", dataSource: analytics, … })
|
|
84
|
+
*
|
|
85
|
+
* A string on the recorded collection, because a collection is data past
|
|
86
|
+
* `defineCollection`: it serialises, it compares with `===`, and it reaches
|
|
87
|
+
* the admin UI over the wire, none of which a handle survives.
|
|
79
88
|
*/
|
|
80
89
|
dataSource?: string;
|
|
81
90
|
/**
|
|
@@ -188,8 +197,23 @@ export interface PostgresCollectionConfig<M extends Record<string, unknown> = Re
|
|
|
188
197
|
engine?: "postgres" | undefined;
|
|
189
198
|
/**
|
|
190
199
|
* The PostgreSQL table name for this collection.
|
|
200
|
+
*
|
|
201
|
+
* Optional: it defaults to `toSnakeCase(slug)`, which is what
|
|
202
|
+
* `getTableName()` has always returned when it was absent. The type simply
|
|
203
|
+
* demanded what the runtime already derived, so the smallest collection
|
|
204
|
+
* anyone could write named its table twice —
|
|
205
|
+
* `{ slug: "todos", table: "todos", … }` — and "why do I write it twice"
|
|
206
|
+
* is the first question every evaluator asked.
|
|
207
|
+
*
|
|
208
|
+
* Set it only when the table name differs from the slug: an existing
|
|
209
|
+
* database whose table is `blog_posts` while the URL should stay `posts`.
|
|
210
|
+
*
|
|
211
|
+
* Note that a **derived** name is still a real name, and nothing yet warns
|
|
212
|
+
* when one moves. Foreign-key and junction column defaults are derived from
|
|
213
|
+
* the *slug* rather than from this field, so renaming a slug re-derives
|
|
214
|
+
* them on the next `db push` even where `table` is pinned.
|
|
191
215
|
*/
|
|
192
|
-
table
|
|
216
|
+
table?: string;
|
|
193
217
|
/**
|
|
194
218
|
* The PostgreSQL schema name for this table.
|
|
195
219
|
* E.g. "public", "rebase", "auth".
|
package/dist/types/cron.d.ts
CHANGED
|
@@ -12,6 +12,16 @@ import type { RebaseServerClient } from "../controllers/client.js";
|
|
|
12
12
|
*/
|
|
13
13
|
export interface CronJobDefinition {
|
|
14
14
|
schedule: string;
|
|
15
|
+
/**
|
|
16
|
+
* IANA time zone the schedule is read in, e.g. `"Europe/Madrid"`.
|
|
17
|
+
*
|
|
18
|
+
* Without it the expression is read in the process's own zone — UTC in
|
|
19
|
+
* nearly every container, the developer's own on a laptop — so `0 3 * * *`
|
|
20
|
+
* fires at a different wall-clock hour either side of a deploy. Name the
|
|
21
|
+
* zone and the schedule means one thing everywhere it runs. An unknown zone
|
|
22
|
+
* is refused when the job loads rather than silently read as local time.
|
|
23
|
+
*/
|
|
24
|
+
timezone?: string;
|
|
15
25
|
/** Human-readable name shown in the Studio UI. */
|
|
16
26
|
name: string;
|
|
17
27
|
/** Optional description shown in the Studio UI. */
|
|
@@ -74,6 +84,30 @@ export interface CronJobContext {
|
|
|
74
84
|
scheduledAt: Date;
|
|
75
85
|
/** A simple logger scoped to this job run. */
|
|
76
86
|
log: (...args: unknown[]) => void;
|
|
87
|
+
/**
|
|
88
|
+
* Aborted when the run exceeds `timeoutSeconds`.
|
|
89
|
+
*
|
|
90
|
+
* The timeout has always stopped the scheduler *waiting* — it loses the
|
|
91
|
+
* race and the run is recorded as failed. It has never stopped the handler:
|
|
92
|
+
* a `fetch` to an unresponsive host kept its socket, and a job on a
|
|
93
|
+
* five-minute schedule with a five-minute timeout accumulated one abandoned
|
|
94
|
+
* request per tick until the process ran out of sockets, all of it invisible
|
|
95
|
+
* because the run was already marked failed.
|
|
96
|
+
*
|
|
97
|
+
* Pass it to anything that takes one, and the work stops when the run does:
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* export default defineCron({
|
|
101
|
+
* name: "Sync inventory",
|
|
102
|
+
* schedule: "*\/15 * * * *",
|
|
103
|
+
* timeoutSeconds: 60,
|
|
104
|
+
* async handler({ signal, log }) {
|
|
105
|
+
* const res = await fetch("https://supplier.example.com/stock", { signal });
|
|
106
|
+
* log(`fetched ${res.status}`);
|
|
107
|
+
* }
|
|
108
|
+
* });
|
|
109
|
+
*/
|
|
110
|
+
signal: AbortSignal;
|
|
77
111
|
/**
|
|
78
112
|
* The server-side Rebase singleton — the **same object** `import { rebase }
|
|
79
113
|
* from "@rebasepro/server"` returns, and the same one `defineFunction`
|
|
@@ -75,6 +75,16 @@ export interface DatabaseAdapter {
|
|
|
75
75
|
* accepted every client as already authenticated.
|
|
76
76
|
*/
|
|
77
77
|
initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown, adapter?: import("./auth_adapter.js").AuthAdapter): Promise<void> | void;
|
|
78
|
+
/**
|
|
79
|
+
* Ask the database whether it is there, before boot's first real query. See
|
|
80
|
+
* `BackendBootstrapper.verifyConnection` for the contract.
|
|
81
|
+
*
|
|
82
|
+
* Same forwarding requirement as the hooks below, and the symptom of
|
|
83
|
+
* dropping it is the failure this hook exists to prevent: a stopped database
|
|
84
|
+
* reported as `Failed query: [redacted]` and a stack through drizzle
|
|
85
|
+
* internals, naming no host, no port and no reason.
|
|
86
|
+
*/
|
|
87
|
+
verifyConnection?(driverResult?: InitializedDriver): Promise<void>;
|
|
78
88
|
/**
|
|
79
89
|
* Bring the database's collection tables up to date, additively — the boot
|
|
80
90
|
* companion to `db push`. See `BackendBootstrapper.ensureCollectionSchema`
|
|
@@ -109,6 +119,28 @@ export interface DatabaseAdapter {
|
|
|
109
119
|
ensureCollectionPolicies?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
|
|
110
120
|
applied: number;
|
|
111
121
|
}>;
|
|
122
|
+
/**
|
|
123
|
+
* Create the helper functions the generated policies call (`rebase.uid()`,
|
|
124
|
+
* `rebase.roles()` and their siblings) on THIS source's database.
|
|
125
|
+
*
|
|
126
|
+
* On the default source these arrive with the auth tables, because auth
|
|
127
|
+
* lives there. A second database gets no auth tables and had no helpers
|
|
128
|
+
* either, so every policy on it failed to create and every user read was
|
|
129
|
+
* denied — a collection declared on `database("analytics")` answered 401 on
|
|
130
|
+
* a healthy-looking backend. Idempotent; runs before
|
|
131
|
+
* `ensureCollectionPolicies` on every non-default source.
|
|
132
|
+
*/
|
|
133
|
+
ensureRlsRuntime?(driverResult?: InitializedDriver): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Re-check, once the schema exists, that requests will really be constrained
|
|
136
|
+
* by the database's own authorization. See
|
|
137
|
+
* `BackendBootstrapper.finalizeSecurityPosture`.
|
|
138
|
+
*
|
|
139
|
+
* Same forwarding requirement as the two hooks above, and the most costly
|
|
140
|
+
* one to drop: a wrapper that omits it turns a fresh deployment's first boot
|
|
141
|
+
* into a server that applies no row-level policy at all, and says nothing.
|
|
142
|
+
*/
|
|
143
|
+
finalizeSecurityPosture?(driverResult: InitializedDriver): Promise<void>;
|
|
112
144
|
/**
|
|
113
145
|
* Read the collections schema version this database was last provisioned
|
|
114
146
|
* from, or `null` when nothing has ever stamped it.
|
|
@@ -153,6 +185,13 @@ export interface DatabaseAdapter {
|
|
|
153
185
|
export interface DatabaseAdapterInitConfig {
|
|
154
186
|
/** Registered collection definitions. */
|
|
155
187
|
collections: CollectionConfig[];
|
|
188
|
+
/**
|
|
189
|
+
* The data-source key this driver serves — `(default)`, or a declared
|
|
190
|
+
* one such as `analytics`. A driver given every collection needs it to
|
|
191
|
+
* know which are its own: the ones whose `dataSource` names this key, or
|
|
192
|
+
* name none when this is the default.
|
|
193
|
+
*/
|
|
194
|
+
dataSourceKey?: string;
|
|
156
195
|
/** The shared collection registry to register into. */
|
|
157
196
|
collectionRegistry: CollectionRegistryInterface;
|
|
158
197
|
/**
|
|
@@ -91,11 +91,24 @@ export type BeforeSaveProps<M extends Record<string, unknown> = Record<string, u
|
|
|
91
91
|
id?: string | number;
|
|
92
92
|
};
|
|
93
93
|
/**
|
|
94
|
-
* Parameters passed to hooks
|
|
94
|
+
* Parameters passed to hooks when a save fails.
|
|
95
|
+
*
|
|
96
|
+
* `id` is optional because a failed create may never have been assigned one.
|
|
97
|
+
* `error` is what the save threw — the reason the hook exists. Documented since
|
|
98
|
+
* the callbacks guide first shipped, and until now not on the type or on the
|
|
99
|
+
* object: a handler that read `props.error` compiled and logged `undefined`.
|
|
100
|
+
*
|
|
95
101
|
* @group Models
|
|
96
102
|
*/
|
|
97
103
|
export type AfterSaveErrorProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = Omit<AfterSaveProps<M, USER>, "id"> & {
|
|
98
104
|
id?: string | number;
|
|
105
|
+
/**
|
|
106
|
+
* Whatever the save threw: a `RebaseApiError` when a `before*` callback
|
|
107
|
+
* or a validator refused it, otherwise the driver's error with the
|
|
108
|
+
* SQLSTATE in its cause chain. Not narrowed, because a callback may
|
|
109
|
+
* throw anything.
|
|
110
|
+
*/
|
|
111
|
+
error: unknown;
|
|
99
112
|
};
|
|
100
113
|
/**
|
|
101
114
|
* Parameters passed to hooks when a entity is saved
|
|
@@ -225,6 +225,13 @@ export type FilterValues<Key extends string> = Partial<Record<Key, [WhereFilterO
|
|
|
225
225
|
* closed. A typo'd relation path is refused at runtime with the target
|
|
226
226
|
* collection's real column list in the message.
|
|
227
227
|
*
|
|
228
|
+
* A JSON path — `metadata->>tier` — is admitted on the same terms and for the
|
|
229
|
+
* same reason. It addresses a key *inside* a `json`/`jsonb` column, so nothing
|
|
230
|
+
* in a generated row type describes it either; the driver resolves it and
|
|
231
|
+
* refuses what it cannot. It has no dot, so the dotted branch above never
|
|
232
|
+
* covered it, and every documented `?metadata->>tier=eq.gold` filter was a
|
|
233
|
+
* compile error on a typed client while working perfectly over HTTP.
|
|
234
|
+
*
|
|
228
235
|
* Undotted keys are unaffected and still checked against `keyof M`.
|
|
229
236
|
*
|
|
230
237
|
* When `M` is left at its default `Record<string, unknown>`, `keyof M` is
|
|
@@ -234,7 +241,23 @@ export type FilterValues<Key extends string> = Partial<Record<Key, [WhereFilterO
|
|
|
234
241
|
*
|
|
235
242
|
* @group Models
|
|
236
243
|
*/
|
|
237
|
-
export type FieldPath<M extends Record<string, unknown> = Record<string, unknown>> = Extract<keyof M, string> |
|
|
244
|
+
export type FieldPath<M extends Record<string, unknown> = Record<string, unknown>> = Extract<keyof M, string> | NonColumnFieldPath;
|
|
245
|
+
/**
|
|
246
|
+
* A field key that is not a column: a relation path (`author.name`) or a JSON
|
|
247
|
+
* path (`metadata->>tier`).
|
|
248
|
+
*
|
|
249
|
+
* The fluent builder needs this on its own, where `FindParams` does not. Its
|
|
250
|
+
* `where(column, operator, value)` types the value against `M[column]`, which
|
|
251
|
+
* only means something for a real column — so paths take a second overload
|
|
252
|
+
* whose value is `unknown`. Keying that overload on the *shape* of a path,
|
|
253
|
+
* rather than on "everything that is not a column", is what keeps a real column
|
|
254
|
+
* with a wrong value type from falling through to it and being accepted: a
|
|
255
|
+
* mistyped column name has neither a dot nor a `->>`, so it matches neither
|
|
256
|
+
* overload and is still refused.
|
|
257
|
+
*
|
|
258
|
+
* @group Models
|
|
259
|
+
*/
|
|
260
|
+
export type NonColumnFieldPath = `${string}.${string}` | `${string}->>${string}`;
|
|
238
261
|
/**
|
|
239
262
|
* Relaxed filter type that also accepts pre-serialized PostgREST strings.
|
|
240
263
|
* **Internal only** — used at the wire-format boundary
|
package/dist/types/policy.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @group Models
|
|
19
19
|
*/
|
|
20
|
-
export type PolicyExpression = TruePolicyExpression | FalsePolicyExpression | AndPolicyExpression | OrPolicyExpression | NotPolicyExpression | ComparePolicyExpression | RolesOverlapPolicyExpression | RolesContainPolicyExpression | AuthenticatedPolicyExpression | ServerContextPolicyExpression | ExistsInPolicyExpression | RawPolicyExpression;
|
|
20
|
+
export type PolicyExpression = TruePolicyExpression | FalsePolicyExpression | AndPolicyExpression | OrPolicyExpression | NotPolicyExpression | ComparePolicyExpression | RolesOverlapPolicyExpression | RolesContainPolicyExpression | AuthenticatedPolicyExpression | RegisteredPolicyExpression | ServerContextPolicyExpression | ExistsInPolicyExpression | RawPolicyExpression;
|
|
21
21
|
/**
|
|
22
22
|
* The id a request without a logged-in user reports as `rebase.uid()`.
|
|
23
23
|
*
|
|
@@ -137,6 +137,33 @@ export interface RolesContainPolicyExpression {
|
|
|
137
137
|
export interface AuthenticatedPolicyExpression {
|
|
138
138
|
kind: "authenticated";
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* True for a signed-in caller who has an ACCOUNT — not a guest.
|
|
142
|
+
*
|
|
143
|
+
* The distinction {@link AuthenticatedPolicyExpression} cannot make. Anonymous
|
|
144
|
+
* SIGN-IN (`POST /auth/anonymous`) mints a real user row with a real uid and a
|
|
145
|
+
* real session, so such a caller is "authenticated" by every test that looks at
|
|
146
|
+
* `rebase.uid()`: same shape, same default role, indistinguishable inside a
|
|
147
|
+
* policy. On a deployment with anonymous sign-in enabled, every rule meaning
|
|
148
|
+
* "a signed-in person" therefore also meant "anybody at all", since pressing
|
|
149
|
+
* Continue as guest needs no email, no password and no agreement to anything.
|
|
150
|
+
*
|
|
151
|
+
* Note the two senses of "anonymous", which is the reason this was easy to
|
|
152
|
+
* miss. {@link ANONYMOUS_USER_ID} is the sentinel for a request carrying NO
|
|
153
|
+
* session, and `authenticated()` already excludes it. A guest is the other
|
|
154
|
+
* thing: a session with nobody behind it. This node excludes both.
|
|
155
|
+
*
|
|
156
|
+
* Compiles to `authenticated() AND NOT rebase.is_anonymous()`.
|
|
157
|
+
*
|
|
158
|
+
* Use it wherever a rule is about a person who could be held responsible for
|
|
159
|
+
* something — writing a review, joining an organization, spending money. Use
|
|
160
|
+
* `authenticated()` where a guest is genuinely welcome, which is what
|
|
161
|
+
* anonymous sign-in is for: a cart before checkout, a draft before signup.
|
|
162
|
+
* @group Models
|
|
163
|
+
*/
|
|
164
|
+
export interface RegisteredPolicyExpression {
|
|
165
|
+
kind: "registered";
|
|
166
|
+
}
|
|
140
167
|
/**
|
|
141
168
|
* True only in the trusted **server context** — the built-in flows that run
|
|
142
169
|
* without a user (signup, migrations, `dataAsAdmin`) set no user GUC, so
|
|
@@ -255,6 +282,7 @@ export declare const policy: {
|
|
|
255
282
|
rolesOverlap: (roles: readonly string[]) => RolesOverlapPolicyExpression;
|
|
256
283
|
rolesContain: (roles: readonly string[]) => RolesContainPolicyExpression;
|
|
257
284
|
authenticated: () => AuthenticatedPolicyExpression;
|
|
285
|
+
registered: () => RegisteredPolicyExpression;
|
|
258
286
|
serverContext: () => ServerContextPolicyExpression;
|
|
259
287
|
existsIn: (args: {
|
|
260
288
|
collection: string;
|