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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/common/src/collections/CollectionRegistry.d.ts +8 -0
  2. package/dist/common/src/util/entities.d.ts +22 -0
  3. package/dist/common/src/util/relations.d.ts +14 -4
  4. package/dist/common/src/util/resolutions.d.ts +1 -1
  5. package/dist/index-DXVBFp5V.js +37 -0
  6. package/dist/index-DXVBFp5V.js.map +1 -0
  7. package/dist/index.es.js +49931 -55
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/index.umd.js +28475 -34569
  10. package/dist/index.umd.js.map +1 -1
  11. package/dist/server-core/src/api/openapi-generator.d.ts +15 -1
  12. package/dist/server-core/src/api/types.d.ts +1 -1
  13. package/dist/server-core/src/auth/admin-routes.d.ts +10 -1
  14. package/dist/server-core/src/auth/apple-oauth.d.ts +30 -0
  15. package/dist/server-core/src/auth/bitbucket-oauth.d.ts +11 -0
  16. package/dist/server-core/src/auth/discord-oauth.d.ts +14 -0
  17. package/dist/server-core/src/auth/facebook-oauth.d.ts +14 -0
  18. package/dist/server-core/src/auth/github-oauth.d.ts +15 -0
  19. package/dist/server-core/src/auth/gitlab-oauth.d.ts +13 -0
  20. package/dist/server-core/src/auth/google-oauth.d.ts +5 -11
  21. package/dist/server-core/src/auth/index.d.ts +13 -2
  22. package/dist/server-core/src/auth/interfaces.d.ts +45 -6
  23. package/dist/server-core/src/auth/jwt.d.ts +1 -0
  24. package/dist/server-core/src/auth/linkedin-oauth.d.ts +18 -0
  25. package/dist/server-core/src/auth/microsoft-oauth.d.ts +16 -0
  26. package/dist/server-core/src/auth/middleware.d.ts +36 -11
  27. package/dist/server-core/src/auth/rate-limiter.d.ts +2 -2
  28. package/dist/server-core/src/auth/routes.d.ts +13 -3
  29. package/dist/server-core/src/auth/slack-oauth.d.ts +12 -0
  30. package/dist/server-core/src/auth/spotify-oauth.d.ts +12 -0
  31. package/dist/server-core/src/auth/twitter-oauth.d.ts +18 -0
  32. package/dist/server-core/src/cron/cron-loader.d.ts +17 -0
  33. package/dist/server-core/src/cron/cron-routes.d.ts +14 -0
  34. package/dist/server-core/src/cron/cron-scheduler.d.ts +61 -0
  35. package/dist/server-core/src/cron/cron-store.d.ts +32 -0
  36. package/dist/server-core/src/cron/index.d.ts +6 -0
  37. package/dist/server-core/src/email/index.d.ts +2 -2
  38. package/dist/server-core/src/email/templates.d.ts +9 -0
  39. package/dist/server-core/src/email/types.d.ts +20 -23
  40. package/dist/server-core/src/history/history-routes.d.ts +2 -2
  41. package/dist/server-core/src/index.d.ts +5 -0
  42. package/dist/server-core/src/init.d.ts +112 -2
  43. package/dist/server-core/src/singleton.d.ts +35 -0
  44. package/dist/server-core/src/storage/LocalStorageController.d.ts +9 -9
  45. package/dist/server-core/src/storage/S3StorageController.d.ts +8 -8
  46. package/dist/server-core/src/storage/index.d.ts +18 -11
  47. package/dist/server-core/src/storage/routes.d.ts +3 -3
  48. package/dist/server-core/src/storage/types.d.ts +28 -16
  49. package/dist/server-core/src/utils/dev-port.d.ts +35 -0
  50. package/dist/server-core/src/utils/logger.d.ts +31 -0
  51. package/dist/server-core/src/utils/request-logger.d.ts +19 -0
  52. package/dist/types/src/controllers/auth.d.ts +2 -0
  53. package/dist/types/src/controllers/client.d.ts +119 -7
  54. package/dist/types/src/controllers/collection_registry.d.ts +4 -3
  55. package/dist/types/src/controllers/customization_controller.d.ts +7 -1
  56. package/dist/types/src/controllers/data.d.ts +34 -7
  57. package/dist/types/src/controllers/data_driver.d.ts +20 -28
  58. package/dist/types/src/controllers/database_admin.d.ts +2 -2
  59. package/dist/types/src/controllers/email.d.ts +34 -0
  60. package/dist/types/src/controllers/index.d.ts +1 -0
  61. package/dist/types/src/controllers/local_config_persistence.d.ts +4 -4
  62. package/dist/types/src/controllers/navigation.d.ts +5 -5
  63. package/dist/types/src/controllers/registry.d.ts +6 -3
  64. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -6
  65. package/dist/types/src/controllers/storage.d.ts +24 -26
  66. package/dist/types/src/rebase_context.d.ts +8 -4
  67. package/dist/types/src/types/backend.d.ts +4 -1
  68. package/dist/types/src/types/builders.d.ts +5 -4
  69. package/dist/types/src/types/chips.d.ts +1 -1
  70. package/dist/types/src/types/collections.d.ts +169 -125
  71. package/dist/types/src/types/cron.d.ts +102 -0
  72. package/dist/types/src/types/data_source.d.ts +1 -1
  73. package/dist/types/src/types/entity_actions.d.ts +8 -8
  74. package/dist/types/src/types/entity_callbacks.d.ts +15 -15
  75. package/dist/types/src/types/entity_link_builder.d.ts +1 -1
  76. package/dist/types/src/types/entity_overrides.d.ts +2 -1
  77. package/dist/types/src/types/entity_views.d.ts +8 -8
  78. package/dist/types/src/types/export_import.d.ts +3 -3
  79. package/dist/types/src/types/index.d.ts +1 -0
  80. package/dist/types/src/types/plugins.d.ts +72 -18
  81. package/dist/types/src/types/properties.d.ts +118 -33
  82. package/dist/types/src/types/relations.d.ts +1 -1
  83. package/dist/types/src/types/slots.d.ts +30 -6
  84. package/dist/types/src/types/translations.d.ts +44 -0
  85. package/dist/types/src/types/user_management_delegate.d.ts +1 -0
  86. package/package.json +84 -84
  87. package/scratch.ts +6 -5
  88. package/src/api/ast-schema-editor.ts +11 -11
  89. package/src/api/collections_for_test/callbacks_test_collection.ts +5 -2
  90. package/src/api/errors.ts +38 -14
  91. package/src/api/graphql/graphql-schema-generator.ts +5 -3
  92. package/src/api/openapi-generator.ts +613 -58
  93. package/src/api/rest/api-generator.ts +17 -11
  94. package/src/api/rest/query-parser.ts +1 -1
  95. package/src/api/schema-editor-routes.ts +2 -0
  96. package/src/api/server.ts +8 -5
  97. package/src/api/types.ts +1 -1
  98. package/src/auth/admin-routes.ts +58 -17
  99. package/src/auth/apple-oauth.ts +130 -0
  100. package/src/auth/bitbucket-oauth.ts +82 -0
  101. package/src/auth/discord-oauth.ts +83 -0
  102. package/src/auth/facebook-oauth.ts +72 -0
  103. package/src/auth/github-oauth.ts +110 -0
  104. package/src/auth/gitlab-oauth.ts +70 -0
  105. package/src/auth/google-oauth.ts +34 -46
  106. package/src/auth/index.ts +15 -2
  107. package/src/auth/interfaces.ts +54 -7
  108. package/src/auth/jwt.ts +22 -5
  109. package/src/auth/linkedin-oauth.ts +81 -0
  110. package/src/auth/microsoft-oauth.ts +88 -0
  111. package/src/auth/middleware.ts +194 -45
  112. package/src/auth/password.ts +3 -1
  113. package/src/auth/rate-limiter.ts +4 -4
  114. package/src/auth/routes.ts +197 -139
  115. package/src/auth/slack-oauth.ts +71 -0
  116. package/src/auth/spotify-oauth.ts +67 -0
  117. package/src/auth/twitter-oauth.ts +120 -0
  118. package/src/collections/loader.ts +6 -6
  119. package/src/cron/cron-loader.ts +89 -0
  120. package/src/cron/cron-routes.test.ts +265 -0
  121. package/src/cron/cron-routes.ts +85 -0
  122. package/src/cron/cron-scheduler.test.ts +421 -0
  123. package/src/cron/cron-scheduler.ts +413 -0
  124. package/src/cron/cron-store.ts +163 -0
  125. package/src/cron/index.ts +6 -0
  126. package/src/db/interfaces.ts +2 -2
  127. package/src/email/index.ts +3 -2
  128. package/src/email/smtp-email-service.ts +5 -2
  129. package/src/email/templates.ts +93 -6
  130. package/src/email/types.ts +17 -24
  131. package/src/functions/function-loader.ts +34 -6
  132. package/src/functions/function-routes.ts +2 -2
  133. package/src/history/history-routes.ts +4 -3
  134. package/src/index.ts +10 -0
  135. package/src/init.ts +475 -57
  136. package/src/services/driver-registry.ts +1 -1
  137. package/src/singleton.test.ts +28 -0
  138. package/src/singleton.ts +70 -0
  139. package/src/storage/LocalStorageController.ts +50 -53
  140. package/src/storage/S3StorageController.ts +49 -46
  141. package/src/storage/index.ts +27 -16
  142. package/src/storage/routes.ts +76 -59
  143. package/src/storage/storage-registry.ts +5 -5
  144. package/src/storage/types.ts +44 -32
  145. package/src/types/index.ts +4 -4
  146. package/src/utils/dev-port.ts +176 -0
  147. package/src/utils/logger.ts +143 -0
  148. package/src/utils/logging.ts +5 -2
  149. package/src/utils/request-logger.ts +66 -0
  150. package/test/admin-routes.test.ts +114 -65
  151. package/test/api-generator.test.ts +73 -30
  152. package/test/ast-schema-editor.test.ts +5 -3
  153. package/test/auth-middleware-hono.test.ts +268 -33
  154. package/test/auth-routes.test.ts +325 -146
  155. package/test/driver-registry.test.ts +4 -2
  156. package/test/error-propagation.test.ts +226 -0
  157. package/test/errors.test.ts +12 -7
  158. package/test/jwt-security.test.ts +18 -9
  159. package/test/jwt.test.ts +26 -13
  160. package/test/middleware.test.ts +13 -8
  161. package/test/query-parser.test.ts +13 -8
  162. package/test/rate-limiter.test.ts +7 -7
  163. package/test/safe-compare.test.ts +66 -0
  164. package/test/singleton.test.ts +59 -0
  165. package/test/storage-local.test.ts +36 -43
  166. package/test/storage-registry.test.ts +38 -36
  167. package/test/storage-routes.test.ts +9 -5
  168. package/test/storage-s3.test.ts +51 -48
  169. package/test.ts +6 -0
  170. package/tsconfig.json +1 -1
  171. package/vite.config.ts +7 -5
  172. package/dist/index-BeMqpmfQ.js +0 -239
  173. package/dist/index-BeMqpmfQ.js.map +0 -1
  174. package/dist/index-bl4J3lNb.js +0 -55823
  175. package/dist/index-bl4J3lNb.js.map +0 -1
  176. package/vite.config.ts.timestamp-1775065397568-8a853255edf6e.mjs +0 -46
@@ -1,10 +1,10 @@
1
1
  import React from "react";
2
- import { Entity } from "./entities";
3
- import { EntityCollection, SelectionController } from "./collections";
4
- import { FormContext } from "./entity_views";
5
- import { User } from "../users";
6
- import { RebaseContext } from "../rebase_context";
7
- import { SideEntityController } from "../controllers";
2
+ import type { Entity } from "./entities";
3
+ import type { EntityCollection, SelectionController } from "./collections";
4
+ import type { FormContext } from "./entity_views";
5
+ import type { User } from "../users";
6
+ import type { RebaseContext } from "../rebase_context";
7
+ import type { SideEntityController } from "../controllers/side_entity_controller";
8
8
  /**
9
9
  * An entity action is a custom action that can be performed on an entity.
10
10
  * They are displayed in the entity view and in the collection view.
@@ -55,7 +55,7 @@ export type EntityActionClickProps<M extends Record<string, unknown>, USER exten
55
55
  entity?: Entity<M>;
56
56
  context: RebaseContext<USER>;
57
57
  path?: string;
58
- collection?: EntityCollection<Record<string, unknown>, any>;
58
+ collection?: EntityCollection<M>;
59
59
  /**
60
60
  * Optional form context, present if the action is being called from a form.
61
61
  * This allows you to access the form state and methods, including modifying the form values.
@@ -72,7 +72,7 @@ export type EntityActionClickProps<M extends Record<string, unknown>, USER exten
72
72
  /**
73
73
  * If the action is rendered in the form, is it open in a side panel or full screen?
74
74
  */
75
- openEntityMode: "side_panel" | "full_screen";
75
+ openEntityMode: "side_panel" | "full_screen" | "split";
76
76
  /**
77
77
  * Optional selection controller, present if the action is being called from a collection view
78
78
  */
@@ -1,14 +1,14 @@
1
- import { EntityCollection } from "./collections";
2
- import { Entity, EntityStatus, EntityValues } from "./entities";
3
- import { User } from "../users";
4
- import { RebaseCallContext } from "../rebase_context";
1
+ import type { EntityCollection } from "./collections";
2
+ import type { Entity, EntityStatus, EntityValues } from "./entities";
3
+ import type { User } from "../users";
4
+ import type { RebaseCallContext } from "../rebase_context";
5
5
  /**
6
6
  * This interface defines all the callbacks that can be used when an entity
7
7
  * is being created, updated or deleted.
8
8
  * Useful for adding your own logic or blocking the execution of the operation.
9
9
  * @group Models
10
10
  */
11
- export type EntityCallbacks<M extends Record<string, any> = any, USER extends User = User> = {
11
+ export type EntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = {
12
12
  /**
13
13
  * Callback used after fetching data
14
14
  * @param props
@@ -51,11 +51,11 @@ export type EntityCallbacks<M extends Record<string, any> = any, USER extends Us
51
51
  * Parameters passed to hooks when an entity is fetched
52
52
  * @group Models
53
53
  */
54
- export interface EntityAfterReadProps<M extends Record<string, any> = any, USER extends User = User> {
54
+ export interface EntityAfterReadProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
55
55
  /**
56
56
  * Collection of the entity
57
57
  */
58
- collection: EntityCollection<Record<string, unknown>, any>;
58
+ collection: EntityCollection<M>;
59
59
  /**
60
60
  * Full path of the CMS where this collection is being fetched.
61
61
  * Might contain unresolved aliases.
@@ -74,25 +74,25 @@ export interface EntityAfterReadProps<M extends Record<string, any> = any, USER
74
74
  * Parameters passed to hooks before an entity is saved
75
75
  * @group Models
76
76
  */
77
- export type EntityBeforeSaveProps<M extends Record<string, any> = any, USER extends User = User> = Omit<EntityAfterSaveProps<M, USER>, "entityId"> & {
77
+ export type EntityBeforeSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = Omit<EntityAfterSaveProps<M, USER>, "entityId"> & {
78
78
  entityId?: string | number;
79
79
  };
80
80
  /**
81
81
  * Parameters passed to hooks before an entity is saved
82
82
  * @group Models
83
83
  */
84
- export type EntityAfterSaveErrorProps<M extends Record<string, any> = any, USER extends User = User> = Omit<EntityAfterSaveProps<M, USER>, "entityId"> & {
84
+ export type EntityAfterSaveErrorProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = Omit<EntityAfterSaveProps<M, USER>, "entityId"> & {
85
85
  entityId?: string | number;
86
86
  };
87
87
  /**
88
88
  * Parameters passed to hooks when an entity is saved
89
89
  * @group Models
90
90
  */
91
- export interface EntityAfterSaveProps<M extends Record<string, any> = any, USER extends User = User> {
91
+ export interface EntityAfterSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
92
92
  /**
93
93
  * Resolved collection of the entity
94
94
  */
95
- collection: EntityCollection<Record<string, unknown>, any>;
95
+ collection: EntityCollection<M>;
96
96
  /**
97
97
  * Full path of the CMS where this entity is being saved.
98
98
  * Might contain unresolved aliases.
@@ -123,11 +123,11 @@ export interface EntityAfterSaveProps<M extends Record<string, any> = any, USER
123
123
  * Parameters passed to hooks when an entity is deleted
124
124
  * @group Models
125
125
  */
126
- export interface EntityBeforeDeleteProps<M extends Record<string, any> = any, USER extends User = User> {
126
+ export interface EntityBeforeDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
127
127
  /**
128
128
  * collection of the entity being deleted
129
129
  */
130
- collection: EntityCollection<Record<string, unknown>, any>;
130
+ collection: EntityCollection<M>;
131
131
  /**
132
132
  * Path of the parent collection
133
133
  */
@@ -149,11 +149,11 @@ export interface EntityBeforeDeleteProps<M extends Record<string, any> = any, US
149
149
  * Parameters passed to hooks after an entity is deleted
150
150
  * @group Models
151
151
  */
152
- export interface EntityAfterDeleteProps<M extends Record<string, any> = any, USER extends User = User> {
152
+ export interface EntityAfterDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
153
153
  /**
154
154
  * collection of the entity being deleted
155
155
  */
156
- collection: EntityCollection<Record<string, unknown>, any>;
156
+ collection: EntityCollection<M>;
157
157
  /**
158
158
  * Path of the parent collection
159
159
  */
@@ -2,6 +2,6 @@ import { Entity } from "./entities";
2
2
  /**
3
3
  * @group Models
4
4
  */
5
- export type EntityLinkBuilder<M extends Record<string, any> = any> = ({ entity }: {
5
+ export type EntityLinkBuilder<M extends Record<string, unknown> = Record<string, unknown>> = ({ entity }: {
6
6
  entity: Entity<M>;
7
7
  }) => string;
@@ -1,4 +1,5 @@
1
- import { DataDriver, StorageSource } from "../controllers";
1
+ import type { DataDriver } from "../controllers/data_driver";
2
+ import type { StorageSource } from "../controllers/storage";
2
3
  export type EntityOverrides = {
3
4
  /**
4
5
  * Internal driver override for this collection.
@@ -1,13 +1,13 @@
1
1
  import React from "react";
2
- import { Entity, EntityValues } from "./entities";
3
- import { EntityCollection } from "./collections";
2
+ import type { Entity, EntityValues } from "./entities";
3
+ import type { EntityCollection } from "./collections";
4
4
  /**
5
5
  * Context passed to custom fields and entity views.
6
- * This is the base definition — `@rebasepro/cms` re-exports a
6
+ * This is the base definition — `@rebasepro/admin` re-exports a
7
7
  * fully-typed version that narrows the `formex` field.
8
8
  * @group Form custom fields
9
9
  */
10
- export interface FormContext<M extends Record<string, any> = any> {
10
+ export interface FormContext<M extends Record<string, unknown> = Record<string, unknown>> {
11
11
  /**
12
12
  * Current values of the entity
13
13
  */
@@ -35,16 +35,16 @@ export interface FormContext<M extends Record<string, any> = any> {
35
35
  status: "new" | "existing" | "copy";
36
36
  entity?: Entity<M>;
37
37
  savingError?: Error;
38
- openEntityMode: "side_panel" | "full_screen";
38
+ openEntityMode: "side_panel" | "full_screen" | "split";
39
39
  /**
40
40
  * The underlying formex controller that powers the form.
41
- * Prefer importing `FormContext` from `@rebasepro/cms` for the
41
+ * Prefer importing `FormContext` from `@rebasepro/admin` for the
42
42
  * fully-typed `FormexController<M>` version.
43
43
  */
44
44
  formex: Record<string, unknown>;
45
45
  disabled: boolean;
46
46
  }
47
- export type EntityCustomView<M extends Record<string, any> = any> = {
47
+ export type EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = {
48
48
  key: string;
49
49
  name: string;
50
50
  tabComponent?: React.ReactNode;
@@ -52,7 +52,7 @@ export type EntityCustomView<M extends Record<string, any> = any> = {
52
52
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
53
53
  position?: "start" | "end";
54
54
  };
55
- export interface EntityCustomViewParams<M extends Record<string, any> = any> {
55
+ export interface EntityCustomViewParams<M extends Record<string, unknown> = Record<string, unknown>> {
56
56
  collection: EntityCollection<M>;
57
57
  entity?: Entity<M>;
58
58
  modifiedValues?: EntityValues<M>;
@@ -1,6 +1,6 @@
1
- import { Entity } from "./entities";
2
- import { User } from "../users";
3
- import { RebaseContext } from "../rebase_context";
1
+ import type { Entity } from "./entities";
2
+ import type { User } from "../users";
3
+ import type { RebaseContext } from "../rebase_context";
4
4
  /**
5
5
  * You can use this configuration to add additional fields to the data
6
6
  * exports
@@ -20,3 +20,4 @@ export * from "./entity_actions";
20
20
  export * from "./property_config";
21
21
  export * from "./entity_views";
22
22
  export * from "./data_source";
23
+ export * from "./cron";
@@ -1,14 +1,68 @@
1
- import React from "react";
2
- import { EntityCollection } from "./collections";
3
- import { EntityStatus } from "./entities";
4
- import { Property } from "./properties";
5
- import { FormContext } from "./entity_views";
6
- import { RebaseContext } from "../rebase_context";
7
- import { NavigationGroupMapping, AppView } from "../controllers";
8
- import { UserManagementDelegate } from "./user_management_delegate";
9
- import { User } from "../users";
10
- import { SlotContribution } from "./slots";
11
- export type FieldProps<T = any, CustomProps = any, M extends Record<string, any> = any> = any;
1
+ import React, { PropsWithChildren } from "react";
2
+ import type { EntityCollection } from "./collections";
3
+ import type { EntityStatus } from "./entities";
4
+ import type { InferPropertyType, Property } from "./properties";
5
+ import type { FormContext } from "./entity_views";
6
+ import type { RebaseContext } from "../rebase_context";
7
+ import type { NavigationGroupMapping, AppView } from "../controllers/navigation";
8
+ import type { UserManagementDelegate } from "./user_management_delegate";
9
+ import type { User } from "../users";
10
+ import type { SlotContribution } from "./slots";
11
+ /**
12
+ * Props interface for custom field components.
13
+ *
14
+ * The `@rebasepro/admin` package re-exports a narrower version of this
15
+ * interface that adds `formex` and layout-specific fields. This base
16
+ * definition captures the core contract that every field renderer must
17
+ * satisfy, regardless of where it is rendered.
18
+ *
19
+ * @typeParam P - The property type this field is bound to
20
+ * @typeParam CustomProps - Extra props injected via the property's `customProps`
21
+ * @typeParam M - The entity model type
22
+ * @group Form custom fields
23
+ */
24
+ export interface FieldProps<P extends Property = Property, CustomProps = unknown, M extends Record<string, unknown> = Record<string, unknown>> {
25
+ /** Key of the property (e.g. "user.name" for a nested path) */
26
+ propertyKey: string;
27
+ /** Current value of this field */
28
+ value: InferPropertyType<P> | null;
29
+ /** Set value of field directly */
30
+ setValue: (value: InferPropertyType<P> | null, shouldValidate?: boolean) => void;
31
+ /** Set value of a different field directly */
32
+ setFieldValue: (propertyKey: string, value: unknown, shouldValidate?: boolean) => void;
33
+ /** Is the form currently submitting */
34
+ isSubmitting?: boolean;
35
+ /** Should this field show the error indicator */
36
+ showError?: boolean;
37
+ /** Error message for this field, or undefined if valid */
38
+ error?: string;
39
+ /** Has this field been touched */
40
+ touched?: boolean;
41
+ /** Property related to this field */
42
+ property: P;
43
+ /** Should this field include a description */
44
+ includeDescription?: boolean;
45
+ /** Flag to indicate that the underlying value has been updated in the driver */
46
+ underlyingValueHasChanged?: boolean;
47
+ /** Is this field part of an array */
48
+ partOfArray?: boolean;
49
+ /** Is this field part of a block */
50
+ partOfBlock?: boolean;
51
+ /** Display the child properties directly, without being wrapped in an extendable panel */
52
+ minimalistView?: boolean;
53
+ /** Should this field autofocus on mount */
54
+ autoFocus?: boolean;
55
+ /** Additional properties set by the developer */
56
+ customProps?: CustomProps;
57
+ /** Additional values related to the state of the form or the entity */
58
+ context: FormContext<M>;
59
+ /** Flag to indicate if this field should be disabled */
60
+ disabled?: boolean;
61
+ /** Size of the field */
62
+ size?: "small" | "medium" | "large";
63
+ /** Callback when internal property state changes (e.g. panel expansion) */
64
+ onPropertyChange?: (property: Partial<Property>) => void;
65
+ }
12
66
  /**
13
67
  * Interface used to define plugins for Rebase.
14
68
  * Plugins contribute UI via **slots**, wrap subtrees with **providers**,
@@ -72,11 +126,11 @@ export interface PluginProvider {
72
126
  * Typed loosely because extra props are passed via the `props` field;
73
127
  * strict signatures cause contravariance issues.
74
128
  */
75
- Component: React.ComponentType<any>;
129
+ Component: React.ComponentType<PropsWithChildren<Record<string, unknown>>>;
76
130
  /**
77
131
  * Additional props passed to the Component.
78
132
  */
79
- props?: Record<string, any>;
133
+ props?: Record<string, unknown>;
80
134
  }
81
135
  /**
82
136
  * Behavioral hooks that a plugin can provide.
@@ -155,7 +209,7 @@ export interface PluginLifecycle {
155
209
  * Called when a collection's visible entities change.
156
210
  * Useful for analytics, caching, or cross-plugin coordination.
157
211
  */
158
- onCollectionChange?: (slug: string, entities: any[]) => void;
212
+ onCollectionChange?: (slug: string, entities: unknown[]) => void;
159
213
  }
160
214
  /**
161
215
  * Configuration for wrapping form field components.
@@ -165,7 +219,7 @@ export interface FieldBuilderConfig {
165
219
  /**
166
220
  * Returns a wrapped field component, or null to skip wrapping.
167
221
  */
168
- wrap: <T>(params: PluginFieldBuilderParams) => React.ComponentType<FieldProps<any>> | null;
222
+ wrap: <T>(params: PluginFieldBuilderParams) => React.ComponentType<FieldProps<Property>> | null;
169
223
  /**
170
224
  * Optional guard — return false to skip wrapping for this field.
171
225
  */
@@ -175,7 +229,7 @@ export interface FieldBuilderConfig {
175
229
  * Props passed to home page collection card action components.
176
230
  * @group Models
177
231
  */
178
- export interface PluginHomePageActionsProps<EP extends object = object, M extends Record<string, any> = any, USER extends User = User, EC extends EntityCollection<M> = EntityCollection<M>> {
232
+ 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>> {
179
233
  slug: string;
180
234
  collection: EC;
181
235
  context: RebaseContext<USER>;
@@ -193,13 +247,13 @@ export interface PluginFormActionProps<USER extends User = User, EC extends Enti
193
247
  disabled: boolean;
194
248
  formContext?: FormContext;
195
249
  context: RebaseContext<USER>;
196
- openEntityMode: "side_panel" | "full_screen";
250
+ openEntityMode: "side_panel" | "full_screen" | "split";
197
251
  }
198
252
  /**
199
253
  * Parameters passed to the field builder wrap function.
200
254
  * @group Models
201
255
  */
202
- export type PluginFieldBuilderParams<M extends Record<string, any> = any, EC extends EntityCollection<M> = EntityCollection<M>> = {
256
+ export type PluginFieldBuilderParams<M extends Record<string, unknown> = Record<string, unknown>, EC extends EntityCollection<M> = EntityCollection<M>> = {
203
257
  fieldConfigId: string;
204
258
  propertyKey: string;
205
259
  property: Property;
@@ -1,11 +1,11 @@
1
1
  import React from "react";
2
- import { EntityReference, EntityRelation, EntityValues, GeoPoint, Entity } from "./entities";
3
- import { FilterValues } from "./collections";
4
- import { ColorKey, ColorScheme } from "./chips";
5
- import { AuthController } from "../controllers";
6
- import { Relation } from "./relations";
7
- import { EntityAfterReadProps, EntityBeforeSaveProps } from "./entity_callbacks";
8
- import { User } from "../users";
2
+ import type { EntityReference, EntityRelation, EntityValues, GeoPoint, Entity } from "./entities";
3
+ import type { Relation, JoinStep, OnAction } from "./relations";
4
+ import type { EntityCollection, FilterValues } from "./collections";
5
+ import type { ColorKey, ColorScheme } from "./chips";
6
+ import type { AuthController } from "../controllers/auth";
7
+ import type { EntityAfterReadProps, EntityBeforeSaveProps } from "./entity_callbacks";
8
+ import type { User } from "../users";
9
9
  /**
10
10
  * Callbacks/Hooks for individual property fields
11
11
  * @group Entity properties
@@ -14,7 +14,7 @@ export type PropertyCallbacks<T = unknown, M extends Record<string, unknown> = R
14
14
  /**
15
15
  * Callback used after fetching data, to transform the value before rendering
16
16
  */
17
- afterRead?(props: Omit<EntityAfterReadProps<M, USER>, 'entity'> & {
17
+ afterRead?(props: Omit<EntityAfterReadProps<M, USER>, "entity"> & {
18
18
  value: T;
19
19
  entity: Entity<M> | undefined;
20
20
  }): Promise<T> | T;
@@ -22,7 +22,7 @@ export type PropertyCallbacks<T = unknown, M extends Record<string, unknown> = R
22
22
  * Callback used before saving, after validation.
23
23
  * You can modify the value before it's saved.
24
24
  */
25
- beforeSave?(props: Omit<EntityBeforeSaveProps<M, USER>, 'values'> & {
25
+ beforeSave?(props: Omit<EntityBeforeSaveProps<M, USER>, "values"> & {
26
26
  value: T;
27
27
  previousValue: T | undefined;
28
28
  values: Partial<M>;
@@ -41,30 +41,49 @@ export type Properties = {
41
41
  * This is the core of the type inference system.
42
42
  */
43
43
  export type InferPropertyType<P extends Property> = P extends StringProperty ? string : P extends NumberProperty ? number : P extends BooleanProperty ? boolean : P extends DateProperty ? Date : P extends GeopointProperty ? GeoPoint : P extends ReferenceProperty ? EntityReference : P extends RelationProperty ? EntityRelation | EntityRelation[] : P extends ArrayProperty ? (P["of"] extends Property ? InferPropertyType<P["of"]>[] : unknown[]) : P extends MapProperty ? (P["properties"] extends Properties ? InferEntityType<P["properties"]> : Record<string, unknown>) : never;
44
+ /**
45
+ * Helper type that determines whether a property is required.
46
+ * Uses direct structural matching against `{ validation: { required: true } }`
47
+ * (without the optional marker on `validation`), which correctly narrows
48
+ * literal `true` while treating widened `boolean` as not-required.
49
+ */
50
+ type IsRequired<P extends Property> = P extends {
51
+ validation: {
52
+ required: true;
53
+ };
54
+ } ? true : false;
55
+ /**
56
+ * Extract keys from Properties where the property is required.
57
+ */
58
+ type RequiredPropertyKeys<P extends Properties> = {
59
+ [K in keyof P]: IsRequired<P[K]> extends true ? K : never;
60
+ }[keyof P];
61
+ /**
62
+ * Extract keys from Properties where the property is optional.
63
+ */
64
+ type OptionalPropertyKeys<P extends Properties> = {
65
+ [K in keyof P]: IsRequired<P[K]> extends true ? never : K;
66
+ }[keyof P];
44
67
  /**
45
68
  * A generic type that converts a `Properties` schema definition into a corresponding
46
69
  * TypeScript entity type. It correctly handles required and optional properties.
47
70
  *
71
+ * A property is considered required when it has `validation: { required: true }`.
72
+ * The `true` must be a literal type — if `required` is typed as `boolean`,
73
+ * the property will be treated as optional (use `as const` for literal inference).
74
+ *
48
75
  * @example
49
76
  * const productSchema = {
50
- * name: { type: 'string', validation: { required: true } },
51
- * price: { type: 'number' }
52
- * };
77
+ * name: { type: 'string', validation: { required: true } },
78
+ * price: { type: 'number' }
79
+ * } as const satisfies Properties;
53
80
  * type Product = InferEntityType<typeof productSchema>;
54
81
  * // Result: { name: string; price?: number; }
55
82
  */
56
83
  export type InferEntityType<P extends Properties> = {
57
- -readonly [K in keyof P as P[K] extends {
58
- validation?: {
59
- required: true;
60
- };
61
- } ? K : never]: InferPropertyType<P[K]>;
84
+ -readonly [K in RequiredPropertyKeys<P>]: InferPropertyType<P[K]>;
62
85
  } & {
63
- -readonly [K in keyof P as P[K] extends {
64
- validation?: {
65
- required: true;
66
- };
67
- } ? never : K]?: InferPropertyType<P[K]>;
86
+ -readonly [K in OptionalPropertyKeys<P>]?: InferPropertyType<P[K]>;
68
87
  };
69
88
  /**
70
89
  * Interface including all common properties of a CMS property.
@@ -396,14 +415,79 @@ export interface RelationProperty extends BaseProperty {
396
415
  */
397
416
  isId?: boolean;
398
417
  /**
399
- * The name of the relation this property refers to. This name must match
400
- * one of the `relationName`s defined in the top-level `relations` array
401
- * of the collection.
418
+ * The target collection this relation points to.
419
+ * When set, the framework treats this property as a self-contained relation
420
+ * definition and no separate `relations[]` entry is needed.
421
+ */
422
+ target?: () => EntityCollection;
423
+ /**
424
+ * Whether this property references one or many records.
425
+ * Defaults to `"one"`.
426
+ */
427
+ cardinality?: "one" | "many";
428
+ /**
429
+ * Which side owns the persistence for this relationship.
430
+ * - `"owning"`: The foreign key (for one-to-one) or junction table (for many-to-many) is on this collection.
431
+ * - `"inverse"`: The foreign key is on the target collection's table.
432
+ * Defaults to `"owning"`.
433
+ */
434
+ direction?: "owning" | "inverse";
435
+ /**
436
+ * The name of the corresponding relation on the target collection.
437
+ * Used for inverse relations to locate the owning side.
438
+ */
439
+ inverseRelationName?: string;
440
+ /**
441
+ * Column on THIS table that stores the foreign key to the target.
442
+ * Required when `direction` is `"owning"` and `cardinality` is `"one"`.
443
+ * Auto-inferred if not set.
444
+ * @example "author_id"
445
+ */
446
+ localKey?: string;
447
+ /**
448
+ * Column on the TARGET table that stores the foreign key back to this entity.
449
+ * Required when `direction` is `"inverse"`.
450
+ * Auto-inferred if not set.
451
+ * @example "post_id"
452
+ */
453
+ foreignKeyOnTarget?: string;
454
+ /**
455
+ * Junction table configuration for many-to-many relationships.
456
+ * Required when `cardinality` is `"many"` and `direction` is `"owning"`.
457
+ * Auto-inferred if not set.
458
+ */
459
+ through?: {
460
+ table: string;
461
+ sourceColumn: string;
462
+ targetColumn: string;
463
+ };
464
+ /**
465
+ * Explicit, ordered join path for advanced multi-hop relations.
466
+ * When set, overrides `localKey`, `foreignKeyOnTarget`, and `through`.
467
+ */
468
+ joinPath?: JoinStep[];
469
+ /**
470
+ * Cascade action on update.
471
+ */
472
+ onUpdate?: OnAction;
473
+ /**
474
+ * Cascade action on delete.
475
+ */
476
+ onDelete?: OnAction;
477
+ /**
478
+ * Overrides applied to the target collection when rendered as a subcollection tab.
479
+ */
480
+ overrides?: Partial<EntityCollection>;
481
+ /**
482
+ * Optional name for this relation. Defaults to the property key at runtime.
483
+ * Only needed when the relation name should differ from the property key,
484
+ * or for backward compatibility with existing `relations[]` entries.
402
485
  */
403
- relationName: string;
486
+ relationName?: string;
404
487
  /**
405
- * The resolved relation object.
406
- * This is set by the framework
488
+ * The resolved relation object, populated by the framework at normalization time.
489
+ * **Do not set manually** — it is computed from the inline fields above
490
+ * or looked up from the collection's `relations[]` array.
407
491
  */
408
492
  relation?: Relation;
409
493
  /**
@@ -765,7 +849,7 @@ export type StorageConfig = {
765
849
  * When set to true, this flag indicates that the bucket name will be
766
850
  * included in the saved storage path.
767
851
  *
768
- * E.g. `gs://my-bucket/path/to/file.png` instead of just `path/to/file.png`
852
+ * E.g. `s3://my-bucket/path/to/file.png` instead of just `path/to/file.png`
769
853
  *
770
854
  * Defaults to false.
771
855
  */
@@ -860,7 +944,7 @@ export interface ImageResize {
860
944
  * - `contain`: Scale down to fit within bounds, preserving aspect ratio (default)
861
945
  * - `cover`: Scale to fill bounds, preserving aspect ratio (may crop)
862
946
  */
863
- mode?: 'contain' | 'cover';
947
+ mode?: "contain" | "cover";
864
948
  /**
865
949
  * Output format for the resized image.
866
950
  * - `original`: Keep the original format (default)
@@ -868,7 +952,7 @@ export interface ImageResize {
868
952
  * - `png`: Convert to PNG
869
953
  * - `webp`: Convert to WebP
870
954
  */
871
- format?: 'original' | 'jpeg' | 'png' | 'webp';
955
+ format?: "original" | "jpeg" | "png" | "webp";
872
956
  /**
873
957
  * Quality for lossy formats (JPEG, WebP). Number between 0 and 100.
874
958
  * Higher is better quality but larger file size. Defaults to 80.
@@ -1048,11 +1132,11 @@ export interface ConditionContext {
1048
1132
  * Current form/entity values.
1049
1133
  * Date values are converted to Unix timestamps (milliseconds).
1050
1134
  */
1051
- values: Record<string, any>;
1135
+ values: Record<string, unknown>;
1052
1136
  /**
1053
1137
  * Previous values before the current edit session.
1054
1138
  */
1055
- previousValues: Record<string, any>;
1139
+ previousValues: Record<string, unknown>;
1056
1140
  /**
1057
1141
  * Current value of this property specifically.
1058
1142
  */
@@ -1089,3 +1173,4 @@ export interface ConditionContext {
1089
1173
  */
1090
1174
  now: number;
1091
1175
  }
1176
+ export {};
@@ -1,4 +1,4 @@
1
- import { EntityCollection } from "./collections";
1
+ import type { EntityCollection } from "./collections";
2
2
  /**
3
3
  * @group Models
4
4
  */
@@ -1,9 +1,9 @@
1
1
  import React from "react";
2
- import { CollectionActionsProps, EntityTableController, SelectionController, EntityCollection } from "./collections";
3
- import { Entity } from "./entities";
4
- import { PluginFormActionProps, PluginGenericProps, PluginHomePageActionsProps, PluginHomePageAdditionalCardsProps } from "./plugins";
5
- import { Property } from "./properties";
6
- import { RebaseContext } from "../rebase_context";
2
+ import type { CollectionActionsProps, EntityTableController, SelectionController, EntityCollection } from "./collections";
3
+ import type { Entity } from "./entities";
4
+ import type { PluginFormActionProps, PluginGenericProps, PluginHomePageActionsProps, PluginHomePageAdditionalCardsProps } from "./plugins";
5
+ import type { Property } from "./properties";
6
+ import type { RebaseContext } from "../rebase_context";
7
7
  /**
8
8
  * Registry mapping slot names to their component prop types.
9
9
  * Each key represents a UI extension point in the CMS.
@@ -14,6 +14,8 @@ export interface SlotRegistry {
14
14
  "home.cards": PluginHomePageAdditionalCardsProps;
15
15
  "home.children.start": PluginGenericProps;
16
16
  "home.children.end": PluginGenericProps;
17
+ /** Compact insight widget rendered inline in a home page collection card. */
18
+ "home.card.insight": HomeCardInsightSlotProps;
17
19
  "home.collection.actions": PluginHomePageActionsProps;
18
20
  /** Rendered below the logo in the sidebar drawer. */
19
21
  "navigation.header": NavigationSlotProps;
@@ -28,6 +30,8 @@ export interface SlotRegistry {
28
30
  "collection.toolbar": CollectionToolbarProps;
29
31
  /** Custom empty-state component when a collection has no data. */
30
32
  "collection.empty-state": CollectionEmptyStateProps;
33
+ /** Insight widgets rendered above the collection table. */
34
+ "collection.insights": CollectionInsightsSlotProps;
31
35
  "form.actions": PluginFormActionProps;
32
36
  "form.actions.top": PluginFormActionProps;
33
37
  /** Rendered before the form title / field list. */
@@ -74,7 +78,7 @@ export interface SlotContribution<K extends SlotName = SlotName> {
74
78
  /**
75
79
  * Additional props to merge into the slot props before rendering.
76
80
  */
77
- props?: Record<string, any>;
81
+ props?: Record<string, unknown>;
78
82
  /**
79
83
  * Ordering hint. Lower values render first. Defaults to 50.
80
84
  */
@@ -226,3 +230,23 @@ export interface GlobalSearchProps {
226
230
  export interface ShellToolbarProps {
227
231
  context: RebaseContext;
228
232
  }
233
+ /**
234
+ * Props for `collection.insights` slot.
235
+ * Insight widgets rendered above the collection table.
236
+ * @group Plugins
237
+ */
238
+ export interface CollectionInsightsSlotProps {
239
+ path: string;
240
+ collection: EntityCollection;
241
+ parentCollectionIds: string[];
242
+ }
243
+ /**
244
+ * Props for `home.card.insight` slot.
245
+ * Compact insight rendered inline in a home page collection card.
246
+ * @group Plugins
247
+ */
248
+ export interface HomeCardInsightSlotProps {
249
+ slug: string;
250
+ collection: EntityCollection;
251
+ context: RebaseContext;
252
+ }