@rebasepro/types 0.0.1-canary.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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/components/EntityFormActionsProps.d.ts +17 -0
- package/dist/components/EntityFormProps.d.ts +46 -0
- package/dist/components/PropertyPreviewProps.d.ts +50 -0
- package/dist/components/formex.d.ts +40 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/controllers/analytics_controller.d.ts +7 -0
- package/dist/controllers/auth.d.ts +73 -0
- package/dist/controllers/customization_controller.d.ts +50 -0
- package/dist/controllers/datasource.d.ts +179 -0
- package/dist/controllers/dialogs_controller.d.ts +36 -0
- package/dist/controllers/index.d.ts +11 -0
- package/dist/controllers/local_config_persistence.d.ts +20 -0
- package/dist/controllers/navigation.d.ts +262 -0
- package/dist/controllers/side_dialogs_controller.d.ts +67 -0
- package/dist/controllers/side_entity_controller.d.ts +90 -0
- package/dist/controllers/snackbar.d.ts +24 -0
- package/dist/controllers/storage.d.ts +173 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +113 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +117 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/rebase_context.d.ts +91 -0
- package/dist/types/backend.d.ts +254 -0
- package/dist/types/chips.d.ts +5 -0
- package/dist/types/collections.d.ts +887 -0
- package/dist/types/entities.d.ts +140 -0
- package/dist/types/entity_actions.d.ts +98 -0
- package/dist/types/entity_callbacks.d.ts +173 -0
- package/dist/types/entity_link_builder.d.ts +7 -0
- package/dist/types/entity_overrides.d.ts +5 -0
- package/dist/types/export_import.d.ts +21 -0
- package/dist/types/fields.d.ts +221 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/locales.d.ts +4 -0
- package/dist/types/modify_collections.d.ts +5 -0
- package/dist/types/plugins.d.ts +276 -0
- package/dist/types/properties.d.ts +1103 -0
- package/dist/types/property_config.d.ts +68 -0
- package/dist/types/rebase.d.ts +180 -0
- package/dist/types/relations.d.ts +336 -0
- package/dist/types/user_management_delegate.d.ts +78 -0
- package/dist/types/websockets.d.ts +33 -0
- package/dist/users/index.d.ts +2 -0
- package/dist/users/roles.d.ts +22 -0
- package/dist/users/user.d.ts +42 -0
- package/package.json +137 -0
- package/src/components/EntityFormActionsProps.tsx +18 -0
- package/src/components/EntityFormProps.tsx +52 -0
- package/src/components/PropertyPreviewProps.tsx +61 -0
- package/src/components/formex.tsx +46 -0
- package/src/components/index.ts +3 -0
- package/src/controllers/analytics_controller.tsx +57 -0
- package/src/controllers/auth.tsx +94 -0
- package/src/controllers/customization_controller.tsx +61 -0
- package/src/controllers/datasource.ts +218 -0
- package/src/controllers/dialogs_controller.tsx +37 -0
- package/src/controllers/index.ts +11 -0
- package/src/controllers/local_config_persistence.tsx +22 -0
- package/src/controllers/navigation.ts +317 -0
- package/src/controllers/side_dialogs_controller.tsx +82 -0
- package/src/controllers/side_entity_controller.tsx +104 -0
- package/src/controllers/snackbar.ts +29 -0
- package/src/controllers/storage.ts +196 -0
- package/src/index.ts +5 -0
- package/src/rebase_context.tsx +122 -0
- package/src/types/backend.ts +385 -0
- package/src/types/chips.ts +46 -0
- package/src/types/collections.ts +1013 -0
- package/src/types/entities.ts +207 -0
- package/src/types/entity_actions.tsx +118 -0
- package/src/types/entity_callbacks.ts +217 -0
- package/src/types/entity_link_builder.ts +8 -0
- package/src/types/entity_overrides.tsx +6 -0
- package/src/types/export_import.ts +26 -0
- package/src/types/fields.tsx +298 -0
- package/src/types/index.ts +20 -0
- package/src/types/locales.ts +81 -0
- package/src/types/modify_collections.tsx +6 -0
- package/src/types/plugins.tsx +328 -0
- package/src/types/properties.ts +1270 -0
- package/src/types/property_config.tsx +93 -0
- package/src/types/rebase.tsx +211 -0
- package/src/types/relations.ts +351 -0
- package/src/types/user_management_delegate.ts +98 -0
- package/src/types/websockets.ts +37 -0
- package/src/users/index.ts +2 -0
- package/src/users/roles.ts +33 -0
- package/src/users/user.ts +46 -0
|
@@ -0,0 +1,1013 @@
|
|
|
1
|
+
import React, { Dispatch, SetStateAction } from "react";
|
|
2
|
+
import { Entity, EntityStatus, EntityValues } from "./entities";
|
|
3
|
+
import { EntityCallbacks } from "./entity_callbacks";
|
|
4
|
+
|
|
5
|
+
import { EnumValues, Properties } from "./properties";
|
|
6
|
+
import { FormContext } from "./fields";
|
|
7
|
+
import { EntityAction } from "./entity_actions";
|
|
8
|
+
import { ExportConfig } from "./export_import";
|
|
9
|
+
import { EntityOverrides } from "./entity_overrides";
|
|
10
|
+
import { User } from "../users";
|
|
11
|
+
import { RebaseContext } from "../rebase_context";
|
|
12
|
+
import { Relation } from "./relations";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This interface represents a view that includes a collection of entities.
|
|
16
|
+
* It can be in the root level of the configuration, defining the main
|
|
17
|
+
* menu navigation. You can also find it as a subcollection of a different one.
|
|
18
|
+
*
|
|
19
|
+
* @group Models
|
|
20
|
+
*/
|
|
21
|
+
export interface EntityCollection<M extends Record<string, any> = any, USER extends User = any> {
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* You can set an alias that will be used internally instead of the `path`.
|
|
25
|
+
* The `alias` value will be used to determine the URL of the collection,
|
|
26
|
+
* while `path` will still be used in the datasource.
|
|
27
|
+
* Note that you can use this value in reference properties too.
|
|
28
|
+
*/
|
|
29
|
+
slug: string;
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Name of the collection, typically plural.
|
|
36
|
+
* E.g. `Products`, `Blog`
|
|
37
|
+
*/
|
|
38
|
+
name: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Singular name of an entry in this collection
|
|
42
|
+
* E.g. `Product`, `Blog entry`
|
|
43
|
+
*/
|
|
44
|
+
singularName?: string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Optional description of this view. You can use Markdown.
|
|
48
|
+
*/
|
|
49
|
+
description?: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Path or table name of the collection in the database.
|
|
53
|
+
* If not specified, the `slug` property is used, converted to snake_case.
|
|
54
|
+
*/
|
|
55
|
+
dbPath: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Which datasource handles this collection.
|
|
59
|
+
* Use this to route collections to different backends:
|
|
60
|
+
* - `"postgres"` - Route to PostgreSQL backend
|
|
61
|
+
* - `"firestore"` - Route to Firestore (client-side)
|
|
62
|
+
* - `"mongodb"` - Route to MongoDB backend
|
|
63
|
+
* - Custom IDs for your own datasource implementations
|
|
64
|
+
*
|
|
65
|
+
* If not specified, the default datasource `"(default)"` is used.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // Simple - no datasource needed for default
|
|
69
|
+
* { slug: "products" }
|
|
70
|
+
*
|
|
71
|
+
* // Firestore collection (client-side real-time)
|
|
72
|
+
* { slug: "analytics", datasource: "firestore" }
|
|
73
|
+
*
|
|
74
|
+
* // Multiple databases within a datasource
|
|
75
|
+
* { slug: "orders", datasource: "postgres", databaseId: "orders_db" }
|
|
76
|
+
*/
|
|
77
|
+
datasource?: string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Which database within the datasource.
|
|
81
|
+
* - For Firestore: The Firestore database ID (e.g., for multi-database projects)
|
|
82
|
+
* - For PostgreSQL: Schema or database name
|
|
83
|
+
* - For MongoDB: Database name
|
|
84
|
+
*
|
|
85
|
+
* If not specified, the default database of the datasource is used.
|
|
86
|
+
*/
|
|
87
|
+
databaseId?: string;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Security rules for this collection (Supabase-style Row Level Security).
|
|
91
|
+
* When defined, the schema generator will enable RLS on the table and
|
|
92
|
+
* create the corresponding PostgreSQL policies.
|
|
93
|
+
*
|
|
94
|
+
* Supports three levels of expressiveness:
|
|
95
|
+
* 1. **Convenience shortcuts** — `ownerField`, `access`, `roles`
|
|
96
|
+
* 2. **Raw SQL** — `using` and `withCheck` for full PostgreSQL power
|
|
97
|
+
* 3. **Combined** — mix shortcuts with `roles` for common patterns
|
|
98
|
+
*
|
|
99
|
+
* The authenticated user context is available in raw SQL via:
|
|
100
|
+
* - `auth.uid()` — the current user's ID
|
|
101
|
+
* - `auth.roles()` — comma-separated app role IDs
|
|
102
|
+
* - `auth.jwt()` — full JWT claims as JSONB
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* // Simple: only owners can access their own rows
|
|
106
|
+
* securityRules: [
|
|
107
|
+
* { operation: "all", ownerField: "user_id" }
|
|
108
|
+
* ]
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* // Public read, owner-only write (using operations array to reduce boilerplate)
|
|
112
|
+
* securityRules: [
|
|
113
|
+
* { operation: "select", access: "public" },
|
|
114
|
+
* { operations: ["insert", "update", "delete"], ownerField: "created_by" }
|
|
115
|
+
* ]
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* // Role-based: admins read all rows, users read own
|
|
119
|
+
* securityRules: [
|
|
120
|
+
* { operation: "select", roles: ["admin"], using: "true" },
|
|
121
|
+
* { operation: "all", ownerField: "user_id" }
|
|
122
|
+
* ]
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* // Raw SQL: cross-table check with subquery
|
|
126
|
+
* securityRules: [
|
|
127
|
+
* {
|
|
128
|
+
* operation: "select",
|
|
129
|
+
* using: "EXISTS (SELECT 1 FROM org_members WHERE org_members.org_id = {org_id} AND org_members.user_id = auth.uid())"
|
|
130
|
+
* }
|
|
131
|
+
* ]
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* // Restrictive policy with both USING and WITH CHECK to constrain old AND new row states
|
|
135
|
+
* securityRules: [
|
|
136
|
+
* { operation: "all", ownerField: "user_id" },
|
|
137
|
+
* { operation: "update", mode: "restrictive", using: "{is_locked} = false", withCheck: "{is_locked} = false" }
|
|
138
|
+
* ]
|
|
139
|
+
*/
|
|
140
|
+
securityRules?: SecurityRule[];
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* If this collection is a top level navigation entry, you can set this
|
|
144
|
+
* property to `true` to indicate that this collection is a collection group.
|
|
145
|
+
*/
|
|
146
|
+
collectionGroup?: boolean;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Icon key to use in this collection.
|
|
150
|
+
* You can use any of the icons in the Material specs:
|
|
151
|
+
* https://fonts.google.com/icons
|
|
152
|
+
* e.g. 'account_tree' or 'person'.
|
|
153
|
+
* Find all the icons in https://rebase.pro/docs/icons
|
|
154
|
+
* You can also pass a React node if you want to render a custom icon.
|
|
155
|
+
* If not specified, a default icon will be used.
|
|
156
|
+
*/
|
|
157
|
+
icon?: string | React.ReactNode;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Optional field used to group top level navigation entries under a~
|
|
161
|
+
* navigation view. If you set this value in a subcollection it has no
|
|
162
|
+
* effect.
|
|
163
|
+
* @deprecated This prop is deprecated and will be removed in the future.
|
|
164
|
+
* You can apply grouping by using the `navigationGroupMappings` prop in the
|
|
165
|
+
* {@link useBuildNavigationController} hook instead.
|
|
166
|
+
*/
|
|
167
|
+
group?: string;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Set of properties that compose an entity
|
|
171
|
+
*/
|
|
172
|
+
properties: Properties;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Default preview properties displayed when this collection is referenced to.
|
|
176
|
+
*/
|
|
177
|
+
previewProperties?: string[];
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Title property of the entity. This is the property that will be used
|
|
181
|
+
* as the title in entity related views and references.
|
|
182
|
+
* If not specified, the first property simple text property will be used.
|
|
183
|
+
*/
|
|
184
|
+
titleProperty?: Extract<keyof M, string>;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* When editing an entity, you can choose to open the entity in a side dialog
|
|
188
|
+
* or in a full screen dialog. Defaults to `full_screen`.
|
|
189
|
+
*/
|
|
190
|
+
openEntityMode?: "side_panel" | "full_screen";
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Order in which the properties are displayed.
|
|
194
|
+
* If you are specifying your collection as code, the order is the same as the
|
|
195
|
+
* one you define in `properties`. Additional columns are added at the
|
|
196
|
+
* end of the list, if the order is not specified.
|
|
197
|
+
* You can use this prop to hide some properties from the table view.
|
|
198
|
+
* Note that if you set this prop, other ways to hide fields, like
|
|
199
|
+
* `hidden` in the property definition, will be ignored.
|
|
200
|
+
* `propertiesOrder` has precedence over `hidden`.
|
|
201
|
+
* - For properties use the property key.
|
|
202
|
+
* - For additional fields use the field key.
|
|
203
|
+
* - If you have subcollections, you get a column for each subcollection,
|
|
204
|
+
* with the path (or alias) as the subcollection, prefixed with
|
|
205
|
+
* `subcollection:`. e.g. `subcollection:orders`.
|
|
206
|
+
* - If you are using a collection group, you will also have an
|
|
207
|
+
* additional `collectionGroupParent` column.
|
|
208
|
+
* You can use this prop to hide some properties from the table view.
|
|
209
|
+
* Note that if you set this prop, other ways to hide fields, like
|
|
210
|
+
* `hidden` in the property definition,will be ignored.
|
|
211
|
+
* `propertiesOrder` has precedence over `hidden`.
|
|
212
|
+
*/
|
|
213
|
+
propertiesOrder?: (Extract<keyof M, string> | string | `subcollection:${string}` | "collectionGroupParent")[];
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* If enabled, content is loaded in batches. If `false` all entities in the
|
|
217
|
+
* collection are loaded. This means that when reaching the end of the
|
|
218
|
+
* collection, the CMS will load more entities.
|
|
219
|
+
* You can specify a number to specify the pagination size (50 by default)
|
|
220
|
+
* Defaults to `true`
|
|
221
|
+
*/
|
|
222
|
+
pagination?: boolean | number;
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
selectionEnabled?: boolean;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* You can add subcollections to your entity in the same way you define the root
|
|
229
|
+
* collections. The collections added here will be displayed when opening
|
|
230
|
+
* the side dialog of an entity.
|
|
231
|
+
*/
|
|
232
|
+
subcollections?: () => EntityCollection<any>[];
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* For SQL databases, you can define the relations between collections here.
|
|
236
|
+
*/
|
|
237
|
+
relations?: Relation[];
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* This interface defines all the callbacks that can be used when an entity
|
|
241
|
+
* is being created, updated or deleted.
|
|
242
|
+
* Useful for adding your own logic or blocking the execution of the operation.
|
|
243
|
+
*/
|
|
244
|
+
callbacks?: EntityCallbacks<M, USER>;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Builder for rendering additional components such as buttons in the
|
|
248
|
+
* collection toolbar
|
|
249
|
+
*/
|
|
250
|
+
Actions?: React.ComponentType<CollectionActionsProps> | React.ComponentType<CollectionActionsProps>[];
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* You can define additional actions that can be performed on the entities
|
|
254
|
+
* in this collection. These actions can be displayed in the collection
|
|
255
|
+
* view or in the entity view.
|
|
256
|
+
*
|
|
257
|
+
* You can use the `onClick` method to implement your own logic.
|
|
258
|
+
* In the `context` prop you can access all the controllers of Rebase.
|
|
259
|
+
*
|
|
260
|
+
* ```
|
|
261
|
+
* const archiveEntityAction: EntityAction = {
|
|
262
|
+
* icon: <ArchiveIcon/>,
|
|
263
|
+
* name: "Archive",
|
|
264
|
+
* onClick({
|
|
265
|
+
* entity,
|
|
266
|
+
* collection,
|
|
267
|
+
* context,
|
|
268
|
+
* }): Promise<void> {
|
|
269
|
+
* // Add your code here
|
|
270
|
+
* return Promise.resolve(undefined);
|
|
271
|
+
* }
|
|
272
|
+
* }
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* You can also pass the action as a string that represents the `key`, in which case it will
|
|
276
|
+
* use the action defined in the main configuration under `entityActions`.
|
|
277
|
+
*/
|
|
278
|
+
entityActions?: (EntityAction<M, USER> | string)[];
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Pass your own selection controller if you want to control selected
|
|
282
|
+
* entities externally.
|
|
283
|
+
* @see useSelectionController
|
|
284
|
+
*/
|
|
285
|
+
selectionController?: SelectionController<M>;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Force a filter in this view. If applied, the rest of the filters will
|
|
289
|
+
* be disabled. Filters applied with this prop cannot be changed.
|
|
290
|
+
* e.g. `forceFilter: { age: [">=", 18] }`
|
|
291
|
+
* e.g. `forceFilter: { related_user: ["==", new EntityReference("sdc43dsw2", "users")] }`
|
|
292
|
+
*/
|
|
293
|
+
forceFilter?: FilterValues<Extract<keyof M, string>>;
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Initial filters applied to the collection this collection is related to.
|
|
297
|
+
* Defaults to none. Filters applied with this prop can be changed.
|
|
298
|
+
* e.g. `filter: { age: [">=", 18] }`
|
|
299
|
+
* e.g. `filter: { related_user: ["==", new EntityReference("sdc43dsw2", "users")] }`
|
|
300
|
+
*/
|
|
301
|
+
filter?: FilterValues<Extract<keyof M, string>>; // setting FilterValues<M> can break defining collections by code
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Default sort applied to this collection.
|
|
305
|
+
* When setting this prop, entities will have a default order
|
|
306
|
+
* applied in the collection.
|
|
307
|
+
* e.g. `sort: ["order", "asc"]`
|
|
308
|
+
*/
|
|
309
|
+
sort?: [Extract<keyof M, string>, "asc" | "desc"];
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Array of builders for rendering additional panels in an entity view.
|
|
313
|
+
* Useful if you need to render custom views.
|
|
314
|
+
* You can either define the custom view inline or pass a reference to
|
|
315
|
+
* a custom view defined in the main configuration under `entityViews`
|
|
316
|
+
*/
|
|
317
|
+
entityViews?: (string | EntityCustomView<M>)[];
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* You can add additional fields to the collection view by implementing
|
|
321
|
+
* an additional field delegate.
|
|
322
|
+
*/
|
|
323
|
+
additionalFields?: AdditionalFieldDelegate<M, USER>[];
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Default size of the rendered collection
|
|
327
|
+
*/
|
|
328
|
+
defaultSize?: CollectionSize;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Can the elements in this collection be edited inline in the collection
|
|
332
|
+
* view. If this flag is set to false but `permissions.edit` is `true`, entities
|
|
333
|
+
* can still be edited in the side panel
|
|
334
|
+
*/
|
|
335
|
+
inlineEditing?: boolean;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Should this collection be hidden from the main navigation panel, if
|
|
339
|
+
* it is at the root level, or in the entity side panel if it's a
|
|
340
|
+
* subcollection.
|
|
341
|
+
* It will still be accessible if you reach the specified path.
|
|
342
|
+
* You can also use this collection as a reference target.
|
|
343
|
+
*/
|
|
344
|
+
hideFromNavigation?: boolean;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* If you want to open custom views or subcollections by default when opening the edit
|
|
348
|
+
* view of an entity, you can specify the path to the view here.
|
|
349
|
+
* The path is relative to the current collection. For example if you have a collection
|
|
350
|
+
* that has a custom view as well as a subcollection that refers to another entity, you can
|
|
351
|
+
* either specify the path to the custom view or the path to the subcollection.
|
|
352
|
+
*/
|
|
353
|
+
defaultSelectedView?: string | DefaultSelectedViewBuilder;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Should the ID of this collection be hidden from the form view.
|
|
357
|
+
*/
|
|
358
|
+
hideIdFromForm?: boolean;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Should the ID of this collection be hidden from the grid view.
|
|
362
|
+
*/
|
|
363
|
+
hideIdFromCollection?: boolean;
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* If set to true, the form will be auto-saved when the user changes
|
|
367
|
+
* the value of a field.
|
|
368
|
+
* Defaults to false.
|
|
369
|
+
* When a new entity is created, this property can be updated to generated a new ID
|
|
370
|
+
*/
|
|
371
|
+
formAutoSave?: boolean;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
*
|
|
375
|
+
*/
|
|
376
|
+
exportable?: boolean | ExportConfig<USER>;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* User id of the owner of this collection. This is used only by plugins, or if you
|
|
380
|
+
* are writing custom code
|
|
381
|
+
*/
|
|
382
|
+
ownerId?: string;
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Overrides for the entity view, like the data source or the storage source.
|
|
386
|
+
*/
|
|
387
|
+
overrides?: EntityOverrides;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Width of the side dialog (in pixels) when opening an entity in this collection.
|
|
391
|
+
*/
|
|
392
|
+
sideDialogWidth?: number | string;
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* If set to true, the default values of the properties will be applied
|
|
396
|
+
* to the entity every time the entity is updated (not only when created).
|
|
397
|
+
* Defaults to false.
|
|
398
|
+
*/
|
|
399
|
+
alwaysApplyDefaultValues?: boolean;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* If set to true, a tab including the JSON representation of the entity will be included.
|
|
403
|
+
*/
|
|
404
|
+
includeJsonView?: boolean;
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* If set to true, changes to the entity will be saved in a subcollection.
|
|
408
|
+
* This prop has no effect if the history plugin is not enabled
|
|
409
|
+
*/
|
|
410
|
+
history?: boolean;
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Should local changes be backed up in local storage, to prevent data loss on
|
|
414
|
+
* accidental navigations.
|
|
415
|
+
* - `manual_apply`: When the user navigates back to an entity with local changes,
|
|
416
|
+
* they will be prompted to restore the changes.
|
|
417
|
+
* - `auto_apply`: When the user navigates back to an entity with local changes,
|
|
418
|
+
* the changes will be automatically applied.
|
|
419
|
+
* - `false`: Local changes will not be backed up.
|
|
420
|
+
* Defaults to `manual_apply`.
|
|
421
|
+
*/
|
|
422
|
+
localChangesBackup?: "manual_apply" | "auto_apply" | false;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Default view mode for displaying this collection.
|
|
426
|
+
* - "table": Display entities in a spreadsheet-like table (default)
|
|
427
|
+
* - "cards": Display entities as a grid of cards with thumbnails
|
|
428
|
+
* - "kanban": Display entities in a Kanban board grouped by a property
|
|
429
|
+
* Defaults to "table".
|
|
430
|
+
*/
|
|
431
|
+
defaultViewMode?: ViewMode;
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Which view modes are available for this collection.
|
|
435
|
+
* Possible values: "table", "cards", "kanban".
|
|
436
|
+
* Defaults to all three: ["table", "cards", "kanban"].
|
|
437
|
+
* Note: "kanban" will only be available if the collection has at least
|
|
438
|
+
* one string property with enumValues defined, regardless of this setting.
|
|
439
|
+
*/
|
|
440
|
+
enabledViews?: ViewMode[];
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Configuration for Kanban board view mode.
|
|
444
|
+
* When set, the Kanban view mode becomes available.
|
|
445
|
+
*/
|
|
446
|
+
kanban?: KanbanConfig<M>;
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Property key to use for ordering items.
|
|
450
|
+
* Must reference a number property. When items are reordered,
|
|
451
|
+
* this property will be updated to reflect the new order using
|
|
452
|
+
* fractional indexing. Used by Kanban view for ordering within columns
|
|
453
|
+
* and can be used for general ordering purposes.
|
|
454
|
+
*/
|
|
455
|
+
orderProperty?: Extract<keyof M, string>;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Configuration for Kanban board view mode.
|
|
460
|
+
* @group Collections
|
|
461
|
+
*/
|
|
462
|
+
export interface KanbanConfig<M extends Record<string, any> = any> {
|
|
463
|
+
/**
|
|
464
|
+
* Property key to use for Kanban board columns.
|
|
465
|
+
* Must reference a string property with enumValues defined.
|
|
466
|
+
* Entities will be grouped into columns based on this property's value.
|
|
467
|
+
* The column order is determined by the order of enumValues in the property.
|
|
468
|
+
*/
|
|
469
|
+
columnProperty: Extract<keyof M, string>;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* View mode for displaying a collection.
|
|
474
|
+
* @group Collections
|
|
475
|
+
*/
|
|
476
|
+
export type ViewMode = "table" | "cards" | "kanban";
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Parameter passed to the `Actions` prop in the collection configuration.
|
|
480
|
+
* The component will receive this prop when it is rendered in the collection
|
|
481
|
+
* toolbar.
|
|
482
|
+
*
|
|
483
|
+
* @group Models
|
|
484
|
+
*/
|
|
485
|
+
export interface CollectionActionsProps<M extends Record<string, any> = any, USER extends User = User, EC extends EntityCollection<M> = EntityCollection<M>> {
|
|
486
|
+
/**
|
|
487
|
+
* Full collection path of this entity. This is the full path, like
|
|
488
|
+
* `users/1234/addresses`
|
|
489
|
+
*/
|
|
490
|
+
path: string;
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Path of the last collection, like `addresses`
|
|
494
|
+
*/
|
|
495
|
+
relativePath: string;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Array of the parent path segments like `['users']`
|
|
499
|
+
*/
|
|
500
|
+
parentCollectionIds: string[];
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* The collection configuration
|
|
504
|
+
*/
|
|
505
|
+
collection: EC;
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Use this controller to get the selected entities and to update the
|
|
509
|
+
* selected entities state.
|
|
510
|
+
*/
|
|
511
|
+
selectionController: SelectionController<M>;
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Use this controller to get the table controller and to update the
|
|
515
|
+
* table controller state.
|
|
516
|
+
*/
|
|
517
|
+
tableController: EntityTableController<M>;
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Context of the app status
|
|
521
|
+
*/
|
|
522
|
+
context: RebaseContext<USER>;
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Count of the entities in this collection.
|
|
526
|
+
* undefined means the count is still loading.
|
|
527
|
+
*/
|
|
528
|
+
collectionEntitiesCount?: number;
|
|
529
|
+
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Use this controller to retrieve the selected entities or modify them in
|
|
534
|
+
* an {@link EntityCollection}
|
|
535
|
+
* @group Models
|
|
536
|
+
*/
|
|
537
|
+
export type SelectionController<M extends Record<string, any> = any> = {
|
|
538
|
+
selectedEntities: Entity<M>[];
|
|
539
|
+
setSelectedEntities: Dispatch<SetStateAction<Entity<M>[]>>;
|
|
540
|
+
isEntitySelected: (entity: Entity<M>) => boolean;
|
|
541
|
+
toggleEntitySelection: (entity: Entity<M>, newSelectedState?: boolean) => void;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Filter conditions in a `Query.where()` clause are specified using the
|
|
546
|
+
* strings `<`, `<=`, `==`, `>=`, `>`, `array-contains`, `in`, and `array-contains-any`.
|
|
547
|
+
* @group Models
|
|
548
|
+
*/
|
|
549
|
+
export type WhereFilterOp =
|
|
550
|
+
| "<"
|
|
551
|
+
| "<="
|
|
552
|
+
| "=="
|
|
553
|
+
| "!="
|
|
554
|
+
| ">="
|
|
555
|
+
| ">"
|
|
556
|
+
| "array-contains"
|
|
557
|
+
| "in"
|
|
558
|
+
| "not-in"
|
|
559
|
+
| "array-contains-any";
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Used to define filters applied in collections
|
|
563
|
+
*
|
|
564
|
+
* e.g. `{ age: [">=", 18] }`
|
|
565
|
+
*
|
|
566
|
+
* @group Models
|
|
567
|
+
*/
|
|
568
|
+
export type FilterValues<Key extends string> =
|
|
569
|
+
Partial<Record<Key, [WhereFilterOp, any]>>;
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Used to indicate valid filter combinations (e.g. created in Firestore)
|
|
573
|
+
* If the user selects a specific filter/sort combination, the CMS checks if it's
|
|
574
|
+
* valid, otherwise it reverts to the simpler valid case
|
|
575
|
+
* @group Models
|
|
576
|
+
*/
|
|
577
|
+
export type FilterCombination<Key extends string> = Partial<Record<Key, "asc" | "desc">>;
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Sizes in which a collection can be rendered
|
|
581
|
+
* @group Models
|
|
582
|
+
*/
|
|
583
|
+
export type CollectionSize = "xs" | "s" | "m" | "l" | "xl";
|
|
584
|
+
|
|
585
|
+
export type AdditionalFieldDelegateProps<M extends Record<string, any> = any, USER extends User = User> = {
|
|
586
|
+
entity: Entity<M>,
|
|
587
|
+
context: RebaseContext<USER>
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Use this interface for adding additional fields to entity collection views and forms.
|
|
592
|
+
* @group Models
|
|
593
|
+
*/
|
|
594
|
+
export interface AdditionalFieldDelegate<M extends Record<string, any> = any,
|
|
595
|
+
USER extends User = User> {
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* ID of this column. You can use this id in the `properties` field of the
|
|
599
|
+
* collection in any order you want
|
|
600
|
+
*/
|
|
601
|
+
key: string;
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Header of this column
|
|
605
|
+
*/
|
|
606
|
+
name: string;
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Width of the generated column in pixels
|
|
610
|
+
*/
|
|
611
|
+
width?: number;
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Builder for the content of the cell for this column
|
|
615
|
+
*/
|
|
616
|
+
Builder?: React.ComponentType<AdditionalFieldDelegateProps<M, USER>>;
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* If this column needs to update dynamically based on other properties,
|
|
620
|
+
* you can define an array of keys as strings with the
|
|
621
|
+
* `dependencies` prop.
|
|
622
|
+
* e.g. ["name", "surname"]
|
|
623
|
+
* This is a performance optimization, if you don't define dependencies
|
|
624
|
+
* it will be updated in every render.
|
|
625
|
+
*/
|
|
626
|
+
dependencies?: Extract<keyof M, string>[];
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Use this prop to define the value of the column as a string or number.
|
|
630
|
+
* This is the value that will be used for exporting the collection.
|
|
631
|
+
* If `Builder` is defined, this prop will be ignored in the collection
|
|
632
|
+
* view.
|
|
633
|
+
* @param entity
|
|
634
|
+
*/
|
|
635
|
+
value?: (props: {
|
|
636
|
+
entity: Entity<M>,
|
|
637
|
+
context: RebaseContext
|
|
638
|
+
}) => string | number | Promise<string | number> | undefined;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* You can use this builder to render a custom panel in the entity detail view.
|
|
643
|
+
* It gets rendered as a tab.
|
|
644
|
+
* @group Models
|
|
645
|
+
*/
|
|
646
|
+
export type EntityCustomView<M extends Record<string, any> = any> =
|
|
647
|
+
{
|
|
648
|
+
/**
|
|
649
|
+
* Key of this custom view.
|
|
650
|
+
*/
|
|
651
|
+
key: string;
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Name of this custom view.
|
|
655
|
+
*/
|
|
656
|
+
name: string;
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Render this custom view in the tab of the entity view, instead of the name
|
|
660
|
+
*/
|
|
661
|
+
tabComponent?: React.ReactNode;
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* If set to true, the actions of the entity (save, discard,delete) will be
|
|
665
|
+
* included in the view. By default the actions are located in the right or bottom,
|
|
666
|
+
* based on the screen size. You can force the actions to be located at the bottom
|
|
667
|
+
* by setting this prop to "bottom".
|
|
668
|
+
*/
|
|
669
|
+
includeActions?: boolean | "bottom";
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Builder for rendering the custom view
|
|
673
|
+
*/
|
|
674
|
+
Builder?: React.ComponentType<EntityCustomViewParams<M>>;
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Position of this tab in the entity view. Defaults to `end`.
|
|
678
|
+
*/
|
|
679
|
+
position?: "start" | "end";
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Parameters passed to the builder in charge of rendering a custom panel for
|
|
684
|
+
* an entity view.
|
|
685
|
+
* @group Models
|
|
686
|
+
*/
|
|
687
|
+
export interface EntityCustomViewParams<M extends Record<string, any> = any> {
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* collection used by this entity
|
|
691
|
+
*/
|
|
692
|
+
collection: EntityCollection<M>;
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Entity that this view refers to. It can be undefined if the entity is new
|
|
696
|
+
*/
|
|
697
|
+
entity?: Entity<M>;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Modified values in the form that have not been saved yet.
|
|
701
|
+
* If the entity is not new and the values are not modified, these values
|
|
702
|
+
* are the same as in `entity`
|
|
703
|
+
*/
|
|
704
|
+
modifiedValues?: EntityValues<M>;
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Use the form context to access the form state and methods
|
|
708
|
+
*/
|
|
709
|
+
formContext: FormContext;
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* If this is a subcollection, this is the path of the parent collections
|
|
713
|
+
*/
|
|
714
|
+
parentCollectionIds?: string[];
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export type InferCollectionType<S extends EntityCollection> = S extends EntityCollection<infer M> ? M : never;
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Used in the {@link EntityCollection#defaultSelectedView} to define the default
|
|
721
|
+
* @group Models
|
|
722
|
+
*/
|
|
723
|
+
export type DefaultSelectedViewBuilder = (params: DefaultSelectedViewParams) => string | undefined;
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Used in the {@link EntityCollection#defaultSelectedView} to define the default
|
|
727
|
+
* @group Models
|
|
728
|
+
*/
|
|
729
|
+
export type DefaultSelectedViewParams = {
|
|
730
|
+
status?: EntityStatus;
|
|
731
|
+
entityId?: string | number;
|
|
732
|
+
};
|
|
733
|
+
/**
|
|
734
|
+
* You can use this controller to control the table view of a collection.
|
|
735
|
+
*/
|
|
736
|
+
export type EntityTableController<M extends Record<string, any> = any> = {
|
|
737
|
+
data: Entity<M>[];
|
|
738
|
+
dataLoading: boolean;
|
|
739
|
+
noMoreToLoad: boolean;
|
|
740
|
+
dataLoadingError?: Error;
|
|
741
|
+
filterValues?: FilterValues<Extract<keyof M, string>>;
|
|
742
|
+
setFilterValues?: (filterValues: FilterValues<Extract<keyof M, string>>) => void;
|
|
743
|
+
sortBy?: [Extract<keyof M, string>, "asc" | "desc"];
|
|
744
|
+
setSortBy?: (sortBy?: [Extract<keyof M, string>, "asc" | "desc"]) => void;
|
|
745
|
+
searchString?: string;
|
|
746
|
+
setSearchString?: (searchString?: string) => void;
|
|
747
|
+
clearFilter?: () => void;
|
|
748
|
+
itemCount?: number;
|
|
749
|
+
setItemCount?: (itemCount: number) => void;
|
|
750
|
+
initialScroll?: number;
|
|
751
|
+
onScroll?: (props: {
|
|
752
|
+
scrollDirection: "forward" | "backward",
|
|
753
|
+
scrollOffset: number,
|
|
754
|
+
scrollUpdateWasRequested: boolean
|
|
755
|
+
}) => void;
|
|
756
|
+
paginationEnabled?: boolean;
|
|
757
|
+
pageSize?: number;
|
|
758
|
+
checkFilterCombination?: (filterValues: FilterValues<any>,
|
|
759
|
+
sortBy?: [string, "asc" | "desc"]) => boolean;
|
|
760
|
+
popupCell?: SelectedCellProps<M>;
|
|
761
|
+
setPopupCell?: (popupCell?: SelectedCellProps<M>) => void;
|
|
762
|
+
|
|
763
|
+
onAddColumn?: (column: string) => void;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
export type SelectedCellProps<M extends Record<string, any> = any> = {
|
|
767
|
+
propertyKey: Extract<keyof M, string>;
|
|
768
|
+
cellRect: DOMRect;
|
|
769
|
+
width: number;
|
|
770
|
+
height: number;
|
|
771
|
+
entityPath: string;
|
|
772
|
+
entityId: string | number;
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* SQL operation that a policy applies to.
|
|
777
|
+
* @group Models
|
|
778
|
+
*/
|
|
779
|
+
export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all";
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Flexible Row Level Security rule for a collection.
|
|
783
|
+
*
|
|
784
|
+
* Inspired by Supabase's approach to PostgreSQL RLS. Rules can range from
|
|
785
|
+
* simple convenience shortcuts to fully custom SQL expressions, giving you the
|
|
786
|
+
* full power of PostgreSQL Row Level Security.
|
|
787
|
+
*
|
|
788
|
+
* The authenticated user's identity is available in raw SQL via:
|
|
789
|
+
* - `auth.uid()` — the user's ID
|
|
790
|
+
* - `auth.roles()` — comma-separated app role IDs
|
|
791
|
+
* - `auth.jwt()` — full JWT claims as JSONB
|
|
792
|
+
*
|
|
793
|
+
* These are set automatically per-transaction by the backend.
|
|
794
|
+
*
|
|
795
|
+
* **How rules combine:** PostgreSQL evaluates all matching policies for an
|
|
796
|
+
* operation. Permissive rules are OR'd together (any one passing is enough).
|
|
797
|
+
* Restrictive rules are AND'd (all must pass). This mirrors Supabase behavior.
|
|
798
|
+
*
|
|
799
|
+
* @group Models
|
|
800
|
+
*/
|
|
801
|
+
export interface SecurityRule {
|
|
802
|
+
/**
|
|
803
|
+
* Optional human-readable name for the policy.
|
|
804
|
+
* If not provided, one will be auto-generated from the table name and operation.
|
|
805
|
+
* Must be unique per table.
|
|
806
|
+
*
|
|
807
|
+
* When using `operations` (array), each generated policy will have the
|
|
808
|
+
* operation name appended, e.g. `"owner_access_select"`, `"owner_access_update"`.
|
|
809
|
+
*/
|
|
810
|
+
name?: string;
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Which SQL operation this policy applies to.
|
|
814
|
+
* Use this when the policy targets a single operation or all operations.
|
|
815
|
+
*
|
|
816
|
+
* For multiple specific operations, use `operations` (array) instead.
|
|
817
|
+
* If neither is specified, defaults to `"all"`.
|
|
818
|
+
*
|
|
819
|
+
* @default "all"
|
|
820
|
+
*/
|
|
821
|
+
operation?: SecurityOperation;
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Array of SQL operations this policy applies to.
|
|
825
|
+
* The compiler will generate one PostgreSQL policy per operation, sharing
|
|
826
|
+
* the same configuration.
|
|
827
|
+
*
|
|
828
|
+
* This reduces boilerplate when the same rule applies to multiple (but not all)
|
|
829
|
+
* operations.
|
|
830
|
+
*
|
|
831
|
+
* Takes precedence over `operation` (singular) if both are specified.
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* // Same rule for select and update
|
|
835
|
+
* { operations: ["select", "update"], ownerField: "user_id" }
|
|
836
|
+
*
|
|
837
|
+
* @example
|
|
838
|
+
* // Equivalent to operation: "all"
|
|
839
|
+
* { operations: ["all"], ownerField: "user_id" }
|
|
840
|
+
*/
|
|
841
|
+
operations?: SecurityOperation[];
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Whether this policy is `"permissive"` (default) or `"restrictive"`.
|
|
845
|
+
*
|
|
846
|
+
* - **permissive**: Multiple permissive policies for the same operation are
|
|
847
|
+
* OR'd together — if *any* passes, access is granted.
|
|
848
|
+
* - **restrictive**: Restrictive policies are AND'd with all permissive
|
|
849
|
+
* policies — they act as additional gates that *must* also pass.
|
|
850
|
+
*
|
|
851
|
+
* This is the same model as PostgreSQL / Supabase.
|
|
852
|
+
*
|
|
853
|
+
* @default "permissive"
|
|
854
|
+
*/
|
|
855
|
+
mode?: "permissive" | "restrictive";
|
|
856
|
+
|
|
857
|
+
// ── Convenience shortcuts ───────────────────────────────────────────
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* **Shortcut.** The property (column) that stores the owner's user ID.
|
|
861
|
+
* Generates a USING/WITH CHECK clause like:
|
|
862
|
+
* `<column> = auth.uid()`
|
|
863
|
+
*
|
|
864
|
+
* Cannot be combined with `using` / `withCheck` / `access`.
|
|
865
|
+
*
|
|
866
|
+
* @example
|
|
867
|
+
* { operation: "all", ownerField: "user_id" }
|
|
868
|
+
*/
|
|
869
|
+
ownerField?: string;
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* **Shortcut.** Grant unrestricted row access (no row filtering) for this operation.
|
|
873
|
+
* Generates `USING (true)`.
|
|
874
|
+
*
|
|
875
|
+
* This means "no row-level filter", NOT "anonymous/unauthenticated access".
|
|
876
|
+
* Authentication is still enforced at the API layer — this only controls which
|
|
877
|
+
* *rows* authenticated users can see.
|
|
878
|
+
*
|
|
879
|
+
* Typically used alone for genuinely public read endpoints, or combined with
|
|
880
|
+
* `roles` to give certain roles an unfiltered view of the table.
|
|
881
|
+
*
|
|
882
|
+
* Cannot be combined with `using` / `withCheck` / `ownerField`.
|
|
883
|
+
*
|
|
884
|
+
* @example
|
|
885
|
+
* // Public read (any authenticated user sees all rows)
|
|
886
|
+
* { operation: "select", access: "public" }
|
|
887
|
+
*/
|
|
888
|
+
access?: "public";
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* **Shortcut.** Restrict this rule to users that have one of these
|
|
892
|
+
* application-level roles.
|
|
893
|
+
*
|
|
894
|
+
* **Important:** These are NOT native PostgreSQL database roles. They are
|
|
895
|
+
* application roles managed by Rebase, stored in the `rebase_user_roles`
|
|
896
|
+
* table, and injected into each transaction via `auth.roles()`.
|
|
897
|
+
*
|
|
898
|
+
* Generates a condition like:
|
|
899
|
+
* `auth.roles() ~ '<role1>|<role2>'`
|
|
900
|
+
*
|
|
901
|
+
* Can be combined with `ownerField`, `access`, or raw `using`/`withCheck`.
|
|
902
|
+
* When combined, the role check is AND'd with the other condition.
|
|
903
|
+
*
|
|
904
|
+
* @example
|
|
905
|
+
* // Only admins can delete
|
|
906
|
+
* { operation: "delete", roles: ["admin"] }
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* // Admins have unfiltered read access to all rows
|
|
910
|
+
* { operation: "select", roles: ["admin"], using: "true" }
|
|
911
|
+
*/
|
|
912
|
+
roles?: string[];
|
|
913
|
+
|
|
914
|
+
// ── Raw SQL expressions (full power) ────────────────────────────────
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Raw SQL expression for the `USING` clause.
|
|
918
|
+
* This controls which *existing* rows are visible / can be modified / deleted.
|
|
919
|
+
* Applied to SELECT, UPDATE, and DELETE.
|
|
920
|
+
*
|
|
921
|
+
* You can reference columns via `{column_name}` which will be resolved to
|
|
922
|
+
* `table.column_name` in the generated Drizzle code. You can also use any
|
|
923
|
+
* valid PostgreSQL expression.
|
|
924
|
+
*
|
|
925
|
+
* Cannot be combined with `ownerField` or `access`.
|
|
926
|
+
*
|
|
927
|
+
* @example
|
|
928
|
+
* // Rows published in the last 30 days are visible
|
|
929
|
+
* { operation: "select", using: "{published_at} > now() - interval '30 days'" }
|
|
930
|
+
*
|
|
931
|
+
* @example
|
|
932
|
+
* // Only the owner, or users with 'moderator' role
|
|
933
|
+
* {
|
|
934
|
+
* operation: "select",
|
|
935
|
+
* using: "{user_id} = auth.uid() OR auth.roles() ~ 'moderator'"
|
|
936
|
+
* }
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* // Cross-table subquery: only if user belongs to the org
|
|
940
|
+
* {
|
|
941
|
+
* operation: "select",
|
|
942
|
+
* using: "EXISTS (SELECT 1 FROM org_members WHERE org_members.org_id = {org_id} AND org_members.user_id = auth.uid())"
|
|
943
|
+
* }
|
|
944
|
+
*/
|
|
945
|
+
using?: string;
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Raw SQL expression for the `WITH CHECK` clause.
|
|
949
|
+
* This controls which *new/updated* row values are allowed.
|
|
950
|
+
* Applied to INSERT and UPDATE.
|
|
951
|
+
*
|
|
952
|
+
* Same syntax as `using` — use `{column_name}` to reference columns.
|
|
953
|
+
*
|
|
954
|
+
* **Important for UPDATE:** PostgreSQL evaluates two row states — the
|
|
955
|
+
* *existing* row (`USING`) and the *incoming new* row (`WITH CHECK`).
|
|
956
|
+
* If you only specify `using`, the same expression is used for both.
|
|
957
|
+
* For security-sensitive updates, always specify `withCheck` explicitly
|
|
958
|
+
* to constrain what the new row values can be.
|
|
959
|
+
*
|
|
960
|
+
* If not provided on INSERT/UPDATE policies, falls back to `using`
|
|
961
|
+
* (which matches PostgreSQL's own default behavior).
|
|
962
|
+
*
|
|
963
|
+
* Cannot be combined with `ownerField` or `access`.
|
|
964
|
+
*
|
|
965
|
+
* @example
|
|
966
|
+
* // Users can only insert rows where they are the owner
|
|
967
|
+
* { operation: "insert", withCheck: "{user_id} = auth.uid()" }
|
|
968
|
+
*
|
|
969
|
+
* @example
|
|
970
|
+
* // Prevent changing the status to 'archived' unless admin
|
|
971
|
+
* {
|
|
972
|
+
* operation: "update",
|
|
973
|
+
* using: "{user_id} = auth.uid()",
|
|
974
|
+
* withCheck: "{status} != 'archived' OR auth.roles() ~ 'admin'"
|
|
975
|
+
* }
|
|
976
|
+
*
|
|
977
|
+
* @example
|
|
978
|
+
* // Restrictive gate: prevent locking AND unlocking unless admin.
|
|
979
|
+
* // `using` checks the old row state, `withCheck` checks the new.
|
|
980
|
+
* {
|
|
981
|
+
* operation: "update",
|
|
982
|
+
* mode: "restrictive",
|
|
983
|
+
* using: "{is_locked} = false",
|
|
984
|
+
* withCheck: "{is_locked} = false"
|
|
985
|
+
* }
|
|
986
|
+
*/
|
|
987
|
+
withCheck?: string;
|
|
988
|
+
|
|
989
|
+
// ── Advanced: native PostgreSQL role targeting ───────────────────────
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* **Advanced.** Native PostgreSQL database roles the policy applies to.
|
|
993
|
+
*
|
|
994
|
+
* By default, all generated policies target the `public` role (i.e.
|
|
995
|
+
* every database connection). This is correct for most setups where
|
|
996
|
+
* a single database role is used for all connections.
|
|
997
|
+
*
|
|
998
|
+
* **Important:** These are NOT the same as the application-level `roles`
|
|
999
|
+
* (admin, editor, viewer, etc.) — those are enforced in the USING/WITH
|
|
1000
|
+
* CHECK clauses via `auth.roles()`. This field controls the PostgreSQL
|
|
1001
|
+
* `TO` clause in `CREATE POLICY ... TO role_name`.
|
|
1002
|
+
*
|
|
1003
|
+
* Use this if you have dedicated PostgreSQL roles (e.g. `app_read`,
|
|
1004
|
+
* `app_write`) and want policies to target specific ones.
|
|
1005
|
+
*
|
|
1006
|
+
* @default ["public"]
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* // Only apply this policy when connected as `app_role`
|
|
1010
|
+
* { operation: "select", access: "public", pgRoles: ["app_role"] }
|
|
1011
|
+
*/
|
|
1012
|
+
pgRoles?: string[];
|
|
1013
|
+
}
|