@rebasepro/types 0.8.0 → 0.9.1-canary.09aaf62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/dist/controllers/auth.d.ts +7 -1
- package/dist/controllers/client.d.ts +204 -6
- package/dist/controllers/collection_registry.d.ts +3 -3
- package/dist/controllers/customization_controller.d.ts +1 -1
- package/dist/controllers/data.d.ts +309 -35
- package/dist/controllers/data_driver.d.ts +92 -37
- package/dist/controllers/email.d.ts +2 -2
- package/dist/controllers/index.d.ts +1 -1
- package/dist/controllers/local_config_persistence.d.ts +4 -4
- package/dist/controllers/navigation.d.ts +2 -2
- package/dist/controllers/registry.d.ts +21 -8
- package/dist/controllers/{side_entity_controller.d.ts → side_panel_controller.d.ts} +7 -7
- package/dist/controllers/storage.d.ts +39 -0
- package/dist/errors.d.ts +64 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +160 -15
- package/dist/index.es.js.map +1 -1
- package/dist/rebase_context.d.ts +8 -4
- package/dist/types/auth_adapter.d.ts +29 -4
- package/dist/types/backend.d.ts +33 -26
- package/dist/types/backup.d.ts +20 -0
- package/dist/types/builders.d.ts +2 -2
- package/dist/types/collections.d.ts +84 -75
- package/dist/types/component_overrides.d.ts +61 -3
- package/dist/types/cron.d.ts +11 -2
- package/dist/types/data_source.d.ts +15 -2
- package/dist/types/database_adapter.d.ts +21 -4
- package/dist/types/entities.d.ts +7 -7
- package/dist/types/entity_actions.d.ts +7 -7
- package/dist/types/entity_callbacks.d.ts +39 -39
- package/dist/types/entity_views.d.ts +3 -3
- package/dist/types/filter-operators.d.ts +62 -17
- package/dist/types/index.d.ts +1 -0
- package/dist/types/modify_collections.d.ts +2 -2
- package/dist/types/plugins.d.ts +9 -9
- package/dist/types/policy.d.ts +111 -11
- package/dist/types/properties.d.ts +54 -9
- package/dist/types/relations.d.ts +3 -3
- package/dist/types/slots.d.ts +14 -14
- package/dist/types/translations.d.ts +5 -1
- package/dist/types/user_management_delegate.d.ts +8 -2
- package/dist/types/websockets.d.ts +46 -13
- package/dist/users/user.d.ts +21 -9
- package/package.json +5 -6
- package/src/controllers/auth.tsx +7 -1
- package/src/controllers/client.ts +235 -7
- package/src/controllers/collection_registry.ts +3 -3
- package/src/controllers/customization_controller.tsx +1 -1
- package/src/controllers/data.ts +330 -39
- package/src/controllers/data_driver.ts +93 -40
- package/src/controllers/email.ts +2 -2
- package/src/controllers/index.ts +1 -1
- package/src/controllers/local_config_persistence.tsx +4 -4
- package/src/controllers/navigation.ts +2 -2
- package/src/controllers/registry.ts +22 -8
- package/src/controllers/{side_entity_controller.tsx → side_panel_controller.tsx} +7 -7
- package/src/controllers/storage.ts +60 -1
- package/src/errors.ts +80 -0
- package/src/index.ts +1 -0
- package/src/rebase_context.tsx +8 -4
- package/src/types/auth_adapter.ts +29 -4
- package/src/types/backend.ts +44 -36
- package/src/types/backup.ts +26 -0
- package/src/types/builders.ts +2 -2
- package/src/types/collections.ts +101 -91
- package/src/types/component_overrides.ts +72 -5
- package/src/types/cron.ts +11 -2
- package/src/types/data_source.ts +24 -2
- package/src/types/database_adapter.ts +19 -4
- package/src/types/entities.ts +7 -7
- package/src/types/entity_actions.tsx +7 -7
- package/src/types/entity_callbacks.ts +42 -42
- package/src/types/entity_views.tsx +3 -3
- package/src/types/filter-operators.ts +96 -23
- package/src/types/index.ts +1 -0
- package/src/types/modify_collections.tsx +2 -2
- package/src/types/plugins.tsx +9 -9
- package/src/types/policy.ts +114 -9
- package/src/types/properties.ts +58 -9
- package/src/types/relations.ts +3 -3
- package/src/types/slots.tsx +14 -14
- package/src/types/translations.ts +5 -1
- package/src/types/user_management_delegate.ts +8 -2
- package/src/types/websockets.ts +43 -14
- package/src/users/user.ts +22 -9
- package/dist/index.umd.js +0 -458
- package/dist/index.umd.js.map +0 -1
package/src/types/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from "./entity_views";
|
|
|
26
26
|
export * from "./data_source";
|
|
27
27
|
export * from "./storage_source";
|
|
28
28
|
export * from "./cron";
|
|
29
|
+
export * from "./backup";
|
|
29
30
|
export * from "./component_ref";
|
|
30
31
|
export * from "./auth_adapter";
|
|
31
32
|
export * from "./database_adapter";
|
package/src/types/plugins.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from "react";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { CollectionConfig, CollectionActionsProps, EntityTableController, SelectionController } from "./collections";
|
|
4
4
|
import type { EntityStatus } from "./entities";
|
|
5
5
|
import type { InferPropertyType, Property } from "./properties";
|
|
6
6
|
import type { FormContext } from "./entity_views";
|
|
@@ -181,19 +181,19 @@ export interface PluginHooks {
|
|
|
181
181
|
/**
|
|
182
182
|
* Modify a single collection before it is rendered (synchronous).
|
|
183
183
|
*/
|
|
184
|
-
modifyCollection?: (collection:
|
|
184
|
+
modifyCollection?: (collection: CollectionConfig) => CollectionConfig;
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
187
|
* Async version of modifyCollection — supports fetching remote config.
|
|
188
188
|
* Runs during navigation resolution. If provided alongside `modifyCollection`,
|
|
189
189
|
* the sync version runs first, then the async version.
|
|
190
190
|
*/
|
|
191
|
-
modifyCollectionAsync?: (collection:
|
|
191
|
+
modifyCollectionAsync?: (collection: CollectionConfig) => Promise<CollectionConfig>;
|
|
192
192
|
|
|
193
193
|
/**
|
|
194
194
|
* Modify, add or remove collections.
|
|
195
195
|
*/
|
|
196
|
-
injectCollections?: (collections:
|
|
196
|
+
injectCollections?: (collections: CollectionConfig[]) => CollectionConfig[];
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
199
|
* Callback called when columns are reordered via drag and drop.
|
|
@@ -202,7 +202,7 @@ export interface PluginHooks {
|
|
|
202
202
|
fullPath: string;
|
|
203
203
|
parentCollectionSlugs: string[];
|
|
204
204
|
parentEntityIds: string[];
|
|
205
|
-
collection:
|
|
205
|
+
collection: CollectionConfig;
|
|
206
206
|
newPropertiesOrder: string[];
|
|
207
207
|
}) => void;
|
|
208
208
|
|
|
@@ -213,7 +213,7 @@ export interface PluginHooks {
|
|
|
213
213
|
fullPath: string;
|
|
214
214
|
parentCollectionSlugs: string[];
|
|
215
215
|
parentEntityIds: string[];
|
|
216
|
-
collection:
|
|
216
|
+
collection: CollectionConfig;
|
|
217
217
|
kanbanColumnProperty: string;
|
|
218
218
|
newColumnsOrder: string[];
|
|
219
219
|
}) => void;
|
|
@@ -291,7 +291,7 @@ export interface FieldBuilderConfig {
|
|
|
291
291
|
* Props passed to home page collection card action components.
|
|
292
292
|
* @group Models
|
|
293
293
|
*/
|
|
294
|
-
export interface PluginHomePageActionsProps<EP extends object = object, M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User, EC extends
|
|
294
|
+
export interface PluginHomePageActionsProps<EP extends object = object, M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User, EC extends CollectionConfig<M> = CollectionConfig<M>> {
|
|
295
295
|
slug: string;
|
|
296
296
|
collection: EC;
|
|
297
297
|
context: RebaseContext<USER>;
|
|
@@ -301,7 +301,7 @@ export interface PluginHomePageActionsProps<EP extends object = object, M extend
|
|
|
301
301
|
* Props passed to form action components in entity edit/form views.
|
|
302
302
|
* @group Models
|
|
303
303
|
*/
|
|
304
|
-
export interface PluginFormActionProps<USER extends User = User, EC extends
|
|
304
|
+
export interface PluginFormActionProps<USER extends User = User, EC extends CollectionConfig = CollectionConfig> {
|
|
305
305
|
entityId?: string | number;
|
|
306
306
|
path: string;
|
|
307
307
|
parentCollectionSlugs: string[];
|
|
@@ -318,7 +318,7 @@ export interface PluginFormActionProps<USER extends User = User, EC extends Enti
|
|
|
318
318
|
* Parameters passed to the field builder wrap function.
|
|
319
319
|
* @group Models
|
|
320
320
|
*/
|
|
321
|
-
export type PluginFieldBuilderParams<M extends Record<string, unknown> = Record<string, unknown>, EC extends
|
|
321
|
+
export type PluginFieldBuilderParams<M extends Record<string, unknown> = Record<string, unknown>, EC extends CollectionConfig<M> = CollectionConfig<M>> = {
|
|
322
322
|
fieldConfigId: string;
|
|
323
323
|
propertyKey: string;
|
|
324
324
|
property: Property;
|
package/src/types/policy.ts
CHANGED
|
@@ -27,8 +27,28 @@ export type PolicyExpression =
|
|
|
27
27
|
| RolesOverlapPolicyExpression
|
|
28
28
|
| RolesContainPolicyExpression
|
|
29
29
|
| AuthenticatedPolicyExpression
|
|
30
|
+
| ServerContextPolicyExpression
|
|
31
|
+
| ExistsInPolicyExpression
|
|
30
32
|
| RawPolicyExpression;
|
|
31
33
|
|
|
34
|
+
/**
|
|
35
|
+
* The id a request without a logged-in user reports as `auth.uid()`.
|
|
36
|
+
*
|
|
37
|
+
* A user-context request always sets `app.user_id`: blank would read back as
|
|
38
|
+
* `NULL`, and `NULL` is how the trusted server context is recognised, so an
|
|
39
|
+
* anonymous visitor would be promoted to server privileges. The driver
|
|
40
|
+
* therefore substitutes this sentinel at the single chokepoint where the GUC
|
|
41
|
+
* is set.
|
|
42
|
+
*
|
|
43
|
+
* The consequence for policy authors is that **`auth.uid() IS NOT NULL` is a
|
|
44
|
+
* tautology on the user path** — it is true for anonymous visitors too. Use
|
|
45
|
+
* {@link policy.authenticated} (or `auth.uid() <> 'anonymous'`) to mean "signed
|
|
46
|
+
* in", and {@link policy.serverContext} to mean "the trusted server context".
|
|
47
|
+
*
|
|
48
|
+
* @group Models
|
|
49
|
+
*/
|
|
50
|
+
export const ANONYMOUS_USER_ID = "anonymous";
|
|
51
|
+
|
|
32
52
|
/** Always allows. Compiles to `true`. @group Models */
|
|
33
53
|
export interface TruePolicyExpression {
|
|
34
54
|
kind: "true";
|
|
@@ -42,13 +62,13 @@ export interface FalsePolicyExpression {
|
|
|
42
62
|
/** Logical AND — every operand must pass. @group Models */
|
|
43
63
|
export interface AndPolicyExpression {
|
|
44
64
|
kind: "and";
|
|
45
|
-
operands: PolicyExpression[];
|
|
65
|
+
operands: readonly PolicyExpression[];
|
|
46
66
|
}
|
|
47
67
|
|
|
48
68
|
/** Logical OR — at least one operand must pass. @group Models */
|
|
49
69
|
export interface OrPolicyExpression {
|
|
50
70
|
kind: "or";
|
|
51
|
-
operands: PolicyExpression[];
|
|
71
|
+
operands: readonly PolicyExpression[];
|
|
52
72
|
}
|
|
53
73
|
|
|
54
74
|
/** Logical negation. @group Models */
|
|
@@ -78,7 +98,7 @@ export interface ComparePolicyExpression {
|
|
|
78
98
|
*/
|
|
79
99
|
export interface RolesOverlapPolicyExpression {
|
|
80
100
|
kind: "rolesOverlap";
|
|
81
|
-
roles: string[];
|
|
101
|
+
roles: readonly string[];
|
|
82
102
|
}
|
|
83
103
|
|
|
84
104
|
/**
|
|
@@ -88,17 +108,85 @@ export interface RolesOverlapPolicyExpression {
|
|
|
88
108
|
*/
|
|
89
109
|
export interface RolesContainPolicyExpression {
|
|
90
110
|
kind: "rolesContain";
|
|
91
|
-
roles: string[];
|
|
111
|
+
roles: readonly string[];
|
|
92
112
|
}
|
|
93
113
|
|
|
94
114
|
/**
|
|
95
|
-
* True when
|
|
115
|
+
* True when a signed-in user is making the request. Compiles to
|
|
116
|
+
* `auth.uid() IS NOT NULL AND auth.uid() <> 'anonymous'`.
|
|
117
|
+
*
|
|
118
|
+
* Both halves are load-bearing. `IS NOT NULL` excludes the server context;
|
|
119
|
+
* the {@link ANONYMOUS_USER_ID} comparison excludes anonymous visitors, who
|
|
120
|
+
* *do* carry a non-null `auth.uid()`. Checking only `IS NOT NULL` grants to
|
|
121
|
+
* everyone — see {@link ANONYMOUS_USER_ID}.
|
|
122
|
+
*
|
|
123
|
+
* `policy.not(policy.authenticated())` therefore means "anonymous visitor or
|
|
124
|
+
* the server context". To single out the server context, use
|
|
125
|
+
* {@link ServerContextPolicyExpression}.
|
|
96
126
|
* @group Models
|
|
97
127
|
*/
|
|
98
128
|
export interface AuthenticatedPolicyExpression {
|
|
99
129
|
kind: "authenticated";
|
|
100
130
|
}
|
|
101
131
|
|
|
132
|
+
/**
|
|
133
|
+
* True only in the trusted **server context** — the built-in flows that run
|
|
134
|
+
* without a user (signup, migrations, `dataAsAdmin`) set no user GUC, so
|
|
135
|
+
* `auth.uid()` is `NULL` for them and only for them. Compiles to
|
|
136
|
+
* `auth.uid() IS NULL`.
|
|
137
|
+
*
|
|
138
|
+
* This is what lets the owner connection satisfy a policy even under FORCE RLS.
|
|
139
|
+
* It is deliberately a primitive rather than `not(authenticated())`: the two
|
|
140
|
+
* meant the same thing while `authenticated` ignored {@link ANONYMOUS_USER_ID},
|
|
141
|
+
* and conflating them is what turns a server-only grant into an anonymous one.
|
|
142
|
+
*
|
|
143
|
+
* The JavaScript evaluator always returns `false` for this node — a client is
|
|
144
|
+
* never the server context.
|
|
145
|
+
* @group Models
|
|
146
|
+
*/
|
|
147
|
+
export interface ServerContextPolicyExpression {
|
|
148
|
+
kind: "serverContext";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Membership / relational access: true when at least one row exists in another
|
|
153
|
+
* collection (a join/membership table) matching `where`. This is what lets you
|
|
154
|
+
* scope reads to "rows whose team the caller belongs to" without an N+1
|
|
155
|
+
* per-row lookup — it compiles to a single correlated `EXISTS` subquery.
|
|
156
|
+
*
|
|
157
|
+
* Inside `where`, {@link FieldPolicyOperand} (`policy.field`) references a column
|
|
158
|
+
* of the joined collection, while {@link OuterFieldPolicyOperand}
|
|
159
|
+
* (`policy.outerField`) references a column of the row being checked (the outer
|
|
160
|
+
* table under RLS). Combine with {@link AuthUidPolicyOperand} to correlate to
|
|
161
|
+
* the caller.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* // documents visible only to members of the document's team:
|
|
166
|
+
* policy.existsIn({
|
|
167
|
+
* collection: "team_members",
|
|
168
|
+
* where: policy.and(
|
|
169
|
+
* policy.compare(policy.field("team_id"), "eq", policy.outerField("team_id")),
|
|
170
|
+
* policy.compare(policy.field("user_id"), "eq", policy.authUid()),
|
|
171
|
+
* ),
|
|
172
|
+
* })
|
|
173
|
+
* // → EXISTS (SELECT 1 FROM team_members _ex0
|
|
174
|
+
* // WHERE _ex0.team_id = documents.team_id AND _ex0.user_id = auth.uid())
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* Postgres-authoritative: like {@link RawPolicyExpression}, the JavaScript
|
|
178
|
+
* evaluator treats it as *unknown* (it cannot run a subquery client-side), so
|
|
179
|
+
* enforcement is always the database's.
|
|
180
|
+
* @group Models
|
|
181
|
+
*/
|
|
182
|
+
export interface ExistsInPolicyExpression {
|
|
183
|
+
kind: "existsIn";
|
|
184
|
+
/** Slug of the collection to search (the join / membership table). */
|
|
185
|
+
collection: string;
|
|
186
|
+
/** Condition evaluated against the joined collection's rows. */
|
|
187
|
+
where: PolicyExpression;
|
|
188
|
+
}
|
|
189
|
+
|
|
102
190
|
/**
|
|
103
191
|
* A raw PostgreSQL boolean expression — the full-power escape hatch.
|
|
104
192
|
*
|
|
@@ -118,6 +206,7 @@ export interface RawPolicyExpression {
|
|
|
118
206
|
*/
|
|
119
207
|
export type PolicyOperand =
|
|
120
208
|
| FieldPolicyOperand
|
|
209
|
+
| OuterFieldPolicyOperand
|
|
121
210
|
| LiteralPolicyOperand
|
|
122
211
|
| AuthUidPolicyOperand
|
|
123
212
|
| AuthRolesPolicyOperand;
|
|
@@ -129,6 +218,18 @@ export interface FieldPolicyOperand {
|
|
|
129
218
|
name: string;
|
|
130
219
|
}
|
|
131
220
|
|
|
221
|
+
/**
|
|
222
|
+
* A column value on the *outer* row when used inside {@link ExistsInPolicyExpression}
|
|
223
|
+
* — i.e. the row the RLS policy is being evaluated for, referenced from within the
|
|
224
|
+
* subquery. Outside an `existsIn` it is equivalent to {@link FieldPolicyOperand}.
|
|
225
|
+
* @group Models
|
|
226
|
+
*/
|
|
227
|
+
export interface OuterFieldPolicyOperand {
|
|
228
|
+
kind: "outerField";
|
|
229
|
+
/** The property/column name on the outer collection. */
|
|
230
|
+
name: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
132
233
|
/** A constant value. @group Models */
|
|
133
234
|
export interface LiteralPolicyOperand {
|
|
134
235
|
kind: "literal";
|
|
@@ -157,16 +258,20 @@ export interface AuthRolesPolicyOperand {
|
|
|
157
258
|
export const policy = {
|
|
158
259
|
true: (): TruePolicyExpression => ({ kind: "true" }),
|
|
159
260
|
false: (): FalsePolicyExpression => ({ kind: "false" }),
|
|
160
|
-
and: (...operands: PolicyExpression[]): AndPolicyExpression => ({ kind: "and", operands }),
|
|
161
|
-
or: (...operands: PolicyExpression[]): OrPolicyExpression => ({ kind: "or", operands }),
|
|
261
|
+
and: (...operands: readonly PolicyExpression[]): AndPolicyExpression => ({ kind: "and", operands: operands as PolicyExpression[] }),
|
|
262
|
+
or: (...operands: readonly PolicyExpression[]): OrPolicyExpression => ({ kind: "or", operands: operands as PolicyExpression[] }),
|
|
162
263
|
not: (operand: PolicyExpression): NotPolicyExpression => ({ kind: "not", operand }),
|
|
163
264
|
compare: (left: PolicyOperand, op: PolicyCompareOperator, right: PolicyOperand): ComparePolicyExpression =>
|
|
164
265
|
({ kind: "compare", op, left, right }),
|
|
165
|
-
rolesOverlap: (roles: string[]): RolesOverlapPolicyExpression => ({ kind: "rolesOverlap", roles }),
|
|
166
|
-
rolesContain: (roles: string[]): RolesContainPolicyExpression => ({ kind: "rolesContain", roles }),
|
|
266
|
+
rolesOverlap: (roles: readonly string[]): RolesOverlapPolicyExpression => ({ kind: "rolesOverlap", roles: roles as string[] }),
|
|
267
|
+
rolesContain: (roles: readonly string[]): RolesContainPolicyExpression => ({ kind: "rolesContain", roles: roles as string[] }),
|
|
167
268
|
authenticated: (): AuthenticatedPolicyExpression => ({ kind: "authenticated" }),
|
|
269
|
+
serverContext: (): ServerContextPolicyExpression => ({ kind: "serverContext" }),
|
|
270
|
+
existsIn: (args: { collection: string; where: PolicyExpression }): ExistsInPolicyExpression =>
|
|
271
|
+
({ kind: "existsIn", collection: args.collection, where: args.where }),
|
|
168
272
|
raw: (sql: string): RawPolicyExpression => ({ kind: "raw", sql }),
|
|
169
273
|
field: (name: string): FieldPolicyOperand => ({ kind: "field", name }),
|
|
274
|
+
outerField: (name: string): OuterFieldPolicyOperand => ({ kind: "outerField", name }),
|
|
170
275
|
literal: (value: string | number | boolean | null): LiteralPolicyOperand => ({ kind: "literal", value }),
|
|
171
276
|
authUid: (): AuthUidPolicyOperand => ({ kind: "authUid" }),
|
|
172
277
|
authRoles: (): AuthRolesPolicyOperand => ({ kind: "authRoles" })
|
package/src/types/properties.ts
CHANGED
|
@@ -2,10 +2,10 @@ import type { ComponentRef } from "./component_ref";
|
|
|
2
2
|
|
|
3
3
|
import type { Entity, EntityReference, EntityRelation, EntityValues, GeoPoint, Vector } from "./entities";
|
|
4
4
|
import type { JoinStep, OnAction, Relation } from "./relations";
|
|
5
|
-
import type {
|
|
5
|
+
import type { CollectionConfig, FilterValues, WhereFilterOp } from "./collections";
|
|
6
6
|
import type { ColorKey, ColorScheme } from "./chips";
|
|
7
7
|
import type { AuthController } from "../controllers/auth";
|
|
8
|
-
import type {
|
|
8
|
+
import type { AfterReadProps, BeforeSaveProps } from "./entity_callbacks";
|
|
9
9
|
import type { User } from "../users";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -16,7 +16,7 @@ export type PropertyCallbacks<T = unknown, M extends Record<string, unknown> = R
|
|
|
16
16
|
/**
|
|
17
17
|
* Callback used after fetching data, to transform the value before rendering
|
|
18
18
|
*/
|
|
19
|
-
afterRead?(props: Omit<
|
|
19
|
+
afterRead?(props: Omit<AfterReadProps<M, USER>, "entity"> & {
|
|
20
20
|
value: T;
|
|
21
21
|
entity: Entity<M> | undefined;
|
|
22
22
|
}): Promise<T> | T;
|
|
@@ -25,7 +25,7 @@ export type PropertyCallbacks<T = unknown, M extends Record<string, unknown> = R
|
|
|
25
25
|
* Callback used before saving, after validation.
|
|
26
26
|
* You can modify the value before it's saved.
|
|
27
27
|
*/
|
|
28
|
-
beforeSave?(props: Omit<
|
|
28
|
+
beforeSave?(props: Omit<BeforeSaveProps<M, USER>, "values"> & {
|
|
29
29
|
value: T;
|
|
30
30
|
previousValue: T | undefined;
|
|
31
31
|
values: Partial<M>;
|
|
@@ -164,6 +164,33 @@ export interface BaseUIConfig<CustomProps = unknown> {
|
|
|
164
164
|
customProps?: CustomProps;
|
|
165
165
|
Field?: ComponentRef<any>;
|
|
166
166
|
Preview?: ComponentRef<any>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Narrow the filter operators offered for this property in collection
|
|
170
|
+
* filter UIs (table header filters and the Filters dialog).
|
|
171
|
+
*
|
|
172
|
+
* The final offered set is the **intersection** of the engine's
|
|
173
|
+
* capabilities, the property-type defaults, and this list — you can only
|
|
174
|
+
* *restrict*, never enable an operator the underlying engine cannot run.
|
|
175
|
+
*
|
|
176
|
+
* Pass an empty array to disable filtering on this property entirely.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* // Email column: exact match, contains, and null check only
|
|
180
|
+
* ui: { filterOperators: ["==", "ilike", "is-null"] }
|
|
181
|
+
*/
|
|
182
|
+
filterOperators?: readonly WhereFilterOp[];
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Replace the filter field rendered for this property in collection
|
|
186
|
+
* filter UIs. The component receives `FilterFieldBindingProps`
|
|
187
|
+
* (property, resolved `operators`, `value`, `setValue`, …).
|
|
188
|
+
*
|
|
189
|
+
* Takes precedence over the collection-level
|
|
190
|
+
* `components["Collection.FilterField"]` override and the built-in
|
|
191
|
+
* per-type filter fields.
|
|
192
|
+
*/
|
|
193
|
+
Filter?: ComponentRef<any>;
|
|
167
194
|
}
|
|
168
195
|
|
|
169
196
|
export interface BaseProperty<CustomProps = unknown> {
|
|
@@ -204,6 +231,20 @@ export interface BaseProperty<CustomProps = unknown> {
|
|
|
204
231
|
*/
|
|
205
232
|
validation?: PropertyValidationSchema;
|
|
206
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Never include this column in an API response.
|
|
236
|
+
*
|
|
237
|
+
* For secrets the server must store and read but no client should ever
|
|
238
|
+
* receive — password hashes, verification tokens. The value is still
|
|
239
|
+
* written and queryable server-side; it is stripped from every row the API
|
|
240
|
+
* serves, for every caller, including admins and service keys.
|
|
241
|
+
*
|
|
242
|
+
* This is a server-side guarantee, unlike `ui.hideFromCollection`, which
|
|
243
|
+
* only stops the admin panel from *rendering* a field and leaves it in the
|
|
244
|
+
* JSON payload.
|
|
245
|
+
*/
|
|
246
|
+
excludeFromApi?: boolean;
|
|
247
|
+
|
|
207
248
|
// NOTE: `defaultValue` is intentionally NOT on BaseProperty.
|
|
208
249
|
// Each concrete property type (StringProperty, NumberProperty, etc.)
|
|
209
250
|
// defines its own typed `defaultValue` for compile-time safety.
|
|
@@ -492,7 +533,7 @@ export interface ReferenceUIConfig extends BaseUIConfig {
|
|
|
492
533
|
}
|
|
493
534
|
|
|
494
535
|
/**
|
|
495
|
-
* A pointer to
|
|
536
|
+
* A pointer to a entity, stored **as a value** on the row (id + path, and
|
|
496
537
|
* optionally a `driver`/`databaseId` for cross-datasource pointers).
|
|
497
538
|
*
|
|
498
539
|
* This is the native primitive of **document databases** — it maps 1:1 to a
|
|
@@ -511,7 +552,7 @@ export interface ReferenceProperty extends BaseProperty {
|
|
|
511
552
|
ui?: ReferenceUIConfig;
|
|
512
553
|
type: "reference";
|
|
513
554
|
/**
|
|
514
|
-
* Default value for new entities. Must be
|
|
555
|
+
* Default value for new entities. Must be a EntityReference.
|
|
515
556
|
*/
|
|
516
557
|
defaultValue?: EntityReference;
|
|
517
558
|
/**
|
|
@@ -575,7 +616,7 @@ export interface RelationProperty extends BaseProperty {
|
|
|
575
616
|
ui?: RelationUIConfig;
|
|
576
617
|
type: "relation";
|
|
577
618
|
/**
|
|
578
|
-
* Default value for new entities. Must be
|
|
619
|
+
* Default value for new entities. Must be a EntityRelation or array of EntityRelation.
|
|
579
620
|
*/
|
|
580
621
|
defaultValue?: EntityRelation | EntityRelation[];
|
|
581
622
|
/**
|
|
@@ -596,7 +637,7 @@ export interface RelationProperty extends BaseProperty {
|
|
|
596
637
|
* When set, the framework treats this property as a self-contained relation
|
|
597
638
|
* definition and no separate `relations[]` entry is needed.
|
|
598
639
|
*/
|
|
599
|
-
target?: string | (() =>
|
|
640
|
+
target?: string | (() => CollectionConfig | string);
|
|
600
641
|
|
|
601
642
|
/**
|
|
602
643
|
* Whether this property references one or many records.
|
|
@@ -664,7 +705,7 @@ export interface RelationProperty extends BaseProperty {
|
|
|
664
705
|
/**
|
|
665
706
|
* Overrides applied to the target collection when rendered as a subcollection tab.
|
|
666
707
|
*/
|
|
667
|
-
overrides?: Partial<
|
|
708
|
+
overrides?: Partial<CollectionConfig>;
|
|
668
709
|
|
|
669
710
|
// ─── Framework-managed fields ───
|
|
670
711
|
|
|
@@ -1006,6 +1047,14 @@ export type StorageConfig = {
|
|
|
1006
1047
|
*/
|
|
1007
1048
|
storageSource?: string;
|
|
1008
1049
|
|
|
1050
|
+
/**
|
|
1051
|
+
* Store files for this property as **public**: they are placed under the
|
|
1052
|
+
* public prefix and served via stable, token-less, permanent, CDN-cacheable
|
|
1053
|
+
* URLs (safe to persist and hotlink). Use for public assets like avatars or
|
|
1054
|
+
* storefront images. Defaults to `false` (private, short-lived signed URLs).
|
|
1055
|
+
*/
|
|
1056
|
+
public?: boolean;
|
|
1057
|
+
|
|
1009
1058
|
/**
|
|
1010
1059
|
* File MIME types that can be uploaded to this reference. Don't specify for
|
|
1011
1060
|
* all.
|
package/src/types/relations.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CollectionConfig } from "./collections";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @group Models
|
|
@@ -20,7 +20,7 @@ export interface Relation {
|
|
|
20
20
|
/**
|
|
21
21
|
* The final collection you want to retrieve records from.
|
|
22
22
|
*/
|
|
23
|
-
target: (() =>
|
|
23
|
+
target: (() => CollectionConfig) | any;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* The nature of the relationship, determining if one or many records are returned.
|
|
@@ -282,7 +282,7 @@ export interface Relation {
|
|
|
282
282
|
*/
|
|
283
283
|
onDelete?: OnAction;
|
|
284
284
|
|
|
285
|
-
overrides?: Partial<
|
|
285
|
+
overrides?: Partial<CollectionConfig>;
|
|
286
286
|
|
|
287
287
|
validation?: {
|
|
288
288
|
required?: boolean;
|
package/src/types/slots.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { CollectionActionsProps, EntityTableController, SelectionController,
|
|
2
|
+
import type { CollectionActionsProps, EntityTableController, SelectionController, CollectionConfig } from "./collections";
|
|
3
3
|
import type { Entity } from "./entities";
|
|
4
4
|
import type { PluginFormActionProps, PluginGenericProps, PluginHomePageActionsProps, PluginHomePageAdditionalCardsProps } from "./plugins";
|
|
5
5
|
import type { Property } from "./properties";
|
|
@@ -128,7 +128,7 @@ export interface NavigationSlotProps {
|
|
|
128
128
|
*/
|
|
129
129
|
export interface CollectionToolbarProps {
|
|
130
130
|
path: string;
|
|
131
|
-
collection:
|
|
131
|
+
collection: CollectionConfig;
|
|
132
132
|
parentCollectionSlugs: string[];
|
|
133
133
|
parentEntityIds: string[];
|
|
134
134
|
tableController: EntityTableController;
|
|
@@ -141,7 +141,7 @@ export interface CollectionToolbarProps {
|
|
|
141
141
|
*/
|
|
142
142
|
export interface CollectionEmptyStateProps {
|
|
143
143
|
path: string;
|
|
144
|
-
collection:
|
|
144
|
+
collection: CollectionConfig;
|
|
145
145
|
parentCollectionSlugs: string[];
|
|
146
146
|
parentEntityIds: string[];
|
|
147
147
|
canCreate: boolean;
|
|
@@ -159,7 +159,7 @@ export interface CollectionHeaderActionProps {
|
|
|
159
159
|
parentCollectionSlugs: string[];
|
|
160
160
|
parentEntityIds: string[];
|
|
161
161
|
onHover: boolean;
|
|
162
|
-
collection:
|
|
162
|
+
collection: CollectionConfig;
|
|
163
163
|
tableController: EntityTableController;
|
|
164
164
|
}
|
|
165
165
|
|
|
@@ -171,7 +171,7 @@ export interface CollectionAddColumnProps {
|
|
|
171
171
|
path: string;
|
|
172
172
|
parentCollectionSlugs: string[];
|
|
173
173
|
parentEntityIds: string[];
|
|
174
|
-
collection:
|
|
174
|
+
collection: CollectionConfig;
|
|
175
175
|
tableController: EntityTableController;
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -181,7 +181,7 @@ export interface CollectionAddColumnProps {
|
|
|
181
181
|
*/
|
|
182
182
|
export interface CollectionErrorProps {
|
|
183
183
|
path: string;
|
|
184
|
-
collection:
|
|
184
|
+
collection: CollectionConfig;
|
|
185
185
|
parentCollectionSlugs?: string[];
|
|
186
186
|
parentEntityIds?: string[];
|
|
187
187
|
error: Error;
|
|
@@ -192,7 +192,7 @@ export interface CollectionErrorProps {
|
|
|
192
192
|
* @group Plugins
|
|
193
193
|
*/
|
|
194
194
|
export interface KanbanSetupProps {
|
|
195
|
-
collection:
|
|
195
|
+
collection: CollectionConfig;
|
|
196
196
|
fullPath: string;
|
|
197
197
|
parentCollectionSlugs: string[];
|
|
198
198
|
parentEntityIds: string[];
|
|
@@ -203,7 +203,7 @@ export interface KanbanSetupProps {
|
|
|
203
203
|
* @group Plugins
|
|
204
204
|
*/
|
|
205
205
|
export interface KanbanAddColumnProps {
|
|
206
|
-
collection:
|
|
206
|
+
collection: CollectionConfig;
|
|
207
207
|
fullPath: string;
|
|
208
208
|
parentCollectionSlugs: string[];
|
|
209
209
|
parentEntityIds: string[];
|
|
@@ -214,14 +214,14 @@ export interface KanbanAddColumnProps {
|
|
|
214
214
|
|
|
215
215
|
/**
|
|
216
216
|
* Props for `entity.row.actions` slot.
|
|
217
|
-
* Rendered for each row in
|
|
217
|
+
* Rendered for each row in a entity collection table.
|
|
218
218
|
* @group Plugins
|
|
219
219
|
*/
|
|
220
220
|
export interface EntityRowActionsProps {
|
|
221
221
|
entity: Entity;
|
|
222
222
|
entityId: string;
|
|
223
223
|
path: string;
|
|
224
|
-
collection:
|
|
224
|
+
collection: CollectionConfig;
|
|
225
225
|
parentCollectionSlugs: string[];
|
|
226
226
|
parentEntityIds: string[];
|
|
227
227
|
selectionController: SelectionController;
|
|
@@ -238,7 +238,7 @@ export interface EntityFieldSlotProps {
|
|
|
238
238
|
property: Property;
|
|
239
239
|
path: string;
|
|
240
240
|
entityId?: string | number;
|
|
241
|
-
collection:
|
|
241
|
+
collection: CollectionConfig;
|
|
242
242
|
context: RebaseContext;
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -249,7 +249,7 @@ export interface EntityFieldSlotProps {
|
|
|
249
249
|
*/
|
|
250
250
|
export interface CollectionFilterPanelProps {
|
|
251
251
|
path: string;
|
|
252
|
-
collection:
|
|
252
|
+
collection: CollectionConfig;
|
|
253
253
|
parentCollectionSlugs: string[];
|
|
254
254
|
parentEntityIds: string[];
|
|
255
255
|
tableController: EntityTableController;
|
|
@@ -290,7 +290,7 @@ export interface ShellToolbarProps {
|
|
|
290
290
|
*/
|
|
291
291
|
export interface CollectionInsightsSlotProps {
|
|
292
292
|
path: string;
|
|
293
|
-
collection:
|
|
293
|
+
collection: CollectionConfig;
|
|
294
294
|
parentCollectionSlugs: string[];
|
|
295
295
|
parentEntityIds: string[];
|
|
296
296
|
}
|
|
@@ -302,6 +302,6 @@ export interface CollectionInsightsSlotProps {
|
|
|
302
302
|
*/
|
|
303
303
|
export interface HomeCardInsightSlotProps {
|
|
304
304
|
slug: string;
|
|
305
|
-
collection:
|
|
305
|
+
collection: CollectionConfig;
|
|
306
306
|
context: RebaseContext;
|
|
307
307
|
}
|
|
@@ -7,7 +7,7 @@ export type DeepPartial<T> = T extends object
|
|
|
7
7
|
: T;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* All user-visible strings used internally by @rebasepro/
|
|
10
|
+
* All user-visible strings used internally by @rebasepro/app.
|
|
11
11
|
* Pass a `DeepPartial<RebaseTranslations>` via the `translations` prop
|
|
12
12
|
* on your Rebase entry-point component to override any key, or to add
|
|
13
13
|
* a new locale.
|
|
@@ -549,6 +549,7 @@ export interface RebaseTranslations {
|
|
|
549
549
|
invitation_sent_title?: string;
|
|
550
550
|
temporary_password?: string;
|
|
551
551
|
temporary_password_description?: string;
|
|
552
|
+
temporary_password_email_failed_description?: string;
|
|
552
553
|
copy_password?: string;
|
|
553
554
|
password_copied?: string;
|
|
554
555
|
|
|
@@ -560,6 +561,9 @@ export interface RebaseTranslations {
|
|
|
560
561
|
reset_password?: string;
|
|
561
562
|
reset_password_success?: string;
|
|
562
563
|
reset_password_confirmation?: string;
|
|
564
|
+
reset_password_send_email?: string;
|
|
565
|
+
reset_password_set_manually?: string;
|
|
566
|
+
reset_password_set_manually_description?: string;
|
|
563
567
|
error_resetting_password?: string;
|
|
564
568
|
|
|
565
569
|
/** Permission-denied empty states */
|
|
@@ -10,8 +10,14 @@ export interface UserCreationResult<USER extends User = User> {
|
|
|
10
10
|
/** Whether an invitation email was sent to the user */
|
|
11
11
|
invitationSent: boolean;
|
|
12
12
|
/**
|
|
13
|
-
* Temporary password
|
|
14
|
-
*
|
|
13
|
+
* Temporary password, present when no invitation email could be delivered —
|
|
14
|
+
* either because no email service is configured, or because delivery failed
|
|
15
|
+
* (see `emailDeliveryFailed`). Returned one-time, to be shared manually.
|
|
15
16
|
*/
|
|
16
17
|
temporaryPassword?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Whether an email service was configured but delivery failed, causing the
|
|
20
|
+
* fallback to `temporaryPassword`. Absent when no email service is configured.
|
|
21
|
+
*/
|
|
22
|
+
emailDeliveryFailed?: boolean;
|
|
17
23
|
}
|