@rebasepro/server-postgresql 0.0.1-canary.4d4fb3e → 0.0.1-canary.ca2cb6e

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 (136) hide show
  1. package/dist/common/src/collections/CollectionRegistry.d.ts +8 -0
  2. package/dist/common/src/util/entities.d.ts +22 -0
  3. package/dist/common/src/util/relations.d.ts +14 -4
  4. package/dist/common/src/util/resolutions.d.ts +1 -1
  5. package/dist/index.es.js +1254 -591
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +1254 -591
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +17 -29
  10. package/dist/server-postgresql/src/auth/services.d.ts +7 -3
  11. package/dist/server-postgresql/src/collections/PostgresCollectionRegistry.d.ts +1 -1
  12. package/dist/server-postgresql/src/connection.d.ts +34 -1
  13. package/dist/server-postgresql/src/data-transformer.d.ts +26 -4
  14. package/dist/server-postgresql/src/databasePoolManager.d.ts +2 -2
  15. package/dist/server-postgresql/src/schema/auth-schema.d.ts +139 -38
  16. package/dist/server-postgresql/src/schema/doctor-cli.d.ts +2 -0
  17. package/dist/server-postgresql/src/schema/doctor.d.ts +43 -0
  18. package/dist/server-postgresql/src/schema/generate-drizzle-schema-logic.d.ts +1 -1
  19. package/dist/server-postgresql/src/schema/test-schema.d.ts +24 -0
  20. package/dist/server-postgresql/src/services/EntityFetchService.d.ts +22 -8
  21. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +1 -1
  22. package/dist/server-postgresql/src/services/RelationService.d.ts +11 -5
  23. package/dist/server-postgresql/src/services/entity-helpers.d.ts +16 -2
  24. package/dist/server-postgresql/src/services/entityService.d.ts +8 -6
  25. package/dist/server-postgresql/src/services/realtimeService.d.ts +2 -0
  26. package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +2 -2
  27. package/dist/types/src/controllers/auth.d.ts +2 -0
  28. package/dist/types/src/controllers/client.d.ts +119 -7
  29. package/dist/types/src/controllers/collection_registry.d.ts +4 -3
  30. package/dist/types/src/controllers/customization_controller.d.ts +7 -1
  31. package/dist/types/src/controllers/data.d.ts +34 -7
  32. package/dist/types/src/controllers/data_driver.d.ts +20 -28
  33. package/dist/types/src/controllers/database_admin.d.ts +2 -2
  34. package/dist/types/src/controllers/email.d.ts +34 -0
  35. package/dist/types/src/controllers/index.d.ts +1 -0
  36. package/dist/types/src/controllers/local_config_persistence.d.ts +4 -4
  37. package/dist/types/src/controllers/navigation.d.ts +5 -5
  38. package/dist/types/src/controllers/registry.d.ts +6 -3
  39. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -6
  40. package/dist/types/src/controllers/storage.d.ts +24 -26
  41. package/dist/types/src/rebase_context.d.ts +8 -4
  42. package/dist/types/src/types/backend.d.ts +4 -1
  43. package/dist/types/src/types/builders.d.ts +5 -4
  44. package/dist/types/src/types/chips.d.ts +1 -1
  45. package/dist/types/src/types/collections.d.ts +169 -125
  46. package/dist/types/src/types/cron.d.ts +102 -0
  47. package/dist/types/src/types/data_source.d.ts +1 -1
  48. package/dist/types/src/types/entity_actions.d.ts +8 -8
  49. package/dist/types/src/types/entity_callbacks.d.ts +15 -15
  50. package/dist/types/src/types/entity_link_builder.d.ts +1 -1
  51. package/dist/types/src/types/entity_overrides.d.ts +2 -1
  52. package/dist/types/src/types/entity_views.d.ts +8 -8
  53. package/dist/types/src/types/export_import.d.ts +3 -3
  54. package/dist/types/src/types/index.d.ts +1 -0
  55. package/dist/types/src/types/plugins.d.ts +72 -18
  56. package/dist/types/src/types/properties.d.ts +118 -33
  57. package/dist/types/src/types/relations.d.ts +1 -1
  58. package/dist/types/src/types/slots.d.ts +30 -6
  59. package/dist/types/src/types/translations.d.ts +44 -0
  60. package/dist/types/src/types/user_management_delegate.d.ts +1 -0
  61. package/drizzle-test/0000_woozy_junta.sql +6 -0
  62. package/drizzle-test/0001_youthful_arachne.sql +1 -0
  63. package/drizzle-test/0002_lively_dragon_lord.sql +2 -0
  64. package/drizzle-test/0003_mean_king_cobra.sql +2 -0
  65. package/drizzle-test/meta/0000_snapshot.json +47 -0
  66. package/drizzle-test/meta/0001_snapshot.json +48 -0
  67. package/drizzle-test/meta/0002_snapshot.json +38 -0
  68. package/drizzle-test/meta/0003_snapshot.json +48 -0
  69. package/drizzle-test/meta/_journal.json +34 -0
  70. package/drizzle-test-out/0000_tan_trauma.sql +6 -0
  71. package/drizzle-test-out/0001_rapid_drax.sql +1 -0
  72. package/drizzle-test-out/meta/0000_snapshot.json +44 -0
  73. package/drizzle-test-out/meta/0001_snapshot.json +54 -0
  74. package/drizzle-test-out/meta/_journal.json +20 -0
  75. package/drizzle.test.config.ts +10 -0
  76. package/package.json +88 -89
  77. package/scratch.ts +41 -0
  78. package/src/PostgresBackendDriver.ts +63 -79
  79. package/src/PostgresBootstrapper.ts +7 -8
  80. package/src/auth/ensure-tables.ts +158 -86
  81. package/src/auth/services.ts +109 -50
  82. package/src/cli.ts +259 -16
  83. package/src/collections/PostgresCollectionRegistry.ts +6 -6
  84. package/src/connection.ts +70 -48
  85. package/src/data-transformer.ts +155 -116
  86. package/src/databasePoolManager.ts +6 -5
  87. package/src/history/HistoryService.ts +3 -12
  88. package/src/interfaces.ts +3 -3
  89. package/src/schema/auth-schema.ts +26 -3
  90. package/src/schema/doctor-cli.ts +47 -0
  91. package/src/schema/doctor.ts +595 -0
  92. package/src/schema/generate-drizzle-schema-logic.ts +204 -57
  93. package/src/schema/generate-drizzle-schema.ts +6 -6
  94. package/src/schema/test-schema.ts +11 -0
  95. package/src/services/BranchService.ts +5 -5
  96. package/src/services/EntityFetchService.ts +317 -188
  97. package/src/services/EntityPersistService.ts +15 -17
  98. package/src/services/RelationService.ts +299 -37
  99. package/src/services/entity-helpers.ts +39 -13
  100. package/src/services/entityService.ts +11 -9
  101. package/src/services/realtimeService.ts +58 -29
  102. package/src/utils/drizzle-conditions.ts +25 -24
  103. package/src/websocket.ts +52 -21
  104. package/test/auth-services.test.ts +131 -39
  105. package/test/batch-many-to-many-regression.test.ts +573 -0
  106. package/test/branchService.test.ts +22 -12
  107. package/test/data-transformer-hardening.test.ts +417 -0
  108. package/test/data-transformer.test.ts +175 -0
  109. package/test/doctor.test.ts +182 -0
  110. package/test/entityService.errors.test.ts +31 -16
  111. package/test/entityService.relations.test.ts +155 -59
  112. package/test/entityService.subcollection-search.test.ts +107 -57
  113. package/test/entityService.test.ts +105 -47
  114. package/test/generate-drizzle-schema.test.ts +262 -69
  115. package/test/historyService.test.ts +31 -16
  116. package/test/n-plus-one-regression.test.ts +314 -0
  117. package/test/postgresDataDriver.test.ts +260 -168
  118. package/test/realtimeService.test.ts +70 -39
  119. package/test/relation-pipeline-gaps.test.ts +637 -0
  120. package/test/relations.test.ts +492 -39
  121. package/test-drizzle-bug.ts +18 -0
  122. package/test-drizzle-out/0000_cultured_freak.sql +7 -0
  123. package/test-drizzle-out/0001_tiresome_professor_monster.sql +1 -0
  124. package/test-drizzle-out/meta/0000_snapshot.json +55 -0
  125. package/test-drizzle-out/meta/0001_snapshot.json +63 -0
  126. package/test-drizzle-out/meta/_journal.json +20 -0
  127. package/test-drizzle-prompt.sh +2 -0
  128. package/test-policy-prompt.sh +3 -0
  129. package/test-programmatic.ts +30 -0
  130. package/test-programmatic2.ts +59 -0
  131. package/test-schema-no-policies.ts +12 -0
  132. package/test_drizzle_mock.js +2 -2
  133. package/test_find_changed.mjs +3 -1
  134. package/test_hash.js +14 -0
  135. package/tsconfig.json +1 -1
  136. package/vite.config.ts +5 -5
@@ -1,9 +1,10 @@
1
- import { Entity, EntityCollection } from "../types";
1
+ import type { Entity } from "../types/entities";
2
+ import type { EntityCollection } from "../types/collections";
2
3
  /**
3
4
  * Props used to open a side dialog
4
5
  * @group Hooks and utilities
5
6
  */
6
- export interface EntitySidePanelProps<M extends Record<string, any> = any> {
7
+ export interface EntitySidePanelProps<M extends Record<string, unknown> = Record<string, unknown>> {
7
8
  /**
8
9
  * Absolute path of the entity
9
10
  */
@@ -43,7 +44,7 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
43
44
  * @param params
44
45
  */
45
46
  onUpdate?: (params: {
46
- entity: Entity<any>;
47
+ entity: Entity<M>;
47
48
  }) => void;
48
49
  /**
49
50
  * Callback when the dialog is closed
@@ -56,7 +57,7 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
56
57
  /**
57
58
  * Override some form properties
58
59
  */
59
- formProps?: any;
60
+ formProps?: Record<string, unknown>;
60
61
  /**
61
62
  * Allow the user to open the entity fullscreen
62
63
  */
@@ -80,10 +81,10 @@ export interface SideEntityController {
80
81
  * (or a new one with that id).
81
82
  * @param props
82
83
  */
83
- open: <M extends Record<string, any> = any>(props: EntitySidePanelProps<M>) => void;
84
+ open: <M extends Record<string, unknown> = Record<string, unknown>>(props: EntitySidePanelProps<M>) => void;
84
85
  /**
85
86
  * Replace the last open entity panel with the given one.
86
87
  * @param props
87
88
  */
88
- replace: <M extends Record<string, any> = any>(props: EntitySidePanelProps<M>) => void;
89
+ replace: <M extends Record<string, unknown> = Record<string, unknown>>(props: EntitySidePanelProps<M>) => void;
89
90
  }
@@ -3,8 +3,7 @@
3
3
  */
4
4
  export interface UploadFileProps {
5
5
  file: File;
6
- fileName?: string;
7
- path?: string;
6
+ key: string;
8
7
  metadata?: Record<string, unknown>;
9
8
  bucket?: string;
10
9
  }
@@ -13,9 +12,9 @@ export interface UploadFileProps {
13
12
  */
14
13
  export interface UploadFileResult {
15
14
  /**
16
- * Storage path including the file name where the file was uploaded.
15
+ * Storage key including the file name where the file was uploaded.
17
16
  */
18
- path: string;
17
+ key: string;
19
18
  /**
20
19
  * Bucket where the file was uploaded
21
20
  */
@@ -23,7 +22,7 @@ export interface UploadFileResult {
23
22
  /**
24
23
  * Fully qualified storage URL for the uploaded file.
25
24
  *
26
- * For example: `gs://my-bucket/path/to/file.png`.
25
+ * For example: `s3://my-bucket/path/to/file.png`.
27
26
  *
28
27
  * This is optional for backwards compatibility.
29
28
  */
@@ -74,39 +73,38 @@ export declare interface DownloadMetadata {
74
73
  */
75
74
  export interface StorageSource {
76
75
  /**
77
- * Upload a file, specifying a name and a path
76
+ * Upload an object, specifying a key
78
77
  * @param file
79
- * @param fileName
80
- * @param path
78
+ * @param key
81
79
  * @param metadata
82
80
  * @param bucket
83
81
  */
84
- uploadFile: ({ file, fileName, path, metadata, bucket }: UploadFileProps) => Promise<UploadFileResult>;
82
+ putObject: ({ file, key, metadata, bucket }: UploadFileProps) => Promise<UploadFileResult>;
85
83
  /**
86
- * Convert a storage path or URL into a download configuration
87
- * @param path
84
+ * Convert a storage key or URL into a download configuration (signed URL equivalent)
85
+ * @param keyOrUrl
88
86
  * @param bucket
89
87
  */
90
- getDownloadURL: (pathOrUrl: string, bucket?: string) => Promise<DownloadConfig>;
88
+ getSignedUrl: (keyOrUrl: string, bucket?: string) => Promise<DownloadConfig>;
91
89
  /**
92
- * Get a file from a storage path.
93
- * It returns null if the file does not exist.
94
- * @param props
90
+ * Get an object from a storage key.
91
+ * It returns null if the object does not exist.
92
+ * @param key
95
93
  * @param bucket
96
94
  */
97
- getFile: (path: string, bucket?: string) => Promise<File | null>;
95
+ getObject: (key: string, bucket?: string) => Promise<File | null>;
98
96
  /**
99
- * Delete a file.
100
- * @param path
97
+ * Delete an object.
98
+ * @param key
101
99
  * @param bucket
102
100
  */
103
- deleteFile: (path: string, bucket?: string) => Promise<void>;
101
+ deleteObject: (key: string, bucket?: string) => Promise<void>;
104
102
  /**
105
- * List the contents of a path.
106
- * @param path
103
+ * List the contents of a prefix.
104
+ * @param prefix
107
105
  * @param options
108
106
  */
109
- list: (path: string, options?: {
107
+ listObjects: (prefix: string, options?: {
110
108
  bucket?: string;
111
109
  maxResults?: number;
112
110
  pageToken?: string;
@@ -137,15 +135,15 @@ export declare interface StorageListResult {
137
135
  nextPageToken?: string;
138
136
  }
139
137
  /**
140
- * Represents a reference to a Google Cloud Storage object. Developers can
138
+ * Represents a reference to an S3-compatible storage object. Developers can
141
139
  * upload, download, and delete objects, as well as get/set object metadata.
142
140
  * @public
143
141
  */
144
142
  export declare interface StorageReference {
145
143
  /**
146
- * Returns a gs:// URL for this object in the form
147
- * `gs://<bucket>/<path>/<to>/<object>`
148
- * @returns The gs:// URL.
144
+ * Returns a s3:// URL for this object in the form
145
+ * `s3://<bucket>/<path>/<to>/<object>`
146
+ * @returns The s3:// URL.
149
147
  */
150
148
  toString(): string;
151
149
  /**
@@ -1,7 +1,11 @@
1
- import { AnalyticsController, AuthController, StorageSource, UserConfigurationPersistence, DatabaseAdmin } from "./controllers";
2
- import { RebaseData } from "./controllers/data";
3
- import { User } from "./users";
4
- import { UserManagementDelegate } from "./types/user_management_delegate";
1
+ import type { AnalyticsController } from "./controllers/analytics_controller";
2
+ import type { AuthController } from "./controllers/auth";
3
+ import type { StorageSource } from "./controllers/storage";
4
+ import type { UserConfigurationPersistence } from "./controllers/local_config_persistence";
5
+ import type { DatabaseAdmin } from "./types/backend";
6
+ import type { RebaseData } from "./controllers/data";
7
+ import type { User } from "./users";
8
+ import type { UserManagementDelegate } from "./types/user_management_delegate";
5
9
  /**
6
10
  * Context that is provided to entity callbacks (hooks).
7
11
  * It contains only the dependencies that are available in both the frontend and the backend.
@@ -1,4 +1,5 @@
1
- import { Entity, EntityCollection, FilterValues, WhereFilterOp } from "./index";
1
+ import type { Entity } from "./entities";
2
+ import type { EntityCollection, FilterValues, WhereFilterOp } from "./collections";
2
3
  /**
3
4
  * Abstract database connection interface.
4
5
  * Represents a connection to any database system.
@@ -33,6 +34,7 @@ export interface FetchCollectionOptions<M extends Record<string, unknown> = Reco
33
34
  orderBy?: string;
34
35
  order?: "desc" | "asc";
35
36
  limit?: number;
37
+ offset?: number;
36
38
  startAfter?: unknown;
37
39
  searchString?: string;
38
40
  databaseId?: string;
@@ -54,6 +56,7 @@ export interface SearchOptions<M extends Record<string, unknown> = Record<string
54
56
  */
55
57
  export interface CountOptions<M extends Record<string, unknown> = Record<string, unknown>> {
56
58
  filter?: FilterValues<Extract<keyof M, string>>;
59
+ searchString?: string;
57
60
  databaseId?: string;
58
61
  }
59
62
  /**
@@ -1,7 +1,8 @@
1
- import { AuthController, RebaseData } from "../controllers";
2
- import { User } from "../users";
3
- import { EntityCollection } from "./collections";
4
- import { AppView } from "../controllers/navigation";
1
+ import type { AuthController } from "../controllers/auth";
2
+ import type { RebaseData } from "../controllers/data";
3
+ import type { User } from "../users";
4
+ import type { EntityCollection } from "./collections";
5
+ import type { AppView } from "../controllers/navigation";
5
6
  export type EntityCollectionsBuilder<EC extends EntityCollection = EntityCollection> = (params: {
6
7
  user: User | null;
7
8
  authController: AuthController;
@@ -2,4 +2,4 @@ export type ColorScheme = {
2
2
  color: string;
3
3
  text: string;
4
4
  };
5
- export type ColorKey = "blueLighter" | "cyanLighter" | "tealLighter" | "greenLighter" | "yellowLighter" | "orangeLighter" | "redLighter" | "pinkLighter" | "purpleLighter" | "grayLighter" | "blueLight" | "cyanLight" | "tealLight" | "greenLight" | "yellowLight" | "orangeLight" | "redLight" | "pinkLight" | "purpleLight" | "grayLight" | "blueDark" | "cyanDark" | "tealDark" | "greenDark" | "yellowDark" | "orangeDark" | "redDark" | "pinkDark" | "purpleDark" | "grayDark" | "blueDarker" | "cyanDarker" | "tealDarker" | "greenDarker" | "yellowDarker" | "orangeDarker" | "redDarker" | "pinkDarker" | "purpleDarker" | "grayDarker";
5
+ export type ColorKey = "blue" | "cyan" | "teal" | "green" | "yellow" | "orange" | "red" | "pink" | "purple" | "gray" | "indigo" | "violet" | "fuchsia" | "rose" | "emerald";
@@ -1,14 +1,14 @@
1
1
  import React from "react";
2
- import { Entity, EntityStatus } from "./entities";
3
- import { EntityCallbacks } from "./entity_callbacks";
4
- import { Properties } from "./properties";
5
- import { ExportConfig } from "./export_import";
6
- import { EntityOverrides } from "./entity_overrides";
7
- import { User } from "../users";
8
- import { RebaseContext } from "../rebase_context";
9
- import { Relation } from "./relations";
10
- import { EntityCustomView } from "./entity_views";
11
- import { EntityAction } from "./entity_actions";
2
+ import type { Entity, EntityStatus } from "./entities";
3
+ import type { EntityCallbacks } from "./entity_callbacks";
4
+ import type { Properties } from "./properties";
5
+ import type { ExportConfig } from "./export_import";
6
+ import type { EntityOverrides } from "./entity_overrides";
7
+ import type { User } from "../users";
8
+ import type { RebaseContext } from "../rebase_context";
9
+ import type { Relation } from "./relations";
10
+ import type { EntityCustomView } from "./entity_views";
11
+ import type { EntityAction } from "./entity_actions";
12
12
  /**
13
13
  * Base interface containing all driver-agnostic collection properties.
14
14
  * Use {@link PostgresCollection} or {@link FirebaseCollection} for
@@ -98,6 +98,11 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
98
98
  * Default preview properties displayed when this collection is referenced to.
99
99
  */
100
100
  previewProperties?: string[];
101
+ /**
102
+ * Properties to display as columns in the list view.
103
+ * If not specified, the list view uses a smart default (Title, Status, Date).
104
+ */
105
+ listProperties?: string[];
101
106
  /**
102
107
  * Title property of the entity. This is the property that will be used
103
108
  * as the title in entity related views and references.
@@ -108,7 +113,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
108
113
  * When editing an entity, you can choose to open the entity in a side dialog
109
114
  * or in a full screen dialog. Defaults to `full_screen`.
110
115
  */
111
- openEntityMode?: "side_panel" | "full_screen";
116
+ openEntityMode?: "side_panel" | "full_screen" | "split";
112
117
  /**
113
118
  * Order in which the properties are displayed.
114
119
  * If you are specifying your collection as code, the order is the same as the
@@ -262,7 +267,7 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
262
267
  localChangesBackup?: "manual_apply" | "auto_apply" | false;
263
268
  /**
264
269
  * Default view mode for displaying this collection.
265
- * - "table": Display entities in a spreadsheet-like table (default)
270
+ * - "table": Display entities in a table with inline editing (default)
266
271
  * - "cards": Display entities as a grid of cards with thumbnails
267
272
  * - "kanban": Display entities in a Kanban board grouped by a property
268
273
  * Defaults to "table".
@@ -283,9 +288,10 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
283
288
  kanban?: KanbanConfig<M>;
284
289
  /**
285
290
  * Property key to use for ordering items.
286
- * Must reference a number property. When items are reordered,
287
- * this property will be updated to reflect the new order using
288
- * fractional indexing. Used by Kanban view for ordering within columns
291
+ * Must reference a string/text property. When items are reordered,
292
+ * this property will be updated with lexicographic sort keys
293
+ * (e.g. "a0", "a1", "a0V") using string-based fractional indexing.
294
+ * Used by Kanban view for ordering within columns
289
295
  * and can be used for general ordering purposes.
290
296
  */
291
297
  readonly orderProperty?: Extract<keyof M, string> | (string & {});
@@ -317,11 +323,6 @@ export interface PostgresCollection<M extends Record<string, unknown> = Record<s
317
323
  * The PostgreSQL table name for this collection.
318
324
  */
319
325
  table: string;
320
- /**
321
- * Set by the backend when the resolved table name doesn't match
322
- * an actual table in the database schema.
323
- */
324
- isTableMissing?: boolean;
325
326
  /**
326
327
  * For SQL databases, you can define the relations between collections here.
327
328
  * Relations describe JOINs, foreign keys, and junction tables.
@@ -365,14 +366,39 @@ export interface FirebaseCollection<M extends Record<string, unknown> = Record<s
365
366
  */
366
367
  subcollections?: () => EntityCollection<Record<string, unknown>>[];
367
368
  }
369
+ /**
370
+ * A collection backed by MongoDB.
371
+ *
372
+ * Use this type instead of {@link EntityCollection} when you want
373
+ * compile-time safety that only MongoDB-relevant fields appear.
374
+ *
375
+ * @group Models
376
+ */
377
+ export interface MongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> extends BaseEntityCollection<M, USER> {
378
+ /**
379
+ * The driver for this collection. Must be set to `"mongodb"`.
380
+ */
381
+ driver: "mongodb";
382
+ }
368
383
  /**
369
384
  * A collection backed by any data source.
370
- * This is a discriminated union — use {@link PostgresCollection} or
371
- * {@link FirebaseCollection} for driver-specific type safety.
385
+ * This is a discriminated union — use {@link PostgresCollection},
386
+ * {@link FirebaseCollection}, or {@link MongoDBCollection} for
387
+ * driver-specific type safety.
372
388
  *
373
389
  * @group Models
374
390
  */
375
- export type EntityCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = PostgresCollection<M, USER> | FirebaseCollection<M, USER>;
391
+ export type EntityCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = PostgresCollection<M, USER> | FirebaseCollection<M, USER> | MongoDBCollection<M, USER>;
392
+ /** An EntityCollection that supports SQL-style relations (e.g. Postgres). */
393
+ export type CollectionWithRelations<M extends Record<string, unknown> = Record<string, unknown>> = EntityCollection<M> & {
394
+ table?: string;
395
+ relations?: Relation[];
396
+ securityRules?: SecurityRule[];
397
+ };
398
+ /** An EntityCollection that supports subcollections (e.g. Firestore). */
399
+ export type CollectionWithSubcollections<M extends Record<string, unknown> = Record<string, unknown>> = EntityCollection<M> & {
400
+ subcollections?: () => EntityCollection<Record<string, unknown>>[];
401
+ };
376
402
  /**
377
403
  * Type guard for PostgreSQL collections.
378
404
  * Returns true if the collection uses the Postgres driver (or the default driver).
@@ -384,6 +410,11 @@ export declare function isPostgresCollection<M extends Record<string, unknown> =
384
410
  * @group Models
385
411
  */
386
412
  export declare function isFirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(collection: EntityCollection<M, USER>): collection is FirebaseCollection<M, USER>;
413
+ /**
414
+ * Type guard for MongoDB collections.
415
+ * @group Models
416
+ */
417
+ export declare function isMongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(collection: EntityCollection<M, USER>): collection is MongoDBCollection<M, USER>;
387
418
  /**
388
419
  * Configuration for Kanban board view mode.
389
420
  * @group Collections
@@ -399,9 +430,13 @@ export interface KanbanConfig<M extends Record<string, unknown> = Record<string,
399
430
  }
400
431
  /**
401
432
  * View mode for displaying a collection.
433
+ * - "list": Simple, clean list view — the classic CMS default
434
+ * - "table": Table with inline editing
435
+ * - "cards": Grid of visual cards with thumbnails
436
+ * - "kanban": Board view grouped by a property
402
437
  * @group Collections
403
438
  */
404
- export type ViewMode = "table" | "cards" | "kanban";
439
+ export type ViewMode = "list" | "table" | "cards" | "kanban";
405
440
  /**
406
441
  * Parameter passed to the `Actions` prop in the collection configuration.
407
442
  * The component will receive this prop when it is rendered in the collection
@@ -610,9 +645,18 @@ export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all
610
645
  * operation. Permissive rules are OR'd together (any one passing is enough).
611
646
  * Restrictive rules are AND'd (all must pass). This mirrors Supabase behavior.
612
647
  *
648
+ * **Mutual exclusivity:** `ownerField`, `access`, and raw SQL (`using`/`withCheck`)
649
+ * cannot be combined. The type system enforces this — attempting to set
650
+ * conflicting fields will produce a compile-time error.
651
+ *
613
652
  * @group Models
614
653
  */
615
- export interface SecurityRule {
654
+ export type SecurityRule = OwnerSecurityRule | PublicSecurityRule | RawSQLSecurityRule | RolesOnlySecurityRule;
655
+ /**
656
+ * Shared fields for all SecurityRule variants.
657
+ * @group Models
658
+ */
659
+ export interface SecurityRuleBase {
616
660
  /**
617
661
  * Optional human-readable name for the policy.
618
662
  * If not provided, one will be auto-generated from the table name and operation.
@@ -664,35 +708,6 @@ export interface SecurityRule {
664
708
  * @default "permissive"
665
709
  */
666
710
  mode?: "permissive" | "restrictive";
667
- /**
668
- * **Shortcut.** The property (column) that stores the owner's user ID.
669
- * Generates a USING/WITH CHECK clause like:
670
- * `<column> = auth.uid()`
671
- *
672
- * Cannot be combined with `using` / `withCheck` / `access`.
673
- *
674
- * @example
675
- * { operation: "all", ownerField: "user_id" }
676
- */
677
- ownerField?: string;
678
- /**
679
- * **Shortcut.** Grant unrestricted row access (no row filtering) for this operation.
680
- * Generates `USING (true)`.
681
- *
682
- * This means "no row-level filter", NOT "anonymous/unauthenticated access".
683
- * Authentication is still enforced at the API layer — this only controls which
684
- * *rows* authenticated users can see.
685
- *
686
- * Typically used alone for genuinely public read endpoints, or combined with
687
- * `roles` to give certain roles an unfiltered view of the table.
688
- *
689
- * Cannot be combined with `using` / `withCheck` / `ownerField`.
690
- *
691
- * @example
692
- * // Public read (any authenticated user sees all rows)
693
- * { operation: "select", access: "public" }
694
- */
695
- access?: "public";
696
711
  /**
697
712
  * **Shortcut.** Restrict this rule to users that have one of these
698
713
  * application-level roles.
@@ -716,77 +731,6 @@ export interface SecurityRule {
716
731
  * { operation: "select", roles: ["admin"], using: "true" }
717
732
  */
718
733
  roles?: string[];
719
- /**
720
- * Raw SQL expression for the `USING` clause.
721
- * This controls which *existing* rows are visible / can be modified / deleted.
722
- * Applied to SELECT, UPDATE, and DELETE.
723
- *
724
- * You can reference columns via `{column_name}` which will be resolved to
725
- * `table.column_name` in the generated Drizzle code. You can also use any
726
- * valid PostgreSQL expression.
727
- *
728
- * Cannot be combined with `ownerField` or `access`.
729
- *
730
- * @example
731
- * // Rows published in the last 30 days are visible
732
- * { operation: "select", using: "{published_at} > now() - interval '30 days'" }
733
- *
734
- * @example
735
- * // Only the owner, or users with 'moderator' role
736
- * {
737
- * operation: "select",
738
- * using: "{user_id} = auth.uid() OR auth.roles() ~ 'moderator'"
739
- * }
740
- *
741
- * @example
742
- * // Cross-table subquery: only if user belongs to the org
743
- * {
744
- * operation: "select",
745
- * using: "EXISTS (SELECT 1 FROM org_members WHERE org_members.org_id = {org_id} AND org_members.user_id = auth.uid())"
746
- * }
747
- */
748
- using?: string;
749
- /**
750
- * Raw SQL expression for the `WITH CHECK` clause.
751
- * This controls which *new/updated* row values are allowed.
752
- * Applied to INSERT and UPDATE.
753
- *
754
- * Same syntax as `using` — use `{column_name}` to reference columns.
755
- *
756
- * **Important for UPDATE:** PostgreSQL evaluates two row states — the
757
- * *existing* row (`USING`) and the *incoming new* row (`WITH CHECK`).
758
- * If you only specify `using`, the same expression is used for both.
759
- * For security-sensitive updates, always specify `withCheck` explicitly
760
- * to constrain what the new row values can be.
761
- *
762
- * If not provided on INSERT/UPDATE policies, falls back to `using`
763
- * (which matches PostgreSQL's own default behavior).
764
- *
765
- * Cannot be combined with `ownerField` or `access`.
766
- *
767
- * @example
768
- * // Users can only insert rows where they are the owner
769
- * { operation: "insert", withCheck: "{user_id} = auth.uid()" }
770
- *
771
- * @example
772
- * // Prevent changing the status to 'archived' unless admin
773
- * {
774
- * operation: "update",
775
- * using: "{user_id} = auth.uid()",
776
- * withCheck: "{status} != 'archived' OR auth.roles() ~ 'admin'"
777
- * }
778
- *
779
- * @example
780
- * // Restrictive gate: prevent locking AND unlocking unless admin.
781
- * // `using` checks the old row state, `withCheck` checks the new.
782
- * {
783
- * operation: "update",
784
- * mode: "restrictive",
785
- * using: "{is_locked} = false",
786
- * withCheck: "{is_locked} = false"
787
- * }
788
- */
789
- withCheck?: string;
790
734
  /**
791
735
  * **Advanced.** Native PostgreSQL database roles the policy applies to.
792
736
  *
@@ -810,3 +754,103 @@ export interface SecurityRule {
810
754
  */
811
755
  pgRoles?: string[];
812
756
  }
757
+ /**
758
+ * Security rule that grants access based on row ownership.
759
+ * Generates a USING/WITH CHECK clause like: `<column> = auth.uid()`
760
+ *
761
+ * Cannot be combined with `using`, `withCheck`, or `access`.
762
+ *
763
+ * @example
764
+ * { operation: "all", ownerField: "user_id" }
765
+ *
766
+ * @group Models
767
+ */
768
+ export interface OwnerSecurityRule extends SecurityRuleBase {
769
+ /** The property (column) that stores the owner's user ID. */
770
+ ownerField: string;
771
+ access?: never;
772
+ using?: never;
773
+ withCheck?: never;
774
+ }
775
+ /**
776
+ * Security rule that grants unrestricted row access (no row filtering).
777
+ * Generates `USING (true)`.
778
+ *
779
+ * This means "no row-level filter", NOT "anonymous/unauthenticated access".
780
+ * Authentication is still enforced at the API layer — this only controls which
781
+ * *rows* authenticated users can see.
782
+ *
783
+ * Cannot be combined with `using`, `withCheck`, or `ownerField`.
784
+ *
785
+ * @example
786
+ * // Public read (any authenticated user sees all rows)
787
+ * { operation: "select", access: "public" }
788
+ *
789
+ * @group Models
790
+ */
791
+ export interface PublicSecurityRule extends SecurityRuleBase {
792
+ /** Grant unrestricted row access for this operation. */
793
+ access: "public";
794
+ ownerField?: never;
795
+ using?: never;
796
+ withCheck?: never;
797
+ }
798
+ /**
799
+ * Security rule using raw SQL expressions for full PostgreSQL RLS power.
800
+ *
801
+ * Cannot be combined with `ownerField` or `access`.
802
+ *
803
+ * You can reference columns via `{column_name}` which will be resolved to
804
+ * `table.column_name` in the generated Drizzle code.
805
+ *
806
+ * @example
807
+ * // Rows published in the last 30 days are visible
808
+ * { operation: "select", using: "{published_at} > now() - interval '30 days'" }
809
+ *
810
+ * @example
811
+ * // Only the owner, or users with 'moderator' role
812
+ * {
813
+ * operation: "select",
814
+ * using: "{user_id} = auth.uid() OR auth.roles() ~ 'moderator'"
815
+ * }
816
+ *
817
+ * @group Models
818
+ */
819
+ export interface RawSQLSecurityRule extends SecurityRuleBase {
820
+ /**
821
+ * Raw SQL expression for the `USING` clause.
822
+ * This controls which *existing* rows are visible / can be modified / deleted.
823
+ * Applied to SELECT, UPDATE, and DELETE.
824
+ */
825
+ using: string;
826
+ /**
827
+ * Raw SQL expression for the `WITH CHECK` clause.
828
+ * This controls which *new/updated* row values are allowed.
829
+ * Applied to INSERT and UPDATE.
830
+ *
831
+ * If not provided on INSERT/UPDATE policies, falls back to `using`
832
+ * (which matches PostgreSQL's own default behavior).
833
+ */
834
+ withCheck?: string;
835
+ ownerField?: never;
836
+ access?: never;
837
+ }
838
+ /**
839
+ * Security rule that only filters by application roles, without any
840
+ * row-level condition (USING/WITH CHECK).
841
+ *
842
+ * Useful for simple "only admins can access this table" rules where
843
+ * no per-row filtering is needed.
844
+ *
845
+ * @example
846
+ * // Only admins can delete
847
+ * { operation: "delete", roles: ["admin"] }
848
+ *
849
+ * @group Models
850
+ */
851
+ export interface RolesOnlySecurityRule extends SecurityRuleBase {
852
+ ownerField?: never;
853
+ access?: never;
854
+ using?: never;
855
+ withCheck?: never;
856
+ }