@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.
Files changed (88) hide show
  1. package/README.md +13 -13
  2. package/dist/controllers/auth.d.ts +7 -1
  3. package/dist/controllers/client.d.ts +204 -6
  4. package/dist/controllers/collection_registry.d.ts +3 -3
  5. package/dist/controllers/customization_controller.d.ts +1 -1
  6. package/dist/controllers/data.d.ts +309 -35
  7. package/dist/controllers/data_driver.d.ts +92 -37
  8. package/dist/controllers/email.d.ts +2 -2
  9. package/dist/controllers/index.d.ts +1 -1
  10. package/dist/controllers/local_config_persistence.d.ts +4 -4
  11. package/dist/controllers/navigation.d.ts +2 -2
  12. package/dist/controllers/registry.d.ts +21 -8
  13. package/dist/controllers/{side_entity_controller.d.ts → side_panel_controller.d.ts} +7 -7
  14. package/dist/controllers/storage.d.ts +39 -0
  15. package/dist/errors.d.ts +64 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.es.js +160 -15
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/rebase_context.d.ts +8 -4
  20. package/dist/types/auth_adapter.d.ts +29 -4
  21. package/dist/types/backend.d.ts +33 -26
  22. package/dist/types/backup.d.ts +20 -0
  23. package/dist/types/builders.d.ts +2 -2
  24. package/dist/types/collections.d.ts +84 -75
  25. package/dist/types/component_overrides.d.ts +61 -3
  26. package/dist/types/cron.d.ts +11 -2
  27. package/dist/types/data_source.d.ts +15 -2
  28. package/dist/types/database_adapter.d.ts +21 -4
  29. package/dist/types/entities.d.ts +7 -7
  30. package/dist/types/entity_actions.d.ts +7 -7
  31. package/dist/types/entity_callbacks.d.ts +39 -39
  32. package/dist/types/entity_views.d.ts +3 -3
  33. package/dist/types/filter-operators.d.ts +62 -17
  34. package/dist/types/index.d.ts +1 -0
  35. package/dist/types/modify_collections.d.ts +2 -2
  36. package/dist/types/plugins.d.ts +9 -9
  37. package/dist/types/policy.d.ts +111 -11
  38. package/dist/types/properties.d.ts +54 -9
  39. package/dist/types/relations.d.ts +3 -3
  40. package/dist/types/slots.d.ts +14 -14
  41. package/dist/types/translations.d.ts +5 -1
  42. package/dist/types/user_management_delegate.d.ts +8 -2
  43. package/dist/types/websockets.d.ts +46 -13
  44. package/dist/users/user.d.ts +21 -9
  45. package/package.json +5 -6
  46. package/src/controllers/auth.tsx +7 -1
  47. package/src/controllers/client.ts +235 -7
  48. package/src/controllers/collection_registry.ts +3 -3
  49. package/src/controllers/customization_controller.tsx +1 -1
  50. package/src/controllers/data.ts +330 -39
  51. package/src/controllers/data_driver.ts +93 -40
  52. package/src/controllers/email.ts +2 -2
  53. package/src/controllers/index.ts +1 -1
  54. package/src/controllers/local_config_persistence.tsx +4 -4
  55. package/src/controllers/navigation.ts +2 -2
  56. package/src/controllers/registry.ts +22 -8
  57. package/src/controllers/{side_entity_controller.tsx → side_panel_controller.tsx} +7 -7
  58. package/src/controllers/storage.ts +60 -1
  59. package/src/errors.ts +80 -0
  60. package/src/index.ts +1 -0
  61. package/src/rebase_context.tsx +8 -4
  62. package/src/types/auth_adapter.ts +29 -4
  63. package/src/types/backend.ts +44 -36
  64. package/src/types/backup.ts +26 -0
  65. package/src/types/builders.ts +2 -2
  66. package/src/types/collections.ts +101 -91
  67. package/src/types/component_overrides.ts +72 -5
  68. package/src/types/cron.ts +11 -2
  69. package/src/types/data_source.ts +24 -2
  70. package/src/types/database_adapter.ts +19 -4
  71. package/src/types/entities.ts +7 -7
  72. package/src/types/entity_actions.tsx +7 -7
  73. package/src/types/entity_callbacks.ts +42 -42
  74. package/src/types/entity_views.tsx +3 -3
  75. package/src/types/filter-operators.ts +96 -23
  76. package/src/types/index.ts +1 -0
  77. package/src/types/modify_collections.tsx +2 -2
  78. package/src/types/plugins.tsx +9 -9
  79. package/src/types/policy.ts +114 -9
  80. package/src/types/properties.ts +58 -9
  81. package/src/types/relations.ts +3 -3
  82. package/src/types/slots.tsx +14 -14
  83. package/src/types/translations.ts +5 -1
  84. package/src/types/user_management_delegate.ts +8 -2
  85. package/src/types/websockets.ts +43 -14
  86. package/src/users/user.ts +22 -9
  87. package/dist/index.umd.js +0 -458
  88. package/dist/index.umd.js.map +0 -1
@@ -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";
@@ -1,6 +1,6 @@
1
- import { EntityCollection } from "./collections";
1
+ import { CollectionConfig } from "./collections";
2
2
 
3
3
  export type ModifyCollectionProps = {
4
- collection: EntityCollection,
4
+ collection: CollectionConfig,
5
5
  parentPaths: string[],
6
6
  };
@@ -1,6 +1,6 @@
1
1
  import React, { PropsWithChildren } from "react";
2
2
 
3
- import type { EntityCollection, CollectionActionsProps, EntityTableController, SelectionController } from "./collections";
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: EntityCollection) => EntityCollection;
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: EntityCollection) => Promise<EntityCollection>;
191
+ modifyCollectionAsync?: (collection: CollectionConfig) => Promise<CollectionConfig>;
192
192
 
193
193
  /**
194
194
  * Modify, add or remove collections.
195
195
  */
196
- injectCollections?: (collections: EntityCollection[]) => EntityCollection[];
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: EntityCollection;
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: EntityCollection;
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 EntityCollection<M> = EntityCollection<M>> {
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 EntityCollection = EntityCollection> {
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 EntityCollection<M> = EntityCollection<M>> = {
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;
@@ -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 there is an authenticated user (`auth.uid() IS NOT NULL`).
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" })
@@ -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 { EntityCollection, FilterValues } from "./collections";
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 { EntityAfterReadProps, EntityBeforeSaveProps } from "./entity_callbacks";
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<EntityAfterReadProps<M, USER>, "entity"> & {
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<EntityBeforeSaveProps<M, USER>, "values"> & {
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 an entity, stored **as a value** on the row (id + path, and
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 an EntityReference.
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 an EntityRelation or array of EntityRelation.
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 | (() => EntityCollection | 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<EntityCollection>;
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.
@@ -1,4 +1,4 @@
1
- import type { EntityCollection } from "./collections";
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: (() => EntityCollection) | any;
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<EntityCollection>;
285
+ overrides?: Partial<CollectionConfig>;
286
286
 
287
287
  validation?: {
288
288
  required?: boolean;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { CollectionActionsProps, EntityTableController, SelectionController, EntityCollection } from "./collections";
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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 an entity collection table.
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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: EntityCollection;
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/core.
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 (only present when email service is not configured).
14
- * This is returned one-time and should be shown to the admin to share manually.
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
  }