@rebasepro/types 0.6.1 → 0.8.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 +69 -1
- package/dist/controllers/data.d.ts +19 -47
- package/dist/controllers/navigation.d.ts +14 -14
- package/dist/controllers/registry.d.ts +8 -4
- package/dist/index.es.js +164 -10
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +171 -9
- package/dist/index.umd.js.map +1 -1
- package/dist/types/api_keys.d.ts +57 -0
- package/dist/types/auth_adapter.d.ts +66 -4
- package/dist/types/backend.d.ts +5 -0
- package/dist/types/collections.d.ts +200 -90
- package/dist/types/data_source.d.ts +79 -3
- package/dist/types/entity_actions.d.ts +2 -2
- package/dist/types/entity_callbacks.d.ts +18 -6
- package/dist/types/entity_views.d.ts +1 -1
- package/dist/types/filter-operators.d.ts +108 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/plugins.d.ts +1 -1
- package/dist/types/policy.d.ts +137 -0
- package/dist/types/properties.d.ts +122 -37
- package/dist/types/property_config.d.ts +1 -1
- package/dist/types/storage_source.d.ts +83 -0
- package/dist/types/translations.d.ts +8 -0
- package/package.json +1 -1
- package/src/controllers/client.ts +69 -1
- package/src/controllers/data.ts +20 -59
- package/src/controllers/navigation.ts +17 -16
- package/src/controllers/registry.ts +10 -4
- package/src/types/api_keys.ts +52 -0
- package/src/types/auth_adapter.ts +80 -4
- package/src/types/backend.ts +6 -1
- package/src/types/collections.ts +235 -113
- package/src/types/data_source.ts +89 -5
- package/src/types/entity_actions.tsx +2 -2
- package/src/types/entity_callbacks.ts +18 -7
- package/src/types/entity_views.tsx +1 -1
- package/src/types/filter-operators.ts +167 -0
- package/src/types/index.ts +5 -2
- package/src/types/plugins.tsx +1 -1
- package/src/types/policy.ts +173 -0
- package/src/types/properties.ts +132 -39
- package/src/types/property_config.tsx +0 -1
- package/src/types/storage_source.ts +90 -0
- package/src/types/translations.ts +8 -0
- package/dist/types/backend_hooks.d.ts +0 -109
- package/dist/types/entity_overrides.d.ts +0 -10
- package/src/types/backend_hooks.ts +0 -114
- package/src/types/entity_overrides.tsx +0 -11
package/src/types/collections.ts
CHANGED
|
@@ -2,16 +2,18 @@ import React, { Dispatch, SetStateAction } from "react";
|
|
|
2
2
|
import type { Entity, EntityStatus, EntityValues } from "./entities";
|
|
3
3
|
import type { EntityCallbacks } from "./entity_callbacks";
|
|
4
4
|
|
|
5
|
-
import type { EnumValues, Properties } from "./properties";
|
|
5
|
+
import type { EnumValues, Properties, PostgresProperties, FirebaseProperties, MongoProperties } from "./properties";
|
|
6
6
|
import type { ExportConfig } from "./export_import";
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import type { User } from "../users";
|
|
9
9
|
import type { RebaseContext } from "../rebase_context";
|
|
10
10
|
import type { Relation } from "./relations";
|
|
11
11
|
import type { EntityCustomView, FormViewConfig } from "./entity_views";
|
|
12
12
|
import type { EntityAction } from "./entity_actions";
|
|
13
|
+
import type { PolicyExpression } from "./policy";
|
|
13
14
|
import type { ComponentRef } from "./component_ref";
|
|
14
15
|
import type { CollectionComponentOverrideMap } from "./component_overrides";
|
|
16
|
+
import type { WhereFilterOp, FilterValues, FilterPreset } from "./filter-operators";
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Base interface containing all driver-agnostic collection properties.
|
|
@@ -58,34 +60,45 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
|
|
|
58
60
|
|
|
59
61
|
|
|
60
62
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* - `"mongodb"` - Route to MongoDB backend
|
|
66
|
-
* - Custom IDs for your own driver implementations
|
|
63
|
+
* The data source this collection belongs to — the routing key shared by
|
|
64
|
+
* the frontend router and the backend driver registry. It points at a
|
|
65
|
+
* {@link DataSourceDefinition} registered on `<Rebase dataSources>` (front)
|
|
66
|
+
* and `initRebase({ dataSources })` (back).
|
|
67
67
|
*
|
|
68
|
-
* If not specified, the default
|
|
68
|
+
* If not specified, the default data source `"(default)"` is used, which
|
|
69
|
+
* for a standard Rebase app is the server-mediated Postgres backend.
|
|
69
70
|
*
|
|
70
71
|
* @example
|
|
71
|
-
* //
|
|
72
|
+
* // Default data source (server-mediated Postgres)
|
|
72
73
|
* { slug: "products" }
|
|
73
74
|
*
|
|
74
|
-
* // Firestore
|
|
75
|
-
* { slug: "
|
|
75
|
+
* // A direct-transport Firestore data source registered as "analytics"
|
|
76
|
+
* { slug: "events", dataSource: "analytics" }
|
|
77
|
+
*/
|
|
78
|
+
dataSource?: string;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The database engine backing this collection (`"postgres"`, `"firestore"`,
|
|
82
|
+
* `"mongodb"`, or a custom id).
|
|
76
83
|
*
|
|
77
|
-
*
|
|
78
|
-
* {
|
|
84
|
+
* On concrete collection types ({@link PostgresCollection},
|
|
85
|
+
* {@link FirebaseCollection}, {@link MongoDBCollection}) this is a literal
|
|
86
|
+
* discriminant. On the base type it is optional and gets stamped
|
|
87
|
+
* automatically during collection normalization from the registered
|
|
88
|
+
* {@link DataSourceDefinition}.
|
|
89
|
+
*
|
|
90
|
+
* Prefer setting {@link dataSource} and letting the engine be resolved.
|
|
79
91
|
*/
|
|
80
|
-
|
|
92
|
+
engine?: string;
|
|
81
93
|
|
|
82
94
|
/**
|
|
83
|
-
* Which database within the
|
|
95
|
+
* Which database within the engine.
|
|
84
96
|
* - For Firestore: The Firestore database ID (e.g., for multi-database projects)
|
|
85
97
|
* - For PostgreSQL: Schema or database name
|
|
86
98
|
* - For MongoDB: Database name
|
|
87
99
|
*
|
|
88
|
-
* If not specified, the default database of the
|
|
100
|
+
* If not specified, the default database of the engine is used. Resolved
|
|
101
|
+
* from the collection's {@link DataSourceDefinition} when omitted here.
|
|
89
102
|
*/
|
|
90
103
|
databaseId?: string;
|
|
91
104
|
|
|
@@ -165,6 +178,26 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
|
|
|
165
178
|
*/
|
|
166
179
|
auth?: boolean | AuthCollectionConfig;
|
|
167
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Opt out of the framework's default Row Level Security policies for
|
|
183
|
+
* authentication collections.
|
|
184
|
+
*
|
|
185
|
+
* When a collection has `auth` enabled, the schema generator automatically
|
|
186
|
+
* injects an admin-only write policy (INSERT/UPDATE/DELETE require the
|
|
187
|
+
* `admin` role, or the trusted server context) for any write operation that
|
|
188
|
+
* the collection does not already cover with an explicit `securityRules`
|
|
189
|
+
* entry. This makes privileged columns such as `roles` safe by default — a
|
|
190
|
+
* non-admin cannot modify the user row through the data API regardless of
|
|
191
|
+
* which code path issues the write.
|
|
192
|
+
*
|
|
193
|
+
* Defining your own write rule for an operation overrides the default for
|
|
194
|
+
* that operation. Set this flag to `true` to remove the default policies
|
|
195
|
+
* entirely and take full responsibility for the collection's RLS.
|
|
196
|
+
*
|
|
197
|
+
* @default false
|
|
198
|
+
*/
|
|
199
|
+
disableDefaultAuthPolicies?: boolean;
|
|
200
|
+
|
|
168
201
|
|
|
169
202
|
/**
|
|
170
203
|
* Order in which the properties are displayed.
|
|
@@ -269,8 +302,8 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
|
|
|
269
302
|
|
|
270
303
|
/**
|
|
271
304
|
* Can the elements in this collection be edited inline in the collection
|
|
272
|
-
* view.
|
|
273
|
-
*
|
|
305
|
+
* view. Even when inline editing is disabled, entities can still be
|
|
306
|
+
* edited in the side panel (subject to `securityRules`).
|
|
274
307
|
*/
|
|
275
308
|
inlineEditing?: boolean;
|
|
276
309
|
|
|
@@ -322,9 +355,11 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
|
|
|
322
355
|
ownerId?: string;
|
|
323
356
|
|
|
324
357
|
/**
|
|
325
|
-
*
|
|
358
|
+
* Arbitrary key-value metadata for external consumers.
|
|
359
|
+
* Not interpreted by Rebase — passed through serialization unchanged.
|
|
360
|
+
* Used by domain apps to store custom per-collection config.
|
|
326
361
|
*/
|
|
327
|
-
|
|
362
|
+
metadata?: Record<string, unknown>;
|
|
328
363
|
|
|
329
364
|
/**
|
|
330
365
|
* Width of the side dialog (in pixels) when opening an entity in this collection.
|
|
@@ -375,7 +410,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
|
|
|
375
410
|
* Possible values: "table", "cards", "kanban".
|
|
376
411
|
* Defaults to all three: ["table", "cards", "kanban"].
|
|
377
412
|
* Note: "kanban" will only be available if the collection has at least
|
|
378
|
-
* one string property with
|
|
413
|
+
* one string property with `enum` defined, regardless of this setting.
|
|
379
414
|
*/
|
|
380
415
|
enabledViews?: ViewMode[];
|
|
381
416
|
|
|
@@ -464,13 +499,13 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
|
|
|
464
499
|
*/
|
|
465
500
|
export interface PostgresCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
|
|
466
501
|
extends BaseEntityCollection<M, USER> {
|
|
467
|
-
properties:
|
|
502
|
+
properties: PostgresProperties;
|
|
468
503
|
|
|
469
504
|
/**
|
|
470
|
-
* The
|
|
505
|
+
* The database engine for this collection. For Postgres collections this
|
|
471
506
|
* can be omitted (Postgres is the default) or set to `"postgres"`.
|
|
472
507
|
*/
|
|
473
|
-
|
|
508
|
+
engine?: "postgres" | undefined;
|
|
474
509
|
|
|
475
510
|
/**
|
|
476
511
|
* The PostgreSQL table name for this collection.
|
|
@@ -520,9 +555,33 @@ export interface PostgresCollection<M extends Record<string, unknown> = Record<s
|
|
|
520
555
|
export interface FirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
|
|
521
556
|
extends BaseEntityCollection<M, USER> {
|
|
522
557
|
/**
|
|
523
|
-
* The
|
|
558
|
+
* The database engine for this collection. Must be set to `"firestore"`.
|
|
524
559
|
*/
|
|
525
|
-
|
|
560
|
+
engine: "firestore";
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Set of properties that compose an entity.
|
|
564
|
+
* Firestore collections support `reference` properties but not `relation`.
|
|
565
|
+
*/
|
|
566
|
+
properties: FirebaseProperties;
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* The Firestore collection path to query. Defaults to `slug` if not set.
|
|
570
|
+
* Use this when the Firestore path differs from the slug
|
|
571
|
+
* (e.g., when a PostgreSQL collection already uses the same slug).
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```typescript
|
|
575
|
+
* const fsCustomer: FirebaseCollection = {
|
|
576
|
+
* slug: "fs_customer", // URL: /c/fs_customer
|
|
577
|
+
* path: "customer", // Firestore path: customer
|
|
578
|
+
* name: "Customers (Firestore)",
|
|
579
|
+
* engine: "firestore",
|
|
580
|
+
* properties: { ... }
|
|
581
|
+
* };
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
path?: string;
|
|
526
585
|
|
|
527
586
|
/**
|
|
528
587
|
* You can add subcollections to your entity in the same way you define the root
|
|
@@ -544,9 +603,33 @@ export interface MongoDBCollection<M extends Record<string, unknown> = Record<st
|
|
|
544
603
|
extends BaseEntityCollection<M, USER> {
|
|
545
604
|
|
|
546
605
|
/**
|
|
547
|
-
* The
|
|
606
|
+
* The database engine for this collection. Must be set to `"mongodb"`.
|
|
607
|
+
*/
|
|
608
|
+
engine: "mongodb";
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Set of properties that compose an entity.
|
|
612
|
+
* MongoDB collections support `reference` properties but not `relation`.
|
|
548
613
|
*/
|
|
549
|
-
|
|
614
|
+
properties: MongoProperties;
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* The MongoDB collection name to use. Defaults to `slug` if not set.
|
|
618
|
+
* Use this when the MongoDB collection name differs from the slug
|
|
619
|
+
* (e.g., when a PostgreSQL collection already uses the same slug).
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```typescript
|
|
623
|
+
* const mongoCustomer: MongoDBCollection = {
|
|
624
|
+
* slug: "mongo_customer", // URL: /c/mongo_customer
|
|
625
|
+
* path: "customer", // MongoDB collection: customer
|
|
626
|
+
* name: "Customers (MongoDB)",
|
|
627
|
+
* engine: "mongodb",
|
|
628
|
+
* properties: { ... }
|
|
629
|
+
* };
|
|
630
|
+
* ```
|
|
631
|
+
*/
|
|
632
|
+
path?: string;
|
|
550
633
|
}
|
|
551
634
|
|
|
552
635
|
/**
|
|
@@ -562,33 +645,15 @@ export type EntityCollection<M extends Record<string, unknown> = Record<string,
|
|
|
562
645
|
| FirebaseCollection<M, USER>
|
|
563
646
|
| MongoDBCollection<M, USER>;
|
|
564
647
|
|
|
565
|
-
// ── Capability intersection types ─────────────────────────────────────
|
|
566
|
-
// Use these after a `getDataSourceCapabilities()` guard to safely access
|
|
567
|
-
// driver-specific fields without coupling to a concrete driver type.
|
|
568
|
-
|
|
569
|
-
/**
|
|
570
|
-
* An EntityCollection that supports SQL-style relations (e.g. Postgres).
|
|
571
|
-
* @deprecated Use `EntityCollection` directly — `table`, `relations`, and `securityRules` are now on `BaseEntityCollection`.
|
|
572
|
-
*/
|
|
573
|
-
export type CollectionWithRelations<M extends Record<string, unknown> = Record<string, unknown>> =
|
|
574
|
-
EntityCollection<M> & { table?: string; relations?: Relation[]; securityRules?: SecurityRule[] };
|
|
575
|
-
|
|
576
|
-
/** An EntityCollection that supports subcollections (e.g. Firestore). */
|
|
577
|
-
export type CollectionWithSubcollections<M extends Record<string, unknown> = Record<string, unknown>> =
|
|
578
|
-
EntityCollection<M> & { subcollections?: () => EntityCollection<Record<string, unknown>>[] };
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
// ── Type guards ───────────────────────────────────────────────────────
|
|
582
|
-
|
|
583
648
|
/**
|
|
584
649
|
* Type guard for PostgreSQL collections.
|
|
585
|
-
* Returns true if the collection uses the Postgres
|
|
650
|
+
* Returns true if the collection uses the Postgres engine (or the default engine).
|
|
586
651
|
* @group Models
|
|
587
652
|
*/
|
|
588
653
|
export function isPostgresCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
|
|
589
654
|
collection: EntityCollection<M, USER>
|
|
590
655
|
): collection is PostgresCollection<M, USER> {
|
|
591
|
-
return !collection.
|
|
656
|
+
return !collection.engine || collection.engine === "postgres";
|
|
592
657
|
}
|
|
593
658
|
|
|
594
659
|
/**
|
|
@@ -598,7 +663,7 @@ export function isPostgresCollection<M extends Record<string, unknown> = Record<
|
|
|
598
663
|
export function isFirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
|
|
599
664
|
collection: EntityCollection<M, USER>
|
|
600
665
|
): collection is FirebaseCollection<M, USER> {
|
|
601
|
-
return collection.
|
|
666
|
+
return collection.engine === "firestore";
|
|
602
667
|
}
|
|
603
668
|
|
|
604
669
|
/**
|
|
@@ -608,7 +673,40 @@ export function isFirebaseCollection<M extends Record<string, unknown> = Record<
|
|
|
608
673
|
export function isMongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
|
|
609
674
|
collection: EntityCollection<M, USER>
|
|
610
675
|
): collection is MongoDBCollection<M, USER> {
|
|
611
|
-
return collection.
|
|
676
|
+
return collection.engine === "mongodb";
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Returns the data path for a collection.
|
|
681
|
+
* For Firestore or MongoDB collections with a `path`, returns that value;
|
|
682
|
+
* otherwise falls back to `slug`.
|
|
683
|
+
*/
|
|
684
|
+
export function getCollectionDataPath<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
|
|
685
|
+
collection: EntityCollection<M, USER>
|
|
686
|
+
): string {
|
|
687
|
+
if (isFirebaseCollection(collection) && collection.path) {
|
|
688
|
+
return collection.path;
|
|
689
|
+
}
|
|
690
|
+
if (isMongoDBCollection(collection) && collection.path) {
|
|
691
|
+
return collection.path;
|
|
692
|
+
}
|
|
693
|
+
return collection.slug;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Reads a collection's driver-declared subcollections thunk (the `subcollections`
|
|
698
|
+
* field) independent of engine identity, so engine-agnostic code doesn't have to
|
|
699
|
+
* type-guard against a specific driver. Returns `undefined` when the collection
|
|
700
|
+
* declares none.
|
|
701
|
+
*
|
|
702
|
+
* Pair with `getDataSourceCapabilities(engine).supportsSubcollections` to decide
|
|
703
|
+
* whether the engine honours subcollections at all before reading them.
|
|
704
|
+
* @group Models
|
|
705
|
+
*/
|
|
706
|
+
export function getDeclaredSubcollections<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
|
|
707
|
+
collection: EntityCollection<M, USER>
|
|
708
|
+
): (() => EntityCollection<Record<string, unknown>>[]) | undefined {
|
|
709
|
+
return (collection as FirebaseCollection<M, USER>).subcollections;
|
|
612
710
|
}
|
|
613
711
|
|
|
614
712
|
|
|
@@ -619,9 +717,9 @@ export function isMongoDBCollection<M extends Record<string, unknown> = Record<s
|
|
|
619
717
|
export interface KanbanConfig<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
620
718
|
/**
|
|
621
719
|
* Property key to use for Kanban board columns.
|
|
622
|
-
* Must reference a string property with
|
|
720
|
+
* Must reference a string property with `enum` values defined.
|
|
623
721
|
* Entities will be grouped into columns based on this property's value.
|
|
624
|
-
* The column order is determined by the order of
|
|
722
|
+
* The column order is determined by the order of `enum` values in the property.
|
|
625
723
|
*/
|
|
626
724
|
columnProperty: Extract<keyof M, string> | (string & {});
|
|
627
725
|
}
|
|
@@ -720,57 +818,8 @@ export interface SelectionController<M extends Record<string, unknown> = Record<
|
|
|
720
818
|
toggleEntitySelection(entity: Entity<M>, newSelectedState?: boolean): void;
|
|
721
819
|
}
|
|
722
820
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
* strings `<`, `<=`, `==`, `>=`, `>`, `array-contains`, `in`, and `array-contains-any`.
|
|
726
|
-
* @group Models
|
|
727
|
-
*/
|
|
728
|
-
export type WhereFilterOp =
|
|
729
|
-
| "<"
|
|
730
|
-
| "<="
|
|
731
|
-
| "=="
|
|
732
|
-
| "!="
|
|
733
|
-
| ">="
|
|
734
|
-
| ">"
|
|
735
|
-
| "array-contains"
|
|
736
|
-
| "in"
|
|
737
|
-
| "not-in"
|
|
738
|
-
| "array-contains-any";
|
|
739
|
-
|
|
740
|
-
/**
|
|
741
|
-
* Used to define filters applied in collections
|
|
742
|
-
*
|
|
743
|
-
* e.g. `{ age: [">=", 18] }`
|
|
744
|
-
*
|
|
745
|
-
* @group Models
|
|
746
|
-
*/
|
|
747
|
-
export type FilterValues<Key extends string> =
|
|
748
|
-
Partial<Record<Key, [WhereFilterOp, unknown] | [WhereFilterOp, unknown][]>>;
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* A pre-defined filter preset for quick access in the collection toolbar.
|
|
752
|
-
* Users can select a preset to instantly apply a set of filters and
|
|
753
|
-
* optionally a sort order.
|
|
754
|
-
*
|
|
755
|
-
* @group Models
|
|
756
|
-
*/
|
|
757
|
-
export interface FilterPreset<Key extends string = string> {
|
|
758
|
-
/**
|
|
759
|
-
* Display label shown in the preset menu.
|
|
760
|
-
* If omitted, a summary is auto-generated from the filter keys.
|
|
761
|
-
*/
|
|
762
|
-
label?: string;
|
|
763
|
-
|
|
764
|
-
/**
|
|
765
|
-
* The filter values to apply when this preset is selected.
|
|
766
|
-
*/
|
|
767
|
-
filterValues: FilterValues<Key>;
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
* Optional sort override to apply alongside the filter values.
|
|
771
|
-
*/
|
|
772
|
-
sort?: [Key, "asc" | "desc"];
|
|
773
|
-
}
|
|
821
|
+
// Canonical filter types — re-exported from the single source-of-truth.
|
|
822
|
+
export type { WhereFilterOp, FilterValues, WireFilterValues, FilterPreset } from "./filter-operators";
|
|
774
823
|
|
|
775
824
|
|
|
776
825
|
/**
|
|
@@ -927,13 +976,26 @@ export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all
|
|
|
927
976
|
* operation. Permissive rules are OR'd together (any one passing is enough).
|
|
928
977
|
* Restrictive rules are AND'd (all must pass). This mirrors Supabase behavior.
|
|
929
978
|
*
|
|
930
|
-
* **Mutual exclusivity:** `ownerField`, `access`,
|
|
931
|
-
* cannot be combined. The type system enforces
|
|
932
|
-
* conflicting fields will produce a compile-time
|
|
979
|
+
* **Mutual exclusivity:** `ownerField`, `access`, structured `condition`, and
|
|
980
|
+
* raw SQL (`using`/`withCheck`) cannot be combined. The type system enforces
|
|
981
|
+
* this — attempting to set conflicting fields will produce a compile-time
|
|
982
|
+
* error.
|
|
983
|
+
*
|
|
984
|
+
* **Which form to reach for:** prefer the structured {@link StructuredSecurityRule}
|
|
985
|
+
* (`condition`/`check`) or the shortcuts (`ownerField`, `access`, `roles`). These
|
|
986
|
+
* are engine-agnostic and evaluated identically by the database and the admin UI,
|
|
987
|
+
* so the UI never shows an action the database will reject. Raw SQL
|
|
988
|
+
* ({@link RawSQLSecurityRule}) keeps full PostgreSQL power but is Postgres-only
|
|
989
|
+
* and server-authoritative (the UI cannot evaluate arbitrary SQL locally).
|
|
933
990
|
*
|
|
934
991
|
* @group Models
|
|
935
992
|
*/
|
|
936
|
-
export type SecurityRule =
|
|
993
|
+
export type SecurityRule =
|
|
994
|
+
| OwnerSecurityRule
|
|
995
|
+
| PublicSecurityRule
|
|
996
|
+
| StructuredSecurityRule
|
|
997
|
+
| RawSQLSecurityRule
|
|
998
|
+
| RolesOnlySecurityRule;
|
|
937
999
|
|
|
938
1000
|
/**
|
|
939
1001
|
* Shared fields for all SecurityRule variants.
|
|
@@ -1003,11 +1065,16 @@ export interface SecurityRuleBase {
|
|
|
1003
1065
|
* application roles managed by Rebase, stored in the `rebase.user_roles`
|
|
1004
1066
|
* table, and injected into each transaction via `auth.roles()`.
|
|
1005
1067
|
*
|
|
1006
|
-
* Generates a condition
|
|
1007
|
-
*
|
|
1068
|
+
* Generates a safe array-overlap condition — the user passes if they hold
|
|
1069
|
+
* *any* of the listed roles:
|
|
1070
|
+
* `string_to_array(auth.roles(), ',') && ARRAY['<role1>', '<role2>']`
|
|
1008
1071
|
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1072
|
+
* (Note: this is a true set intersection, NOT a regex/substring match, so
|
|
1073
|
+
* a role named `admin` never matches `nonadmin` or `superadmin`.)
|
|
1074
|
+
*
|
|
1075
|
+
* Can be combined with `ownerField`, `access`, `condition`, or raw
|
|
1076
|
+
* `using`/`withCheck`. When combined, the role check is AND'd with the
|
|
1077
|
+
* other condition.
|
|
1011
1078
|
*
|
|
1012
1079
|
* @example
|
|
1013
1080
|
* // Only admins can delete
|
|
@@ -1062,6 +1129,8 @@ export interface OwnerSecurityRule extends SecurityRuleBase {
|
|
|
1062
1129
|
access?: never;
|
|
1063
1130
|
using?: never;
|
|
1064
1131
|
withCheck?: never;
|
|
1132
|
+
condition?: never;
|
|
1133
|
+
check?: never;
|
|
1065
1134
|
}
|
|
1066
1135
|
|
|
1067
1136
|
/**
|
|
@@ -1086,12 +1155,61 @@ export interface PublicSecurityRule extends SecurityRuleBase {
|
|
|
1086
1155
|
ownerField?: never;
|
|
1087
1156
|
using?: never;
|
|
1088
1157
|
withCheck?: never;
|
|
1158
|
+
condition?: never;
|
|
1159
|
+
check?: never;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Security rule expressed as a structured, engine-agnostic
|
|
1164
|
+
* {@link PolicyExpression}. This is the **recommended** way to write a
|
|
1165
|
+
* non-trivial condition: it compiles to PostgreSQL `USING`/`WITH CHECK` SQL
|
|
1166
|
+
* *and* is evaluated identically by the admin UI, so the UI can never show an
|
|
1167
|
+
* action the database will reject.
|
|
1168
|
+
*
|
|
1169
|
+
* Cannot be combined with `ownerField`, `access`, or raw `using`/`withCheck`.
|
|
1170
|
+
*
|
|
1171
|
+
* @example
|
|
1172
|
+
* // Owner, or any user holding the `moderator` role
|
|
1173
|
+
* {
|
|
1174
|
+
* operation: "update",
|
|
1175
|
+
* condition: policy.or(
|
|
1176
|
+
* policy.compare(policy.field("user_id"), "eq", policy.authUid()),
|
|
1177
|
+
* policy.rolesOverlap(["moderator"])
|
|
1178
|
+
* )
|
|
1179
|
+
* }
|
|
1180
|
+
*
|
|
1181
|
+
* @group Models
|
|
1182
|
+
*/
|
|
1183
|
+
export interface StructuredSecurityRule extends SecurityRuleBase {
|
|
1184
|
+
/**
|
|
1185
|
+
* Structured condition for the `USING` clause — which *existing* rows are
|
|
1186
|
+
* visible / can be modified / deleted (SELECT, UPDATE, DELETE).
|
|
1187
|
+
*/
|
|
1188
|
+
condition: PolicyExpression;
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* Structured condition for the `WITH CHECK` clause — which *new/updated*
|
|
1192
|
+
* row values are allowed (INSERT, UPDATE). Defaults to `condition` when
|
|
1193
|
+
* omitted, mirroring PostgreSQL's own behavior.
|
|
1194
|
+
*/
|
|
1195
|
+
check?: PolicyExpression;
|
|
1196
|
+
|
|
1197
|
+
ownerField?: never;
|
|
1198
|
+
access?: never;
|
|
1199
|
+
using?: never;
|
|
1200
|
+
withCheck?: never;
|
|
1089
1201
|
}
|
|
1090
1202
|
|
|
1091
1203
|
/**
|
|
1092
1204
|
* Security rule using raw SQL expressions for full PostgreSQL RLS power.
|
|
1093
1205
|
*
|
|
1094
|
-
*
|
|
1206
|
+
* **Postgres-only and server-authoritative.** Arbitrary SQL cannot be
|
|
1207
|
+
* evaluated by the admin UI, so a rule using this form is treated as *unknown*
|
|
1208
|
+
* client-side (never silently allowed) and its effect on visible actions is
|
|
1209
|
+
* reflected from the server. For conditions that should also drive the UI
|
|
1210
|
+
* precisely, prefer the structured {@link StructuredSecurityRule}.
|
|
1211
|
+
*
|
|
1212
|
+
* Cannot be combined with `ownerField`, `access`, or structured `condition`.
|
|
1095
1213
|
*
|
|
1096
1214
|
* You can reference columns via `{column_name}` which will be resolved to
|
|
1097
1215
|
* `table.column_name` in the generated Drizzle code.
|
|
@@ -1129,6 +1247,8 @@ export interface RawSQLSecurityRule extends SecurityRuleBase {
|
|
|
1129
1247
|
|
|
1130
1248
|
ownerField?: never;
|
|
1131
1249
|
access?: never;
|
|
1250
|
+
condition?: never;
|
|
1251
|
+
check?: never;
|
|
1132
1252
|
}
|
|
1133
1253
|
|
|
1134
1254
|
/**
|
|
@@ -1149,6 +1269,8 @@ export interface RolesOnlySecurityRule extends SecurityRuleBase {
|
|
|
1149
1269
|
access?: never;
|
|
1150
1270
|
using?: never;
|
|
1151
1271
|
withCheck?: never;
|
|
1272
|
+
condition?: never;
|
|
1273
|
+
check?: never;
|
|
1152
1274
|
}
|
|
1153
1275
|
|
|
1154
1276
|
/**
|
package/src/types/data_source.ts
CHANGED
|
@@ -53,6 +53,90 @@ export interface DataSourceCapabilities {
|
|
|
53
53
|
*/
|
|
54
54
|
export type DataSourceFeatures = Omit<DataSourceCapabilities, "key" | "label">;
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* The default data-source key, used when a collection does not name a
|
|
58
|
+
* `dataSource`. Shared by the frontend router and the backend driver
|
|
59
|
+
* registry so both agree on "the default database".
|
|
60
|
+
* @group Models
|
|
61
|
+
*/
|
|
62
|
+
export const DEFAULT_DATA_SOURCE_KEY = "(default)";
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* How the *frontend* reaches a data source.
|
|
66
|
+
*
|
|
67
|
+
* - `"server"` — through the Rebase backend (the `RebaseClient`). The backend
|
|
68
|
+
* holds the actual database adapter and routes by data-source key. This is
|
|
69
|
+
* the default and covers Postgres, MongoDB, and any other server-mediated
|
|
70
|
+
* engine.
|
|
71
|
+
* - `"direct"` — straight from the client to the external backend via its own
|
|
72
|
+
* SDK driver (e.g. Firestore). The Rebase backend is not in the data path.
|
|
73
|
+
* - `"custom"` — a developer-supplied {@link DataDriver}, transport unspecified.
|
|
74
|
+
*
|
|
75
|
+
* @group Models
|
|
76
|
+
*/
|
|
77
|
+
export type DataSourceTransport = "server" | "direct" | "custom";
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Declarative definition of a data source — a named place data lives.
|
|
81
|
+
*
|
|
82
|
+
* Declared once and shared front and back: the frontend uses it to decide
|
|
83
|
+
* transport (client vs direct driver), the backend uses the same `key` to
|
|
84
|
+
* resolve a database adapter, and the editor derives capabilities from
|
|
85
|
+
* `engine`. Collections reference a definition by its `key` via
|
|
86
|
+
* `collection.dataSource`.
|
|
87
|
+
*
|
|
88
|
+
* @group Models
|
|
89
|
+
*/
|
|
90
|
+
export interface DataSourceDefinition {
|
|
91
|
+
/**
|
|
92
|
+
* Unique identifier for this data source. Collections point at it via
|
|
93
|
+
* `dataSource`. Defaults to {@link DEFAULT_DATA_SOURCE_KEY}.
|
|
94
|
+
*/
|
|
95
|
+
key: string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The engine backing this data source (e.g. `"postgres"`, `"mongodb"`,
|
|
99
|
+
* `"firestore"`, or a custom id). Determines the
|
|
100
|
+
* {@link DataSourceCapabilities} surfaced in the editor.
|
|
101
|
+
*/
|
|
102
|
+
engine: string;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* How the frontend reaches this source. Defaults to `"server"`.
|
|
106
|
+
*/
|
|
107
|
+
transport: DataSourceTransport;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The physical database/schema/Firestore-database within the engine.
|
|
111
|
+
* Threaded to drivers/adapters as the existing `databaseId` runtime
|
|
112
|
+
* parameter. Defaults to the engine's own default.
|
|
113
|
+
*/
|
|
114
|
+
databaseId?: string;
|
|
115
|
+
|
|
116
|
+
/** Human-readable label for the UI. */
|
|
117
|
+
label?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The resolved data source for a collection: the single source of truth that
|
|
122
|
+
* the frontend router, backend registry, and editor all derive from.
|
|
123
|
+
* Produced by `resolveDataSource(collection, registry)`.
|
|
124
|
+
*
|
|
125
|
+
* @group Models
|
|
126
|
+
*/
|
|
127
|
+
export interface ResolvedDataSource {
|
|
128
|
+
/** Data-source key (routing key, shared front + back). */
|
|
129
|
+
key: string;
|
|
130
|
+
/** Engine backing the source (drives capabilities). */
|
|
131
|
+
engine: string;
|
|
132
|
+
/** Frontend transport. */
|
|
133
|
+
transport: DataSourceTransport;
|
|
134
|
+
/** Within-engine instance, if any (the `databaseId` runtime param). */
|
|
135
|
+
databaseId?: string;
|
|
136
|
+
/** Capabilities derived from {@link engine}. */
|
|
137
|
+
capabilities: DataSourceCapabilities;
|
|
138
|
+
}
|
|
139
|
+
|
|
56
140
|
// ── Built-in driver capabilities ─────────────────────────────────────
|
|
57
141
|
|
|
58
142
|
/** @group Models */
|
|
@@ -127,13 +211,13 @@ const CAPABILITIES_REGISTRY: Record<string, DataSourceCapabilities> = {
|
|
|
127
211
|
};
|
|
128
212
|
|
|
129
213
|
/**
|
|
130
|
-
* Look up capabilities for a given
|
|
131
|
-
* If `
|
|
214
|
+
* Look up capabilities for a given engine key.
|
|
215
|
+
* If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
|
|
132
216
|
* @group Models
|
|
133
217
|
*/
|
|
134
|
-
export function getDataSourceCapabilities(
|
|
135
|
-
if (!
|
|
136
|
-
return CAPABILITIES_REGISTRY[
|
|
218
|
+
export function getDataSourceCapabilities(engine?: string): DataSourceCapabilities {
|
|
219
|
+
if (!engine) return POSTGRES_CAPABILITIES; // postgres is the default engine
|
|
220
|
+
return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
|
|
137
221
|
}
|
|
138
222
|
|
|
139
223
|
/**
|
|
@@ -69,7 +69,7 @@ export interface EntityAction<M extends Record<string, unknown> = Record<string,
|
|
|
69
69
|
|
|
70
70
|
export type EntityActionClickProps<M extends Record<string, unknown>, USER extends User = User> = {
|
|
71
71
|
entity?: Entity<M>;
|
|
72
|
-
context
|
|
72
|
+
context?: RebaseContext<USER>;
|
|
73
73
|
|
|
74
74
|
path?: string;
|
|
75
75
|
collection?: EntityCollection<M>;
|
|
@@ -93,7 +93,7 @@ export type EntityActionClickProps<M extends Record<string, unknown>, USER exten
|
|
|
93
93
|
/**
|
|
94
94
|
* If the action is rendered in the form, is it open in a side panel or full screen?
|
|
95
95
|
*/
|
|
96
|
-
openEntityMode
|
|
96
|
+
openEntityMode?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
99
|
* Optional selection controller, present if the action is being called from a collection view
|