@rebasepro/types 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +83 -232
  2. package/dist/controllers/client.d.ts +79 -32
  3. package/dist/controllers/customization_controller.d.ts +10 -9
  4. package/dist/index.es.js +249 -197
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +294 -224
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/rebase_context.d.ts +0 -16
  9. package/dist/types/auth_adapter.d.ts +59 -4
  10. package/dist/types/backend.d.ts +36 -1
  11. package/dist/types/backend_hooks.d.ts +0 -63
  12. package/dist/types/breadcrumbs.d.ts +26 -0
  13. package/dist/types/collections.d.ts +162 -1
  14. package/dist/types/component_overrides.d.ts +138 -0
  15. package/dist/types/entity_views.d.ts +9 -1
  16. package/dist/types/index.d.ts +2 -0
  17. package/dist/types/plugins.d.ts +0 -5
  18. package/dist/types/properties.d.ts +0 -8
  19. package/dist/types/translations.d.ts +3 -0
  20. package/dist/types/user_management_delegate.d.ts +0 -70
  21. package/package.json +10 -10
  22. package/src/controllers/client.ts +85 -33
  23. package/src/controllers/customization_controller.tsx +11 -11
  24. package/src/rebase_context.tsx +0 -16
  25. package/src/types/auth_adapter.ts +70 -4
  26. package/src/types/backend.ts +39 -1
  27. package/src/types/backend_hooks.ts +0 -55
  28. package/src/types/breadcrumbs.ts +27 -0
  29. package/src/types/collections.ts +172 -2
  30. package/src/types/component_overrides.ts +177 -0
  31. package/src/types/database_adapter.ts +1 -1
  32. package/src/types/entity_views.tsx +10 -1
  33. package/src/types/index.ts +2 -0
  34. package/src/types/plugins.tsx +1 -5
  35. package/src/types/properties.ts +0 -9
  36. package/src/types/translations.ts +3 -0
  37. package/src/types/user_management_delegate.ts +0 -77
@@ -11,6 +11,7 @@ import type { Relation } from "./relations";
11
11
  import type { EntityCustomView, FormViewConfig } from "./entity_views";
12
12
  import type { EntityAction } from "./entity_actions";
13
13
  import type { ComponentRef } from "./component_ref";
14
+ import type { CollectionComponentOverrideMap } from "./component_overrides";
14
15
 
15
16
  /**
16
17
  * Base interface containing all driver-agnostic collection properties.
@@ -158,6 +159,11 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
158
159
  */
159
160
  disableDefaultActions?: ("edit" | "copy" | "delete")[];
160
161
 
162
+ /**
163
+ * Mark this collection as an authentication collection.
164
+ * When true, this collection is used for user management, login, password hashing, and invitation flows.
165
+ */
166
+ auth?: boolean | AuthCollectionConfig;
161
167
 
162
168
 
163
169
  /**
@@ -399,7 +405,50 @@ export interface BaseEntityCollection<M extends Record<string, unknown> = Record
399
405
  */
400
406
  Actions?: ComponentRef<CollectionActionsProps>[];
401
407
 
408
+ /**
409
+ * The database table name for this collection.
410
+ * Automatically set for PostgreSQL collections.
411
+ * For non-SQL backends, this may be undefined.
412
+ */
413
+ table?: string;
414
+
415
+ /**
416
+ * Relations defined for this collection.
417
+ * Populated at normalization time from inline relation properties
418
+ * or explicit relation definitions.
419
+ */
420
+ relations?: Relation[];
421
+
422
+ /**
423
+ * Security rules for this collection (Row Level Security).
424
+ * When defined, the backend enforces access control policies.
425
+ */
426
+ securityRules?: SecurityRule[];
402
427
 
428
+ /**
429
+ * Collection-scoped component overrides. These take precedence over
430
+ * global overrides set on `<Rebase>`, but only within this collection's
431
+ * views (entity form, detail view, table, empty state, etc.).
432
+ *
433
+ * Only collection-scoped components (like `Entity.Form`, `Collection.EmptyState`,
434
+ * `Collection.Card`, etc.) can be overridden here. App-level components
435
+ * (like `Shell.AppBar`, `HomePage`) can only be overridden at the `<Rebase>` level.
436
+ *
437
+ * @example
438
+ * ```tsx
439
+ * const productsCollection: PostgresCollection = {
440
+ * name: "Products",
441
+ * slug: "products",
442
+ * table: "products",
443
+ * components: {
444
+ * "Entity.Form": { Component: ProductCustomForm },
445
+ * "Collection.Card": { Component: ProductCard },
446
+ * },
447
+ * properties: { ... }
448
+ * };
449
+ * ```
450
+ */
451
+ components?: CollectionComponentOverrideMap;
403
452
  }
404
453
 
405
454
  // ── Driver-specific collection types ──────────────────────────────────
@@ -517,7 +566,10 @@ export type EntityCollection<M extends Record<string, unknown> = Record<string,
517
566
  // Use these after a `getDataSourceCapabilities()` guard to safely access
518
567
  // driver-specific fields without coupling to a concrete driver type.
519
568
 
520
- /** An EntityCollection that supports SQL-style relations (e.g. Postgres). */
569
+ /**
570
+ * An EntityCollection that supports SQL-style relations (e.g. Postgres).
571
+ * @deprecated Use `EntityCollection` directly — `table`, `relations`, and `securityRules` are now on `BaseEntityCollection`.
572
+ */
521
573
  export type CollectionWithRelations<M extends Record<string, unknown> = Record<string, unknown>> =
522
574
  EntityCollection<M> & { table?: string; relations?: Relation[]; securityRules?: SecurityRule[] };
523
575
 
@@ -721,7 +773,6 @@ export interface FilterPreset<Key extends string = string> {
721
773
  }
722
774
 
723
775
 
724
-
725
776
  /**
726
777
  * Used to indicate valid filter combinations (e.g. created in Firestore)
727
778
  * If the user selects a specific filter/sort combination, the CMS checks if it's
@@ -1099,3 +1150,122 @@ export interface RolesOnlySecurityRule extends SecurityRuleBase {
1099
1150
  using?: never;
1100
1151
  withCheck?: never;
1101
1152
  }
1153
+
1154
+ /**
1155
+ * Configuration for authentication collections.
1156
+ *
1157
+ * Controls what happens when admins create users, reset passwords,
1158
+ * and which entity actions are auto-injected.
1159
+ *
1160
+ * Use `auth: true` as sugar for `{ enabled: true }` with all defaults.
1161
+ *
1162
+ * @example Override user creation
1163
+ * ```ts
1164
+ * auth: {
1165
+ * enabled: true,
1166
+ * onCreateUser: async (values, ctx) => {
1167
+ * const hash = await ctx.hashPassword("welcome123");
1168
+ * return {
1169
+ * values: { ...values, passwordHash: hash, emailVerified: true },
1170
+ * temporaryPassword: "welcome123",
1171
+ * };
1172
+ * },
1173
+ * }
1174
+ * ```
1175
+ *
1176
+ * @example Disable the reset-password entity action
1177
+ * ```ts
1178
+ * auth: {
1179
+ * enabled: true,
1180
+ * actions: { resetPassword: false },
1181
+ * }
1182
+ * ```
1183
+ *
1184
+ * @group Models
1185
+ */
1186
+ export interface AuthCollectionConfig {
1187
+ /** Set to true to mark this collection as the authentication collection. */
1188
+ enabled: boolean;
1189
+
1190
+ /**
1191
+ * Called when an admin creates a user via the collection REST API.
1192
+ *
1193
+ * Default: generate password → hash → normalize email → save →
1194
+ * send invitation email (or return temp password if no email configured).
1195
+ *
1196
+ * Override to implement custom invitation flows, LDAP sync, etc.
1197
+ */
1198
+ onCreateUser?: (
1199
+ values: Record<string, unknown>,
1200
+ ctx: AuthCollectionContext
1201
+ ) => Promise<AuthCollectionCreateResult>;
1202
+
1203
+ /**
1204
+ * Called when an admin resets a user's password via the admin panel.
1205
+ *
1206
+ * Default: generate reset token → send email (or generate + return temp password).
1207
+ * Override for custom reset flows.
1208
+ */
1209
+ onResetPassword?: (
1210
+ userId: string,
1211
+ ctx: AuthCollectionContext
1212
+ ) => Promise<AuthCollectionResetResult>;
1213
+
1214
+ /**
1215
+ * Control which auth-specific entity actions are auto-injected.
1216
+ *
1217
+ * Default: `{ resetPassword: true }` — the framework auto-injects
1218
+ * the built-in `resetPasswordAction` into the collection's entity actions.
1219
+ *
1220
+ * Set to `false` to disable, or pass a custom `EntityAction` to replace the UI.
1221
+ */
1222
+ actions?: {
1223
+ resetPassword?: boolean | EntityAction;
1224
+ };
1225
+ }
1226
+
1227
+ /**
1228
+ * Context provided to collection-level auth hooks.
1229
+ *
1230
+ * This is a simplified facade over the server internals —
1231
+ * it exposes only what's needed for custom auth flows without
1232
+ * coupling collection config to internal interfaces.
1233
+ *
1234
+ * @group Models
1235
+ */
1236
+ export interface AuthCollectionContext {
1237
+ /** Hash a password using the configured algorithm (scrypt by default). */
1238
+ hashPassword: (password: string) => Promise<string>;
1239
+ /** Send an email. Only available when email service is configured. */
1240
+ sendEmail?: (options: { to: string; subject: string; html: string; text?: string }) => Promise<void>;
1241
+ /** Whether the email service is configured and available. */
1242
+ emailConfigured: boolean;
1243
+ /** The app name from email config (for templates). */
1244
+ appName: string;
1245
+ /** The base URL for password reset links. */
1246
+ resetPasswordUrl: string;
1247
+ }
1248
+
1249
+ /**
1250
+ * Result of a collection-level `onCreateUser` hook.
1251
+ * @group Models
1252
+ */
1253
+ export interface AuthCollectionCreateResult {
1254
+ /** Processed values to persist (must include passwordHash, NOT raw password). */
1255
+ values: Record<string, unknown>;
1256
+ /** If set, shown to the admin in the creation result dialog. */
1257
+ temporaryPassword?: string;
1258
+ /** Whether an invitation email was sent. */
1259
+ invitationSent?: boolean;
1260
+ }
1261
+
1262
+ /**
1263
+ * Result of a collection-level `onResetPassword` hook.
1264
+ * @group Models
1265
+ */
1266
+ export interface AuthCollectionResetResult {
1267
+ /** If set, shown to the admin. */
1268
+ temporaryPassword?: string;
1269
+ /** Whether a reset email was sent. */
1270
+ invitationSent?: boolean;
1271
+ }
@@ -0,0 +1,177 @@
1
+ import type React from "react";
2
+
3
+ // ── Scoped component name unions ──────────────────────────────────────
4
+
5
+ /**
6
+ * Components that can only be overridden at the **app level** via the
7
+ * `components` prop on `<Rebase>`.
8
+ *
9
+ * These are shell-level / global components that exist outside of any
10
+ * specific collection context.
11
+ *
12
+ * @group Component Overrides
13
+ */
14
+ export type AppComponentName =
15
+ // ── Shell / Layout ──
16
+ | "Shell.AppBar"
17
+ | "Shell.Drawer"
18
+ | "Shell.DrawerNavigationItem"
19
+ | "Shell.DrawerNavigationGroup"
20
+
21
+ // ── Home Page ──
22
+ | "HomePage"
23
+ | "HomePage.CollectionCard"
24
+
25
+ // ── Auth ──
26
+ | "Auth.LoginView";
27
+
28
+ /**
29
+ * Components that can be overridden at the **collection level**
30
+ * (on an individual collection definition) or at the **app level**
31
+ * (as a default for all collections).
32
+ *
33
+ * When set at the app level, these act as defaults. When set on a
34
+ * specific collection, they override the app-level default for that
35
+ * collection only.
36
+ *
37
+ * @group Component Overrides
38
+ */
39
+ export type CollectionComponentName =
40
+ // ── Collection View ──
41
+ | "Collection.View"
42
+ | "Collection.Table"
43
+ | "Collection.Card"
44
+ | "Collection.EmptyState"
45
+ | "Collection.Actions"
46
+
47
+ // ── Entity / Form ──
48
+ | "Entity.Form"
49
+ | "Entity.FormActions"
50
+ | "Entity.DetailView"
51
+ | "Entity.SidePanel"
52
+ | "Entity.Preview"
53
+ | "Entity.MissingReference";
54
+
55
+ /**
56
+ * All overridable component names across all scopes.
57
+ * @group Component Overrides
58
+ */
59
+ export type OverridableComponentName = AppComponentName | CollectionComponentName;
60
+
61
+ // ── Override entry ────────────────────────────────────────────────────
62
+
63
+ /**
64
+ * A single component override entry.
65
+ *
66
+ * - **Eject mode** (default): Your component fully replaces the built-in one.
67
+ * It receives the same props as the original.
68
+ *
69
+ * - **Wrap mode** (`wrap: true`): Your component wraps the original. The
70
+ * built-in component is passed as `OriginalComponent` in props, so you can
71
+ * render it inside your custom layout/logic.
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * // Eject — full replacement
76
+ * { Component: MyCustomAppBar }
77
+ *
78
+ * // Wrap — augment the original
79
+ * {
80
+ * Component: ({ OriginalComponent, ...props }) => (
81
+ * <div>
82
+ * <MyBanner />
83
+ * <OriginalComponent {...props} />
84
+ * </div>
85
+ * ),
86
+ * wrap: true
87
+ * }
88
+ * ```
89
+ *
90
+ * @group Component Overrides
91
+ */
92
+ export interface ComponentOverride<P = any> {
93
+ /**
94
+ * The replacement component. Receives the same props as the built-in
95
+ * component it replaces.
96
+ *
97
+ * When `wrap` is true, an additional `OriginalComponent` prop is injected
98
+ * containing the default component, allowing you to render it within
99
+ * your custom wrapper.
100
+ */
101
+ Component: React.ComponentType<P>;
102
+
103
+ /**
104
+ * When true, the original default component is injected as the
105
+ * `OriginalComponent` prop into your Component, enabling the
106
+ * wrapping pattern (similar to Docusaurus's `--wrap` swizzle mode).
107
+ *
108
+ * When false or omitted, your component fully replaces the default
109
+ * (similar to Docusaurus's `--eject` swizzle mode).
110
+ *
111
+ * @default false
112
+ */
113
+ wrap?: boolean;
114
+ }
115
+
116
+ // ── Override maps by scope ────────────────────────────────────────────
117
+
118
+ /**
119
+ * Collection-scoped overrides. Only collection-level components
120
+ * can be overridden here.
121
+ *
122
+ * Set on a collection's `components` field to customize
123
+ * components for that specific collection.
124
+ *
125
+ * @example
126
+ * ```tsx
127
+ * const productsCollection = {
128
+ * name: "Products",
129
+ * slug: "products",
130
+ * components: {
131
+ * "Entity.Form": { Component: ProductForm },
132
+ * "Collection.EmptyState": { Component: ProductsEmptyState },
133
+ * "Collection.Card": { Component: ProductCard },
134
+ * }
135
+ * };
136
+ * ```
137
+ *
138
+ * @group Component Overrides
139
+ */
140
+ export type CollectionComponentOverrideMap = {
141
+ [K in CollectionComponentName]?: ComponentOverride;
142
+ };
143
+
144
+ /**
145
+ * App-level overrides. Includes both app-only components (Shell, HomePage, Auth)
146
+ * and collection-level components (as defaults for all collections).
147
+ *
148
+ * Pass this to the `components` prop on `<Rebase>`.
149
+ *
150
+ * Collection-level components set here act as **defaults** — they apply to all
151
+ * collections unless a specific collection overrides them in its own
152
+ * `components`.
153
+ *
154
+ * @example
155
+ * ```tsx
156
+ * <Rebase
157
+ * client={client}
158
+ * components={{
159
+ * // App-level: only available here
160
+ * "Shell.AppBar": { Component: MyAppBar },
161
+ * "HomePage": { Component: MyDashboard },
162
+ *
163
+ * // Collection defaults: apply to ALL collections
164
+ * "Entity.FormActions": {
165
+ * Component: MyFormActions,
166
+ * wrap: true
167
+ * },
168
+ * "Collection.EmptyState": { Component: MyEmptyState },
169
+ * }}
170
+ * />
171
+ * ```
172
+ *
173
+ * @group Component Overrides
174
+ */
175
+ export type ComponentOverrideMap = {
176
+ [K in OverridableComponentName]?: ComponentOverride;
177
+ };
@@ -27,7 +27,7 @@ import type {
27
27
  DatabaseAdmin,
28
28
  InitializedDriver,
29
29
  RealtimeProvider,
30
- BootstrappedAuth,
30
+ BootstrappedAuth
31
31
  } from "./backend";
32
32
 
33
33
  /**
@@ -21,10 +21,19 @@ export interface FormContext<M extends Record<string, unknown> = Record<string,
21
21
  setFieldValue: (key: string, value: unknown, shouldValidate?: boolean) => void;
22
22
 
23
23
  /**
24
- * Save the entity.
24
+ * Quietly persist the entity to the database without any UI feedback
25
+ * (no validation, no snackbar, no form reset).
26
+ * Use this for programmatic/background saves from custom views.
25
27
  */
26
28
  save: (values: M) => void;
27
29
 
30
+ /**
31
+ * Submit the form — validates, saves, resets the form, and shows
32
+ * a success snackbar. This is what the Save button calls.
33
+ * Use this from custom views when you want the full "user saved" experience.
34
+ */
35
+ submit: () => void;
36
+
28
37
  /**
29
38
  * Collection of the entity being modified
30
39
  */
@@ -28,3 +28,5 @@ export * from "./backend_hooks";
28
28
  export * from "./component_ref";
29
29
  export * from "./auth_adapter";
30
30
  export * from "./database_adapter";
31
+ export * from "./breadcrumbs";
32
+ export * from "./component_overrides";
@@ -6,7 +6,7 @@ import type { InferPropertyType, Property } from "./properties";
6
6
  import type { FormContext } from "./entity_views";
7
7
  import type { RebaseContext } from "../rebase_context";
8
8
  import type { NavigationGroupMapping, AppView } from "../controllers/navigation";
9
- import type { UserManagementDelegate } from "./user_management_delegate";
9
+
10
10
  import type { User } from "../users";
11
11
  import type { SlotContribution } from "./slots";
12
12
 
@@ -136,10 +136,6 @@ export interface RebasePlugin {
136
136
  */
137
137
  views?: AppView[];
138
138
 
139
- /**
140
- * User management delegate from this plugin.
141
- */
142
- userManagement?: UserManagementDelegate;
143
139
 
144
140
  /**
145
141
  * Optional lifecycle hooks. Called by the Rebase runtime
@@ -745,15 +745,6 @@ export interface MapProperty extends BaseProperty {
745
745
  * Properties that are displayed when rendered as a preview
746
746
  */
747
747
  previewProperties?: string[];
748
- /**
749
- * Allow the user to add only some keys in this map.
750
- * By default, all properties of the map have the corresponding field in
751
- * the form view. Setting this flag to true allows to pick only some.
752
- * Useful for map that can have a lot of sub-properties that may not be
753
- * needed
754
- */
755
- pickOnlySomeKeys?: boolean;
756
-
757
748
  /**
758
749
  * Render this map as a key-value table that allows to use
759
750
  * arbitrary keys. You don't need to define the properties in this case.
@@ -130,6 +130,9 @@ export interface RebaseTranslations {
130
130
 
131
131
  // ─── Error states ─────────────────────────────────────────────
132
132
  error: string;
133
+ error_loading_data?: string;
134
+ error_check_server_logs?: string;
135
+ error_technical_details?: string;
133
136
  error_uploading_file: string;
134
137
  error_deleting: string;
135
138
  error_before_delete: string;
@@ -15,80 +15,3 @@ export interface UserCreationResult<USER extends User = User> {
15
15
  */
16
16
  temporaryPassword?: string;
17
17
  }
18
-
19
-
20
- /**
21
- * Delegate to manage auth-specific user operations.
22
- *
23
- * This interface allows the CMS to be agnostic of the underlying
24
- * authentication provider or backend. User/role CRUD is now handled
25
- * by the collection system; this delegate only exposes auth-specific
26
- * operations (password hashing, invitations, bootstrap).
27
- *
28
- * @group Models
29
- */
30
- export interface UserManagementDelegate<USER extends User = User> {
31
-
32
- /**
33
- * Are auth-related operations currently loading?
34
- */
35
- loading: boolean;
36
-
37
- /**
38
- * In-memory list of users (used for client-side filtering fallback).
39
- */
40
- users?: USER[];
41
-
42
- /**
43
- * Error from fetching the users list, if any.
44
- */
45
- usersError?: Error;
46
-
47
- /**
48
- * Look up a single user by UID from the in-memory cache.
49
- */
50
- getUser?: (uid: string) => USER | null;
51
-
52
- /**
53
- * Server-side user search with pagination.
54
- */
55
- searchUsers?: (params: { search?: string; limit?: number; offset?: number }) => Promise<{ users: USER[]; total: number }>;
56
-
57
- /**
58
- * Create a new user with invitation/password generation support.
59
- * Returns additional info about how the credentials were delivered.
60
- */
61
- createUser?: (user: USER) => Promise<UserCreationResult<USER>>;
62
-
63
- /**
64
- * Reset the password for an existing user.
65
- * Returns a temporary password if no email service is configured,
66
- * or a flag indicating an email invitation was sent.
67
- */
68
- resetPassword?: (user: USER) => Promise<UserCreationResult<USER>>;
69
-
70
- /**
71
- * Is the currently logged in user an admin?
72
- */
73
- isAdmin?: boolean;
74
-
75
- /**
76
- * Optionally define roles for a given user. This is useful when the roles
77
- * are coming from a separate provider than the one issuing the tokens.
78
- */
79
- defineRolesFor?: (user: USER) => Promise<string[] | undefined> | string[] | undefined;
80
-
81
- /**
82
- * Whether any admin users exist. Used by the bootstrap banner to decide
83
- * whether to prompt. Populated via a lightweight check (e.g. `limit=1`
84
- * query) instead of loading all users.
85
- */
86
- hasAdminUsers?: boolean;
87
-
88
- /**
89
- * Optional function to bootstrap an admin user.
90
- * Often used when the database is empty.
91
- */
92
- bootstrapAdmin?: () => Promise<void>;
93
-
94
- }