@rebasepro/types 0.8.0 → 0.9.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.
Files changed (78) hide show
  1. package/README.md +10 -10
  2. package/dist/controllers/auth.d.ts +1 -1
  3. package/dist/controllers/client.d.ts +184 -6
  4. package/dist/controllers/collection_registry.d.ts +3 -3
  5. package/dist/controllers/customization_controller.d.ts +1 -1
  6. package/dist/controllers/data.d.ts +267 -35
  7. package/dist/controllers/data_driver.d.ts +50 -37
  8. package/dist/controllers/index.d.ts +1 -1
  9. package/dist/controllers/local_config_persistence.d.ts +4 -4
  10. package/dist/controllers/navigation.d.ts +2 -2
  11. package/dist/controllers/registry.d.ts +17 -4
  12. package/dist/controllers/{side_entity_controller.d.ts → side_panel_controller.d.ts} +7 -7
  13. package/dist/controllers/storage.d.ts +39 -0
  14. package/dist/errors.d.ts +64 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.es.js +142 -15
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/index.umd.js +150 -17
  19. package/dist/index.umd.js.map +1 -1
  20. package/dist/rebase_context.d.ts +8 -4
  21. package/dist/types/auth_adapter.d.ts +4 -1
  22. package/dist/types/backend.d.ts +26 -26
  23. package/dist/types/builders.d.ts +2 -2
  24. package/dist/types/collections.d.ts +62 -63
  25. package/dist/types/component_overrides.d.ts +61 -3
  26. package/dist/types/cron.d.ts +10 -1
  27. package/dist/types/data_source.d.ts +15 -2
  28. package/dist/types/database_adapter.d.ts +4 -3
  29. package/dist/types/entities.d.ts +7 -7
  30. package/dist/types/entity_actions.d.ts +7 -7
  31. package/dist/types/entity_callbacks.d.ts +39 -39
  32. package/dist/types/entity_views.d.ts +3 -3
  33. package/dist/types/filter-operators.d.ts +62 -17
  34. package/dist/types/modify_collections.d.ts +2 -2
  35. package/dist/types/plugins.d.ts +9 -9
  36. package/dist/types/policy.d.ts +64 -10
  37. package/dist/types/properties.d.ts +41 -9
  38. package/dist/types/relations.d.ts +3 -3
  39. package/dist/types/slots.d.ts +14 -14
  40. package/dist/types/websockets.d.ts +12 -13
  41. package/dist/users/user.d.ts +21 -9
  42. package/package.json +1 -1
  43. package/src/controllers/auth.tsx +1 -1
  44. package/src/controllers/client.ts +214 -6
  45. package/src/controllers/collection_registry.ts +3 -3
  46. package/src/controllers/customization_controller.tsx +1 -1
  47. package/src/controllers/data.ts +290 -39
  48. package/src/controllers/data_driver.ts +49 -40
  49. package/src/controllers/index.ts +1 -1
  50. package/src/controllers/local_config_persistence.tsx +4 -4
  51. package/src/controllers/navigation.ts +2 -2
  52. package/src/controllers/registry.ts +18 -4
  53. package/src/controllers/{side_entity_controller.tsx → side_panel_controller.tsx} +7 -7
  54. package/src/controllers/storage.ts +60 -1
  55. package/src/errors.ts +80 -0
  56. package/src/index.ts +1 -0
  57. package/src/rebase_context.tsx +8 -4
  58. package/src/types/auth_adapter.ts +4 -1
  59. package/src/types/backend.ts +36 -36
  60. package/src/types/builders.ts +2 -2
  61. package/src/types/collections.ts +78 -79
  62. package/src/types/component_overrides.ts +72 -5
  63. package/src/types/cron.ts +10 -1
  64. package/src/types/data_source.ts +24 -2
  65. package/src/types/database_adapter.ts +4 -3
  66. package/src/types/entities.ts +7 -7
  67. package/src/types/entity_actions.tsx +7 -7
  68. package/src/types/entity_callbacks.ts +42 -42
  69. package/src/types/entity_views.tsx +3 -3
  70. package/src/types/filter-operators.ts +96 -23
  71. package/src/types/modify_collections.tsx +2 -2
  72. package/src/types/plugins.tsx +9 -9
  73. package/src/types/policy.ts +64 -8
  74. package/src/types/properties.ts +44 -9
  75. package/src/types/relations.ts +3 -3
  76. package/src/types/slots.tsx +14 -14
  77. package/src/types/websockets.ts +12 -14
  78. package/src/users/user.ts +22 -9
@@ -1,6 +1,6 @@
1
1
  import React, { Dispatch, SetStateAction } from "react";
2
2
  import type { Entity, EntityStatus, EntityValues } from "./entities";
3
- import type { EntityCallbacks } from "./entity_callbacks";
3
+ import type { CollectionCallbacks } from "./entity_callbacks";
4
4
 
5
5
  import type { EnumValues, Properties, PostgresProperties, FirebaseProperties, MongoProperties } from "./properties";
6
6
  import type { ExportConfig } from "./export_import";
@@ -13,17 +13,17 @@ import type { EntityAction } from "./entity_actions";
13
13
  import type { PolicyExpression } from "./policy";
14
14
  import type { ComponentRef } from "./component_ref";
15
15
  import type { CollectionComponentOverrideMap } from "./component_overrides";
16
- import type { WhereFilterOp, FilterValues, FilterPreset } from "./filter-operators";
16
+ import type { WhereFilterOp, FilterValues, FilterPreset, OrderByTuple } from "./filter-operators";
17
17
 
18
18
  /**
19
19
  * Base interface containing all driver-agnostic collection properties.
20
- * Use {@link PostgresCollection} or {@link FirebaseCollection} for
21
- * driver-specific type safety, or {@link EntityCollection} when you
20
+ * Use {@link PostgresCollectionConfig} or {@link FirebaseCollectionConfig} for
21
+ * driver-specific type safety, or {@link CollectionConfig} when you
22
22
  * need to handle any collection regardless of backend.
23
23
  *
24
24
  * @group Models
25
25
  */
26
- export interface BaseEntityCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
26
+ export interface BaseCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
27
27
 
28
28
  /**
29
29
  * You can set an alias that will be used internally instead of the collection name.
@@ -56,14 +56,14 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
56
56
  *
57
57
  * Custom drivers can set this directly to expose child collections to the UI.
58
58
  */
59
- childCollections?: () => EntityCollection<Record<string, unknown>>[];
59
+ childCollections?: () => CollectionConfig<Record<string, unknown>>[];
60
60
 
61
61
 
62
62
  /**
63
63
  * The data source this collection belongs to — the routing key shared by
64
64
  * the frontend router and the backend driver registry. It points at a
65
65
  * {@link DataSourceDefinition} registered on `<Rebase dataSources>` (front)
66
- * and `initRebase({ dataSources })` (back).
66
+ * and `initializeRebaseBackend({ dataSources })` (back).
67
67
  *
68
68
  * If not specified, the default data source `"(default)"` is used, which
69
69
  * for a standard Rebase app is the server-mediated Postgres backend.
@@ -81,8 +81,8 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
81
81
  * The database engine backing this collection (`"postgres"`, `"firestore"`,
82
82
  * `"mongodb"`, or a custom id).
83
83
  *
84
- * On concrete collection types ({@link PostgresCollection},
85
- * {@link FirebaseCollection}, {@link MongoDBCollection}) this is a literal
84
+ * On concrete collection types ({@link PostgresCollectionConfig},
85
+ * {@link FirebaseCollectionConfig}, {@link MongoDBCollectionConfig}) this is a literal
86
86
  * discriminant. On the base type it is optional and gets stamped
87
87
  * automatically during collection normalization from the registered
88
88
  * {@link DataSourceDefinition}.
@@ -103,7 +103,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
103
103
  databaseId?: string;
104
104
 
105
105
  /**
106
- * Set of properties that compose an entity
106
+ * Set of properties that compose a entity
107
107
  */
108
108
  properties: Properties;
109
109
 
@@ -145,13 +145,13 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
145
145
  readonly titleProperty?: Extract<keyof M, string> | (string & {});
146
146
 
147
147
  /**
148
- * When editing an entity, you can choose to open the entity in a side dialog
148
+ * When editing a entity, you can choose to open the entity in a side dialog
149
149
  * or in a full screen dialog. Defaults to `full_screen`.
150
150
  */
151
151
  openEntityMode?: "side_panel" | "full_screen" | "split" | "dialog";
152
152
 
153
153
  /**
154
- * Controls what happens when a user clicks on an entity in the collection view.
154
+ * Controls what happens when a user clicks on a entity in the collection view.
155
155
  * - `"edit"` (default): Opens the entity in the edit form.
156
156
  * - `"view"`: Opens a read-only detail view with an "Edit" button.
157
157
  */
@@ -204,19 +204,18 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
204
204
  * If you are specifying your collection as code, the order is the same as the
205
205
  * one you define in `properties`. Additional columns are added at the
206
206
  * end of the list, if the order is not specified.
207
+ *
207
208
  * You can use this prop to hide some properties from the table view.
208
209
  * Note that if you set this prop, other ways to hide fields, like
209
210
  * `hidden` in the property definition, will be ignored.
210
211
  * `propertiesOrder` has precedence over `hidden`.
211
- * - For properties use the property key.
212
- * - For additional fields use the field key.
213
- * - If you have subcollections, you get a column for each subcollection,
214
- * with the path (or alias) as the subcollection, prefixed with
215
- * `subcollection:`. e.g. `subcollection:orders`.
216
- * You can use this prop to hide some properties from the table view.
217
- * Note that if you set this prop, other ways to hide fields, like
218
- * `hidden` in the property definition,will be ignored.
219
- * `propertiesOrder` has precedence over `hidden`.
212
+ *
213
+ * Supported entry formats:
214
+ * - For properties, use the property key.
215
+ * - For additional fields, use the field key.
216
+ * - Child collections (Firestore subcollections, or Postgres relations
217
+ * with `many` cardinality) each get a column with id
218
+ * `subcollection:<slug>`, e.g. `subcollection:orders`.
220
219
  */
221
220
  propertiesOrder?: (Extract<keyof M, string> | (string & {}) | string | `subcollection:${string}`)[];
222
221
 
@@ -233,11 +232,11 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
233
232
  selectionEnabled?: boolean;
234
233
 
235
234
  /**
236
- * This interface defines all the callbacks that can be used when an entity
235
+ * This interface defines all the callbacks that can be used when a entity
237
236
  * is being created, updated or deleted.
238
237
  * Useful for adding your own logic or blocking the execution of the operation.
239
238
  */
240
- readonly callbacks?: EntityCallbacks<M, USER>;
239
+ readonly callbacks?: CollectionCallbacks<M, USER>;
241
240
 
242
241
  /**
243
242
  * Pass your own selection controller if you want to control selected
@@ -287,7 +286,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
287
286
  * applied in the collection.
288
287
  * e.g. `sort: ["order", "asc"]`
289
288
  */
290
- readonly sort?: [Extract<keyof M, string> | (string & {}), "asc" | "desc"];
289
+ readonly sort?: OrderByTuple<Extract<keyof M, string> | (string & {})>;
291
290
 
292
291
  /**
293
292
  * You can add additional fields to the collection view by implementing
@@ -318,7 +317,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
318
317
 
319
318
  /**
320
319
  * If you want to open custom views or subcollections by default when opening the edit
321
- * view of an entity, you can specify the path to the view here.
320
+ * view of a entity, you can specify the path to the view here.
322
321
  * The path is relative to the current collection. For example if you have a collection
323
322
  * that has a custom view as well as a subcollection that refers to another entity, you can
324
323
  * either specify the path to the custom view or the path to the subcollection.
@@ -362,7 +361,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
362
361
  metadata?: Record<string, unknown>;
363
362
 
364
363
  /**
365
- * Width of the side dialog (in pixels) when opening an entity in this collection.
364
+ * Width of the side dialog (in pixels) when opening a entity in this collection.
366
365
  */
367
366
  sideDialogWidth?: number | string;
368
367
 
@@ -387,9 +386,9 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
387
386
  /**
388
387
  * Should local changes be backed up in local storage, to prevent data loss on
389
388
  * accidental navigations.
390
- * - `manual_apply`: When the user navigates back to an entity with local changes,
389
+ * - `manual_apply`: When the user navigates back to a entity with local changes,
391
390
  * they will be prompted to restore the changes.
392
- * - `auto_apply`: When the user navigates back to an entity with local changes,
391
+ * - `auto_apply`: When the user navigates back to a entity with local changes,
393
392
  * the changes will be automatically applied.
394
393
  * - `false`: Local changes will not be backed up.
395
394
  * Defaults to `manual_apply`.
@@ -458,7 +457,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
458
457
  * Security rules for this collection (Row Level Security).
459
458
  * When defined, the backend enforces access control policies.
460
459
  */
461
- securityRules?: SecurityRule[];
460
+ securityRules?: readonly SecurityRule[];
462
461
 
463
462
  /**
464
463
  * Collection-scoped component overrides. These take precedence over
@@ -471,7 +470,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
471
470
  *
472
471
  * @example
473
472
  * ```tsx
474
- * const productsCollection: PostgresCollection = {
473
+ * const productsCollection: PostgresCollectionConfig = {
475
474
  * name: "Products",
476
475
  * slug: "products",
477
476
  * table: "products",
@@ -492,13 +491,13 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
492
491
  * A collection backed by PostgreSQL (or any SQL database).
493
492
  * Adds support for SQL-style relations (JOINs) and Row Level Security.
494
493
  *
495
- * Use this type instead of {@link EntityCollection} when you want
494
+ * Use this type instead of {@link CollectionConfig} when you want
496
495
  * compile-time safety that only SQL-relevant fields appear.
497
496
  *
498
497
  * @group Models
499
498
  */
500
- export interface PostgresCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
501
- extends BaseEntityCollection<M, USER> {
499
+ export interface PostgresCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
500
+ extends BaseCollectionConfig<M, USER> {
502
501
  properties: PostgresProperties;
503
502
 
504
503
  /**
@@ -526,7 +525,7 @@ export interface PostgresCollection<M extends Record<string, unknown> = Record<s
526
525
  relations?: Relation[];
527
526
 
528
527
  /**
529
- * Security rules for this collection (Supabase-style Row Level Security).
528
+ * Security rules for this collection (PostgreSQL Row Level Security).
530
529
  * When defined, the schema generator will enable RLS on the table and
531
530
  * create the corresponding PostgreSQL policies.
532
531
  *
@@ -540,27 +539,27 @@ export interface PostgresCollection<M extends Record<string, unknown> = Record<s
540
539
  * - `auth.roles()` — comma-separated app role IDs
541
540
  * - `auth.jwt()` — full JWT claims as JSONB
542
541
  */
543
- securityRules?: SecurityRule[];
542
+ securityRules?: readonly SecurityRule[];
544
543
  }
545
544
 
546
545
  /**
547
546
  * A collection backed by Firebase / Firestore.
548
547
  * Adds support for subcollections (nested document collections).
549
548
  *
550
- * Use this type instead of {@link EntityCollection} when you want
549
+ * Use this type instead of {@link CollectionConfig} when you want
551
550
  * compile-time safety that only Firestore-relevant fields appear.
552
551
  *
553
552
  * @group Models
554
553
  */
555
- export interface FirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
556
- extends BaseEntityCollection<M, USER> {
554
+ export interface FirebaseCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
555
+ extends BaseCollectionConfig<M, USER> {
557
556
  /**
558
557
  * The database engine for this collection. Must be set to `"firestore"`.
559
558
  */
560
559
  engine: "firestore";
561
560
 
562
561
  /**
563
- * Set of properties that compose an entity.
562
+ * Set of properties that compose a entity.
564
563
  * Firestore collections support `reference` properties but not `relation`.
565
564
  */
566
565
  properties: FirebaseProperties;
@@ -572,7 +571,7 @@ export interface FirebaseCollection<M extends Record<string, unknown> = Record<s
572
571
  *
573
572
  * @example
574
573
  * ```typescript
575
- * const fsCustomer: FirebaseCollection = {
574
+ * const fsCustomer: FirebaseCollectionConfig = {
576
575
  * slug: "fs_customer", // URL: /c/fs_customer
577
576
  * path: "customer", // Firestore path: customer
578
577
  * name: "Customers (Firestore)",
@@ -586,21 +585,21 @@ export interface FirebaseCollection<M extends Record<string, unknown> = Record<s
586
585
  /**
587
586
  * You can add subcollections to your entity in the same way you define the root
588
587
  * collections. The collections added here will be displayed when opening
589
- * the side dialog of an entity.
588
+ * the side dialog of a entity.
590
589
  */
591
- subcollections?: () => EntityCollection<Record<string, unknown>>[];
590
+ subcollections?: () => CollectionConfig<Record<string, unknown>>[];
592
591
  }
593
592
 
594
593
  /**
595
594
  * A collection backed by MongoDB.
596
595
  *
597
- * Use this type instead of {@link EntityCollection} when you want
596
+ * Use this type instead of {@link CollectionConfig} when you want
598
597
  * compile-time safety that only MongoDB-relevant fields appear.
599
598
  *
600
599
  * @group Models
601
600
  */
602
- export interface MongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
603
- extends BaseEntityCollection<M, USER> {
601
+ export interface MongoDBCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
602
+ extends BaseCollectionConfig<M, USER> {
604
603
 
605
604
  /**
606
605
  * The database engine for this collection. Must be set to `"mongodb"`.
@@ -608,7 +607,7 @@ export interface MongoDBCollection<M extends Record<string, unknown> = Record<st
608
607
  engine: "mongodb";
609
608
 
610
609
  /**
611
- * Set of properties that compose an entity.
610
+ * Set of properties that compose a entity.
612
611
  * MongoDB collections support `reference` properties but not `relation`.
613
612
  */
614
613
  properties: MongoProperties;
@@ -620,7 +619,7 @@ export interface MongoDBCollection<M extends Record<string, unknown> = Record<st
620
619
  *
621
620
  * @example
622
621
  * ```typescript
623
- * const mongoCustomer: MongoDBCollection = {
622
+ * const mongoCustomer: MongoDBCollectionConfig = {
624
623
  * slug: "mongo_customer", // URL: /c/mongo_customer
625
624
  * path: "customer", // MongoDB collection: customer
626
625
  * name: "Customers (MongoDB)",
@@ -634,25 +633,25 @@ export interface MongoDBCollection<M extends Record<string, unknown> = Record<st
634
633
 
635
634
  /**
636
635
  * A collection backed by any data source.
637
- * This is a discriminated union — use {@link PostgresCollection},
638
- * {@link FirebaseCollection}, or {@link MongoDBCollection} for
636
+ * This is a discriminated union — use {@link PostgresCollectionConfig},
637
+ * {@link FirebaseCollectionConfig}, or {@link MongoDBCollectionConfig} for
639
638
  * driver-specific type safety.
640
639
  *
641
640
  * @group Models
642
641
  */
643
- export type EntityCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =
644
- | PostgresCollection<M, USER>
645
- | FirebaseCollection<M, USER>
646
- | MongoDBCollection<M, USER>;
642
+ export type CollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =
643
+ | PostgresCollectionConfig<M, USER>
644
+ | FirebaseCollectionConfig<M, USER>
645
+ | MongoDBCollectionConfig<M, USER>;
647
646
 
648
647
  /**
649
648
  * Type guard for PostgreSQL collections.
650
649
  * Returns true if the collection uses the Postgres engine (or the default engine).
651
650
  * @group Models
652
651
  */
653
- export function isPostgresCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
654
- collection: EntityCollection<M, USER>
655
- ): collection is PostgresCollection<M, USER> {
652
+ export function isPostgresCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
653
+ collection: CollectionConfig<M, USER>
654
+ ): collection is PostgresCollectionConfig<M, USER> {
656
655
  return !collection.engine || collection.engine === "postgres";
657
656
  }
658
657
 
@@ -660,9 +659,9 @@ export function isPostgresCollection<M extends Record<string, unknown> = Record<
660
659
  * Type guard for Firebase / Firestore collections.
661
660
  * @group Models
662
661
  */
663
- export function isFirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
664
- collection: EntityCollection<M, USER>
665
- ): collection is FirebaseCollection<M, USER> {
662
+ export function isFirebaseCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
663
+ collection: CollectionConfig<M, USER>
664
+ ): collection is FirebaseCollectionConfig<M, USER> {
666
665
  return collection.engine === "firestore";
667
666
  }
668
667
 
@@ -670,9 +669,9 @@ export function isFirebaseCollection<M extends Record<string, unknown> = Record<
670
669
  * Type guard for MongoDB collections.
671
670
  * @group Models
672
671
  */
673
- export function isMongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
674
- collection: EntityCollection<M, USER>
675
- ): collection is MongoDBCollection<M, USER> {
672
+ export function isMongoDBCollectionConfig<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
673
+ collection: CollectionConfig<M, USER>
674
+ ): collection is MongoDBCollectionConfig<M, USER> {
676
675
  return collection.engine === "mongodb";
677
676
  }
678
677
 
@@ -682,12 +681,12 @@ export function isMongoDBCollection<M extends Record<string, unknown> = Record<s
682
681
  * otherwise falls back to `slug`.
683
682
  */
684
683
  export function getCollectionDataPath<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(
685
- collection: EntityCollection<M, USER>
684
+ collection: CollectionConfig<M, USER>
686
685
  ): string {
687
- if (isFirebaseCollection(collection) && collection.path) {
686
+ if (isFirebaseCollectionConfig(collection) && collection.path) {
688
687
  return collection.path;
689
688
  }
690
- if (isMongoDBCollection(collection) && collection.path) {
689
+ if (isMongoDBCollectionConfig(collection) && collection.path) {
691
690
  return collection.path;
692
691
  }
693
692
  return collection.slug;
@@ -704,9 +703,9 @@ export function getCollectionDataPath<M extends Record<string, unknown> = Record
704
703
  * @group Models
705
704
  */
706
705
  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;
706
+ collection: CollectionConfig<M, USER>
707
+ ): (() => CollectionConfig<Record<string, unknown>>[]) | undefined {
708
+ return (collection as FirebaseCollectionConfig<M, USER>).subcollections;
710
709
  }
711
710
 
712
711
 
@@ -741,7 +740,7 @@ export type ViewMode = "list" | "table" | "cards" | "kanban";
741
740
  *
742
741
  * @group Models
743
742
  */
744
- export interface CollectionActionsProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User, EC extends EntityCollection<M> = EntityCollection<M>> {
743
+ export interface CollectionActionsProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User, EC extends CollectionConfig<M> = CollectionConfig<M>> {
745
744
  /**
746
745
  * Full collection path of this entity. This is the full path, like
747
746
  * `users/1234/addresses`
@@ -807,7 +806,7 @@ export interface CollectionActionsProps<M extends Record<string, unknown> = Reco
807
806
 
808
807
  /**
809
808
  * Use this controller to retrieve the selected entities or modify them in
810
- * an {@link EntityCollection}
809
+ * an {@link CollectionConfig}
811
810
  * @group Models
812
811
  */
813
812
  export interface SelectionController<M extends Record<string, unknown> = Record<string, unknown>> {
@@ -894,16 +893,16 @@ export interface AdditionalFieldDelegate<M extends Record<string, unknown> = Rec
894
893
  }
895
894
 
896
895
 
897
- export type InferCollectionType<S extends EntityCollection> = S extends EntityCollection<infer M> ? M : never;
896
+ export type InferCollectionConfigType<S extends CollectionConfig> = S extends CollectionConfig<infer M> ? M : never;
898
897
 
899
898
  /**
900
- * Used in the {@link EntityCollection#defaultSelectedView} to define the default
899
+ * Used in the {@link CollectionConfig#defaultSelectedView} to define the default
901
900
  * @group Models
902
901
  */
903
902
  export type DefaultSelectedViewBuilder = (params: DefaultSelectedViewParams) => string | undefined;
904
903
 
905
904
  /**
906
- * Used in the {@link EntityCollection#defaultSelectedView} to define the default
905
+ * Used in the {@link CollectionConfig#defaultSelectedView} to define the default
907
906
  * @group Models
908
907
  */
909
908
  export type DefaultSelectedViewParams = {
@@ -961,7 +960,7 @@ export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all
961
960
  /**
962
961
  * Flexible Row Level Security rule for a collection.
963
962
  *
964
- * Inspired by Supabase's approach to PostgreSQL RLS. Rules can range from
963
+ * Built on PostgreSQL Row Level Security. Rules can range from
965
964
  * simple convenience shortcuts to fully custom SQL expressions, giving you the
966
965
  * full power of PostgreSQL Row Level Security.
967
966
  *
@@ -974,7 +973,7 @@ export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all
974
973
  *
975
974
  * **How rules combine:** PostgreSQL evaluates all matching policies for an
976
975
  * operation. Permissive rules are OR'd together (any one passing is enough).
977
- * Restrictive rules are AND'd (all must pass). This mirrors Supabase behavior.
976
+ * Restrictive rules are AND'd (all must pass). This is standard PostgreSQL RLS behavior.
978
977
  *
979
978
  * **Mutual exclusivity:** `ownerField`, `access`, structured `condition`, and
980
979
  * raw SQL (`using`/`withCheck`) cannot be combined. The type system enforces
@@ -1041,7 +1040,7 @@ export interface SecurityRuleBase {
1041
1040
  * // Equivalent to operation: "all"
1042
1041
  * { operations: ["all"], ownerField: "user_id" }
1043
1042
  */
1044
- operations?: SecurityOperation[];
1043
+ operations?: readonly SecurityOperation[];
1045
1044
 
1046
1045
  /**
1047
1046
  * Whether this policy is `"permissive"` (default) or `"restrictive"`.
@@ -1051,7 +1050,7 @@ export interface SecurityRuleBase {
1051
1050
  * - **restrictive**: Restrictive policies are AND'd with all permissive
1052
1051
  * policies — they act as additional gates that *must* also pass.
1053
1052
  *
1054
- * This is the same model as PostgreSQL / Supabase.
1053
+ * This is the standard PostgreSQL RLS model.
1055
1054
  *
1056
1055
  * @default "permissive"
1057
1056
  */
@@ -1084,7 +1083,7 @@ export interface SecurityRuleBase {
1084
1083
  * // Admins have unfiltered read access to all rows
1085
1084
  * { operation: "select", roles: ["admin"], using: "true" }
1086
1085
  */
1087
- roles?: string[];
1086
+ roles?: readonly string[];
1088
1087
 
1089
1088
  // ── Advanced: native PostgreSQL role targeting ───────────────────────
1090
1089
 
@@ -1109,7 +1108,7 @@ export interface SecurityRuleBase {
1109
1108
  * // Only apply this policy when connected as `app_role`
1110
1109
  * { operation: "select", access: "public", pgRoles: ["app_role"] }
1111
1110
  */
1112
- pgRoles?: string[];
1111
+ pgRoles?: readonly string[];
1113
1112
  }
1114
1113
 
1115
1114
  /**
@@ -1,4 +1,6 @@
1
1
  import type React from "react";
2
+ import type { Property } from "./properties";
3
+ import type { WhereFilterOp } from "./filter-operators";
2
4
 
3
5
  // ── Scoped component name unions ──────────────────────────────────────
4
6
 
@@ -43,13 +45,14 @@ export type CollectionComponentName =
43
45
  | "Collection.Card"
44
46
  | "Collection.EmptyState"
45
47
  | "Collection.Actions"
48
+ | "Collection.FilterField"
46
49
 
47
50
  // ── Entity / Form ──
48
51
  | "Entity.Form"
49
- | "Entity.FormActions"
50
- | "Entity.DetailView"
52
+ | "EditView.FormActions"
53
+ | "DetailView"
51
54
  | "Entity.SidePanel"
52
- | "Entity.Preview"
55
+ | "EntityPreview"
53
56
  | "Entity.MissingReference";
54
57
 
55
58
  /**
@@ -58,6 +61,70 @@ export type CollectionComponentName =
58
61
  */
59
62
  export type OverridableComponentName = AppComponentName | CollectionComponentName;
60
63
 
64
+ /**
65
+ * Props received by a filter field component — whether it is a built-in
66
+ * per-type field, a property-level replacement (`property.ui.Filter`), or a
67
+ * `"Collection.FilterField"` override.
68
+ *
69
+ * The `operators` list is **already resolved**: it is the intersection of the
70
+ * engine's {@link DataSourceCapabilities.filterOperators}, the property-type
71
+ * defaults, and any `property.ui.filterOperators` narrowing. A custom field
72
+ * should only offer operators from this list — anything else may throw at
73
+ * query time on engines that cannot execute it.
74
+ *
75
+ * @example
76
+ * ```tsx
77
+ * function MyStatusFilter({ value, setValue, operators }: FilterFieldBindingProps) {
78
+ * return (
79
+ * <select
80
+ * value={value?.[1] as string ?? ""}
81
+ * onChange={e => setValue(e.target.value ? ["==", e.target.value] : undefined)}>
82
+ * <option value="">Any</option>
83
+ * <option value="active">Active</option>
84
+ * <option value="archived">Archived</option>
85
+ * </select>
86
+ * );
87
+ * }
88
+ * ```
89
+ *
90
+ * @group Component Overrides
91
+ */
92
+ export interface FilterFieldBindingProps {
93
+ /** Key of the property being filtered (the column id). */
94
+ propertyKey: string;
95
+
96
+ /**
97
+ * The resolved property. For array properties this is the **item**
98
+ * property (`property.of`), with `isArray` set to true.
99
+ */
100
+ property: Property;
101
+
102
+ /** True when the underlying property is an array of `property`. */
103
+ isArray: boolean;
104
+
105
+ /**
106
+ * Operators this field may offer, already narrowed by engine
107
+ * capabilities, property-type defaults, and `property.ui.filterOperators`.
108
+ */
109
+ operators: readonly WhereFilterOp[];
110
+
111
+ /** Current filter condition for this property, if any. */
112
+ value?: [WhereFilterOp, unknown];
113
+
114
+ /** Set (or clear, with `undefined`) the filter condition. */
115
+ setValue: (value?: [WhereFilterOp, unknown]) => void;
116
+
117
+ /** Display title for the field (usually the property name). */
118
+ title?: string;
119
+
120
+ /**
121
+ * Coordination flags used by fields that open their own dialogs
122
+ * (e.g. the reference picker hides the parent filters dialog).
123
+ */
124
+ hidden?: boolean;
125
+ setHidden?: (hidden: boolean) => void;
126
+ }
127
+
61
128
  // ── Override entry ────────────────────────────────────────────────────
62
129
 
63
130
  /**
@@ -89,7 +156,7 @@ export type OverridableComponentName = AppComponentName | CollectionComponentNam
89
156
  *
90
157
  * @group Component Overrides
91
158
  */
92
- export interface ComponentOverride<P = any> {
159
+ export interface ComponentOverride<P = Record<string, unknown>> {
93
160
  /**
94
161
  * The replacement component. Receives the same props as the built-in
95
162
  * component it replaces.
@@ -161,7 +228,7 @@ export type CollectionComponentOverrideMap = {
161
228
  * "HomePage": { Component: MyDashboard },
162
229
  *
163
230
  * // Collection defaults: apply to ALL collections
164
- * "Entity.FormActions": {
231
+ * "EditView.FormActions": {
165
232
  * Component: MyFormActions,
166
233
  * wrap: true
167
234
  * },
package/src/types/cron.ts CHANGED
@@ -60,7 +60,16 @@ export interface CronJobContext {
60
60
  /** A simple logger scoped to this job run. */
61
61
  log: (...args: unknown[]) => void;
62
62
 
63
- /** The RebaseClient instance to interact with the database. */
63
+ /**
64
+ * The server-side {@link RebaseClient}. This is the **same singleton**
65
+ * exposed as `rebase` (imported from `@rebasepro/server-core`) and as
66
+ * `context` in collection callbacks — it is only named `client` here.
67
+ *
68
+ * Its data plane (`client.data`) runs with **admin privileges and bypasses
69
+ * RLS** (`{ uid: "service", roles: ["admin"] }`). There is no per-request
70
+ * user in a cron, so treat every query as fully trusted and scope your own
71
+ * filters explicitly.
72
+ */
64
73
  client: RebaseClient;
65
74
  }
66
75
 
@@ -1,3 +1,5 @@
1
+ import { ALL_WHERE_FILTER_OPS, WhereFilterOp } from "./filter-operators";
2
+
1
3
  /**
2
4
  * Describes the capabilities and features supported by a data source (driver).
3
5
  *
@@ -35,6 +37,17 @@ export interface DataSourceCapabilities {
35
37
  /** Does this source support real-time listeners? */
36
38
  supportsRealtime: boolean;
37
39
 
40
+ /**
41
+ * Canonical filter operators this engine can execute.
42
+ *
43
+ * The admin UI intersects this set with the property-type defaults and
44
+ * any per-property narrowing (`property.ui.filterOperators`) to decide
45
+ * which operators to offer in filter fields — so an engine that cannot
46
+ * run `ilike` (e.g. Firestore) never shows a "Contains" filter that
47
+ * would throw at query time.
48
+ */
49
+ filterOperators: readonly WhereFilterOp[];
50
+
38
51
  // ── Admin capability flags ───────────────────────────────────────
39
52
  /** Does this source support SQL admin operations (SQL editor, EXPLAIN, etc.)? */
40
53
  supportsSQLAdmin: boolean;
@@ -102,9 +115,11 @@ export interface DataSourceDefinition {
102
115
  engine: string;
103
116
 
104
117
  /**
105
- * How the frontend reaches this source. Defaults to `"server"`.
118
+ * How the frontend reaches this source. Optional when omitted it is
119
+ * inferred: `"direct"` if the definition carries a client-side driver,
120
+ * `"server"` otherwise.
106
121
  */
107
- transport: DataSourceTransport;
122
+ transport?: DataSourceTransport;
108
123
 
109
124
  /**
110
125
  * The physical database/schema/Firestore-database within the engine.
@@ -149,6 +164,7 @@ export const POSTGRES_CAPABILITIES: DataSourceCapabilities = {
149
164
  supportsReferences: false,
150
165
  supportsColumnTypes: true,
151
166
  supportsRealtime: true,
167
+ filterOperators: ALL_WHERE_FILTER_OPS,
152
168
  supportsSQLAdmin: true,
153
169
  supportsDocumentAdmin: false,
154
170
  supportsSchemaAdmin: true
@@ -164,6 +180,10 @@ export const FIREBASE_CAPABILITIES: DataSourceCapabilities = {
164
180
  supportsReferences: true,
165
181
  supportsColumnTypes: false,
166
182
  supportsRealtime: true,
183
+ // Firestore has no SQL pattern matching — the driver throws on the LIKE
184
+ // family, so the UI must never offer it.
185
+ filterOperators: ALL_WHERE_FILTER_OPS.filter(op =>
186
+ op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
167
187
  supportsSQLAdmin: false,
168
188
  supportsDocumentAdmin: false,
169
189
  supportsSchemaAdmin: false
@@ -179,6 +199,7 @@ export const MONGODB_CAPABILITIES: DataSourceCapabilities = {
179
199
  supportsReferences: true,
180
200
  supportsColumnTypes: false,
181
201
  supportsRealtime: false,
202
+ filterOperators: ALL_WHERE_FILTER_OPS,
182
203
  supportsSQLAdmin: false,
183
204
  supportsDocumentAdmin: true,
184
205
  supportsSchemaAdmin: true
@@ -198,6 +219,7 @@ export const DEFAULT_CAPABILITIES: DataSourceCapabilities = {
198
219
  supportsReferences: true,
199
220
  supportsColumnTypes: true,
200
221
  supportsRealtime: true,
222
+ filterOperators: ALL_WHERE_FILTER_OPS,
201
223
  supportsSQLAdmin: true,
202
224
  supportsDocumentAdmin: true,
203
225
  supportsSchemaAdmin: true