@rebasepro/types 0.7.0 → 0.8.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/dist/controllers/client.d.ts +53 -1
  2. package/dist/controllers/data.d.ts +19 -47
  3. package/dist/controllers/registry.d.ts +0 -2
  4. package/dist/index.es.js +157 -10
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +163 -9
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/auth_adapter.d.ts +5 -5
  9. package/dist/types/backend.d.ts +4 -0
  10. package/dist/types/collections.d.ts +158 -82
  11. package/dist/types/data_source.d.ts +3 -3
  12. package/dist/types/entity_callbacks.d.ts +18 -6
  13. package/dist/types/filter-operators.d.ts +108 -0
  14. package/dist/types/index.d.ts +3 -2
  15. package/dist/types/policy.d.ts +137 -0
  16. package/dist/types/properties.d.ts +115 -37
  17. package/dist/types/property_config.d.ts +1 -1
  18. package/dist/types/storage_source.d.ts +83 -0
  19. package/package.json +1 -1
  20. package/src/controllers/client.ts +61 -1
  21. package/src/controllers/data.ts +20 -59
  22. package/src/controllers/registry.ts +0 -2
  23. package/src/types/auth_adapter.ts +5 -5
  24. package/src/types/backend.ts +5 -0
  25. package/src/types/collections.ts +191 -106
  26. package/src/types/data_source.ts +5 -5
  27. package/src/types/entity_callbacks.ts +18 -7
  28. package/src/types/filter-operators.ts +167 -0
  29. package/src/types/index.ts +3 -2
  30. package/src/types/policy.ts +173 -0
  31. package/src/types/properties.ts +123 -38
  32. package/src/types/property_config.tsx +0 -1
  33. package/src/types/storage_source.ts +90 -0
  34. package/dist/types/backend_hooks.d.ts +0 -109
  35. package/dist/types/entity_overrides.d.ts +0 -10
  36. package/src/types/backend_hooks.ts +0 -114
  37. package/src/types/entity_overrides.tsx +0 -11
@@ -75,6 +75,20 @@ export type FirebaseProperties = {
75
75
  [key: string]: FirebaseProperty;
76
76
  };
77
77
 
78
+ // MongoDB is a document store: it uses references (stored pointers), not
79
+ // SQL-style relations/joins. Same gating as Firestore.
80
+ export type MongoProperty = Exclude<Property, RelationProperty>;
81
+ export type MongoProperties = {
82
+ [key: string]: MongoProperty;
83
+ };
84
+
85
+ /**
86
+ * Union of all engine-specific property maps. Use this at engine-agnostic
87
+ * boundaries (collection editor, normalization) where the concrete engine is
88
+ * unknown but the narrowed property constraint must be satisfied.
89
+ */
90
+ export type EngineProperties = PostgresProperties | FirebaseProperties | MongoProperties;
91
+
78
92
  /**
79
93
  * A helper type to infer the underlying data type from a Property definition.
80
94
  * This is the core of the type inference system.
@@ -190,10 +204,9 @@ export interface BaseProperty<CustomProps = unknown> {
190
204
  */
191
205
  validation?: PropertyValidationSchema;
192
206
 
193
- /**
194
- * This value will be set by default for new entities.
195
- */
196
- defaultValue?: unknown;
207
+ // NOTE: `defaultValue` is intentionally NOT on BaseProperty.
208
+ // Each concrete property type (StringProperty, NumberProperty, etc.)
209
+ // defines its own typed `defaultValue` for compile-time safety.
197
210
 
198
211
  /**
199
212
  * Use this to define dynamic properties that change based on certain conditions
@@ -235,16 +248,37 @@ export interface BaseProperty<CustomProps = unknown> {
235
248
  * @group Entity properties
236
249
  */
237
250
  export interface StringUIConfig extends BaseUIConfig {
251
+ /**
252
+ * Is this string property long enough so it should be displayed in
253
+ * a multiple line field. Defaults to false. If set to true,
254
+ * the number of lines adapts to the content
255
+ */
238
256
  multiline?: boolean;
257
+ /**
258
+ * Should this string property be displayed as a markdown field. If true,
259
+ * the field is rendered as a text editor that supports markdown highlight
260
+ * syntax. It also includes a preview of the result.
261
+ */
239
262
  markdown?: boolean;
263
+ /**
264
+ * Should this string be rendered as a tag instead of just text.
265
+ */
240
266
  previewAsTag?: boolean;
241
267
  clearable?: boolean;
268
+ /**
269
+ * If the value of this property is a URL, you can set this flag to true
270
+ * to add a link, or one of the supported media types to render a preview
271
+ */
242
272
  url?: boolean | PreviewType;
243
273
  }
244
274
 
245
275
  export interface StringProperty extends BaseProperty {
246
276
  ui?: StringUIConfig;
247
277
  type: "string";
278
+ /**
279
+ * Default value for new entities. Must be a string.
280
+ */
281
+ defaultValue?: string;
248
282
  /**
249
283
  * Optional database column type. If not set, it defaults to `varchar` or `uuid` depending on `isId` configuration.
250
284
  * Use `text` for strings with unbound length, `char` for fixed-length strings, or `varchar` for variable-length strings with a limit.
@@ -279,18 +313,6 @@ export interface StringProperty extends BaseProperty {
279
313
  *
280
314
  */
281
315
  enum?: EnumValues;
282
- /**
283
- * Is this string property long enough so it should be displayed in
284
- * a multiple line field. Defaults to false. If set to true,
285
- * the number of lines adapts to the content
286
- */
287
- multiline?: boolean;
288
- /**
289
- * Should this string property be displayed as a markdown field. If true,
290
- * the field is rendered as a text editors that supports markdown highlight
291
- * syntax. It also includes a preview of the result.
292
- */
293
- markdown?: boolean;
294
316
  /**
295
317
  * You can specify a `Storage` configuration. It is used to
296
318
  * indicate that this string refers to a path in your storage provider.
@@ -301,33 +323,16 @@ export interface StringProperty extends BaseProperty {
301
323
  * This property is used to indicate that the string is a user ID, and
302
324
  * it will be rendered as a user picker.
303
325
  * Note that the user ID needs to be the one used in your authentication
304
- * provider, e.g. Firebase Auth.
326
+ * provider (e.g. the ID in your `users` table).
305
327
  * You can also use a property builder to specify the user path dynamically
306
328
  * based on other values of the entity.
307
329
  */
308
330
  userSelect?: boolean;
309
331
 
310
- /**
311
- * If the value of this property is a URL, you can set this flag to true
312
- * to add a link, or one of the supported media types to render a preview
313
- */
314
- url?: boolean | PreviewType;
315
332
  /**
316
333
  * Does this field include an email
317
334
  */
318
335
  email?: boolean;
319
- /**
320
- * Should this string be rendered as a tag instead of just text.
321
- */
322
- previewAsTag?: boolean;
323
-
324
- /**
325
- * You can use this property (a string) to behave as a reference to another
326
- * collection. The stored value is the ID of the entity in the
327
- * collection, and the `path` prop is used to
328
- * define the collection this reference points to.
329
- */
330
- reference?: ReferenceProperty;
331
336
  }
332
337
 
333
338
  /**
@@ -340,6 +345,10 @@ export interface NumberUIConfig extends BaseUIConfig {
340
345
  export interface NumberProperty extends BaseProperty {
341
346
  ui?: NumberUIConfig;
342
347
  type: "number";
348
+ /**
349
+ * Default value for new entities. Must be a number.
350
+ */
351
+ defaultValue?: number;
343
352
  /**
344
353
  * Optional database column type. Allows specifying exact database numeric types.
345
354
  * If not provided, integer fields (where validation.integer is true or isId is true) default to `integer`, others to `numeric`.
@@ -375,6 +384,10 @@ export interface NumberProperty extends BaseProperty {
375
384
  export interface BooleanProperty extends BaseProperty {
376
385
  ui?: BaseUIConfig;
377
386
  type: "boolean";
387
+ /**
388
+ * Default value for new entities. Must be a boolean.
389
+ */
390
+ defaultValue?: boolean;
378
391
  /**
379
392
  * Rules for validating this property
380
393
  */
@@ -391,6 +404,10 @@ export interface VectorUIConfig extends BaseUIConfig {
391
404
  export interface VectorProperty extends BaseProperty {
392
405
  ui?: VectorUIConfig;
393
406
  type: "vector";
407
+ /**
408
+ * Default value for new entities.
409
+ */
410
+ defaultValue?: Vector;
394
411
  dimensions: number;
395
412
  validation?: PropertyValidationSchema;
396
413
  }
@@ -400,6 +417,10 @@ export interface VectorProperty extends BaseProperty {
400
417
  */
401
418
  export interface BinaryProperty extends BaseProperty {
402
419
  type: "binary";
420
+ /**
421
+ * Default value for new entities. Must be a base64-encoded string.
422
+ */
423
+ defaultValue?: string;
403
424
  validation?: PropertyValidationSchema;
404
425
  }
405
426
 
@@ -407,12 +428,19 @@ export interface BinaryProperty extends BaseProperty {
407
428
  * @group Entity properties
408
429
  */
409
430
  export interface DateUIConfig extends BaseUIConfig {
431
+ /**
432
+ * Add an icon to clear the value and set it to `null`. Defaults to `false`
433
+ */
410
434
  clearable?: boolean;
411
435
  }
412
436
 
413
437
  export interface DateProperty extends BaseProperty {
414
438
  ui?: DateUIConfig;
415
439
  type: "date";
440
+ /**
441
+ * Default value for new entities. Must be a Date.
442
+ */
443
+ defaultValue?: Date;
416
444
  /**
417
445
  * Optional database column type. If not set, defaults to `timestamp` with timezone.
418
446
  */
@@ -438,10 +466,6 @@ export interface DateProperty extends BaseProperty {
438
466
  * `updated_on` fields
439
467
  */
440
468
  autoValue?: "on_create" | "on_update";
441
- /**
442
- * Add an icon to clear the value and set it to `null`. Defaults to `false`
443
- */
444
- clearable?: boolean;
445
469
  }
446
470
 
447
471
  /**
@@ -450,6 +474,10 @@ export interface DateProperty extends BaseProperty {
450
474
  export interface GeopointProperty extends BaseProperty {
451
475
  ui?: BaseUIConfig;
452
476
  type: "geopoint";
477
+ /**
478
+ * Default value for new entities. Must be a GeoPoint.
479
+ */
480
+ defaultValue?: GeoPoint;
453
481
  /**
454
482
  * Rules for validating this property
455
483
  */
@@ -463,9 +491,29 @@ export interface ReferenceUIConfig extends BaseUIConfig {
463
491
  previewProperties?: string[];
464
492
  }
465
493
 
494
+ /**
495
+ * A pointer to an entity, stored **as a value** on the row (id + path, and
496
+ * optionally a `driver`/`databaseId` for cross-datasource pointers).
497
+ *
498
+ * This is the native primitive of **document databases** — it maps 1:1 to a
499
+ * Firestore `DocumentReference`, and is persisted by the MongoDB driver as a
500
+ * tagged sub-document. It carries no schema-level relationship (no foreign key,
501
+ * no join, no cascade) and is resolved on demand.
502
+ *
503
+ * **Which to use:**
504
+ * - Firestore / MongoDB collection → use `reference`.
505
+ * - Postgres collection → use {@link RelationProperty} (`type: "relation"`),
506
+ * which models a real foreign key / join with prefetch and cascade.
507
+ *
508
+ * @group Entity properties
509
+ */
466
510
  export interface ReferenceProperty extends BaseProperty {
467
511
  ui?: ReferenceUIConfig;
468
512
  type: "reference";
513
+ /**
514
+ * Default value for new entities. Must be an EntityReference.
515
+ */
516
+ defaultValue?: EntityReference;
469
517
  /**
470
518
  * Marks this field as a Primary Key / Unique Identifier.
471
519
  * Framework behavior: Auto-maps to `collection.primaryKeys` internally if not explicitly set.
@@ -507,9 +555,29 @@ export interface RelationUIConfig extends BaseUIConfig {
507
555
  widget?: "select" | "dialog";
508
556
  }
509
557
 
558
+ /**
559
+ * A schema-level relationship between collections **within a single
560
+ * datasource** — backed by a foreign key, junction table, or explicit join
561
+ * path. The resolved value (an `EntityRelation`) can carry a prefetched entity
562
+ * payload to eliminate N+1 queries, and supports `onUpdate`/`onDelete` cascade.
563
+ *
564
+ * This is the native primitive of **relational databases** (Postgres). It is
565
+ * the SQL counterpart to {@link ReferenceProperty}.
566
+ *
567
+ * **Which to use:**
568
+ * - Postgres collection → use `relation`.
569
+ * - Firestore / MongoDB collection → use {@link ReferenceProperty}
570
+ * (`type: "reference"`), a stored pointer with no join engine.
571
+ *
572
+ * @group Entity properties
573
+ */
510
574
  export interface RelationProperty extends BaseProperty {
511
575
  ui?: RelationUIConfig;
512
576
  type: "relation";
577
+ /**
578
+ * Default value for new entities. Must be an EntityRelation or array of EntityRelation.
579
+ */
580
+ defaultValue?: EntityRelation | EntityRelation[];
513
581
  /**
514
582
  * Marks this field as a Primary Key / Unique Identifier.
515
583
  * Framework behavior: Auto-maps to `collection.primaryKeys` internally if not explicitly set.
@@ -649,6 +717,10 @@ export interface ArrayUIConfig extends BaseUIConfig {
649
717
  export interface ArrayProperty extends BaseProperty {
650
718
  ui?: ArrayUIConfig;
651
719
  type: "array";
720
+ /**
721
+ * Default value for new entities. Must be an array.
722
+ */
723
+ defaultValue?: unknown[];
652
724
  /**
653
725
  * Optional database column type. By default, maps to a native Postgres array
654
726
  * (e.g. `text[]`, `integer[]`/`numeric[]`, `boolean[]`) if the element type
@@ -729,6 +801,10 @@ export interface MapUIConfig extends BaseUIConfig {
729
801
  export interface MapProperty extends BaseProperty {
730
802
  ui?: MapUIConfig;
731
803
  type: "map";
804
+ /**
805
+ * Default value for new entities. Must be a record/object.
806
+ */
807
+ defaultValue?: Record<string, unknown>;
732
808
  /**
733
809
  * Optional database column type. Defaults to `jsonb`.
734
810
  */
@@ -921,6 +997,15 @@ export interface ArrayPropertyValidationSchema extends PropertyValidationSchema
921
997
  * @group Entity properties
922
998
  */
923
999
  export type StorageConfig = {
1000
+ /**
1001
+ * Key referencing a named storage backend from the StorageRegistry.
1002
+ * Must match a `StorageSourceDefinition.key` or a key registered
1003
+ * in `initializeRebaseBackend({ storage: { ... } })`.
1004
+ *
1005
+ * When omitted, the default storage source is used.
1006
+ */
1007
+ storageSource?: string;
1008
+
924
1009
  /**
925
1010
  * File MIME types that can be uploaded to this reference. Don't specify for
926
1011
  * all.
@@ -85,7 +85,6 @@ export type PropertyConfigId =
85
85
  "group" |
86
86
  "key_value" |
87
87
  "reference" |
88
- "reference_as_string" |
89
88
  "multi_references" |
90
89
  "relation" |
91
90
  "switch" |
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Describes a named storage backend — a place files live.
3
+ *
4
+ * Declared once and shared front + back: the frontend uses it to decide
5
+ * transport (HTTP proxy vs direct SDK), the backend uses the same `key`
6
+ * to resolve a StorageController, and collection properties reference
7
+ * a definition by its `key` via `StorageConfig.storageSource`.
8
+ *
9
+ * This mirrors the {@link DataSourceDefinition} pattern used for databases.
10
+ *
11
+ * @group Models
12
+ */
13
+
14
+ /**
15
+ * The default storage source key, used when a property does not specify
16
+ * a `storageSource`. Shared by the frontend and backend registries so
17
+ * both agree on "the default storage backend".
18
+ * @group Models
19
+ */
20
+ export const DEFAULT_STORAGE_SOURCE_KEY = "(default)";
21
+
22
+ /**
23
+ * How the *frontend* reaches a storage backend.
24
+ *
25
+ * - `"server"` — through the Rebase backend REST API (`/api/storage`).
26
+ * The backend holds the actual `StorageController` and routes by
27
+ * storage-source key. This is the default and covers Local, S3, GCS,
28
+ * and any other server-mediated engine.
29
+ * - `"direct"` — straight from the client to the external backend via
30
+ * its own SDK (e.g. Firebase Storage via `@firebase/storage`).
31
+ * The Rebase backend is **not** in the upload/download path.
32
+ *
33
+ * @group Models
34
+ */
35
+ export type StorageSourceTransport = "server" | "direct";
36
+
37
+ /**
38
+ * Declarative definition of a storage source — a named place files live.
39
+ *
40
+ * Declared once and shared front and back: the frontend uses it to decide
41
+ * transport (client HTTP proxy vs direct provider SDK), the backend uses
42
+ * the same `key` to resolve a `StorageController`, and collection
43
+ * properties reference a definition by its `key` via
44
+ * `StorageConfig.storageSource`.
45
+ *
46
+ * @group Models
47
+ */
48
+ export interface StorageSourceDefinition {
49
+ /**
50
+ * Unique identifier for this storage source. Collection properties
51
+ * point at it via `StorageConfig.storageSource`.
52
+ * Defaults to {@link DEFAULT_STORAGE_SOURCE_KEY}.
53
+ */
54
+ key: string;
55
+
56
+ /**
57
+ * The engine backing this storage source (e.g. `"local"`, `"s3"`,
58
+ * `"gcs"`, `"firebase"`, `"azure"`, or a custom id).
59
+ */
60
+ engine: string;
61
+
62
+ /**
63
+ * How the frontend reaches this storage. Defaults to `"server"`.
64
+ *
65
+ * When `"direct"`, the client uses a provider-specific SDK
66
+ * (e.g. `@firebase/storage`) and the backend does not proxy
67
+ * upload/download traffic for this source.
68
+ */
69
+ transport: StorageSourceTransport;
70
+
71
+ /** Human-readable label for the UI (e.g. "Firebase Storage", "S3 Media"). */
72
+ label?: string;
73
+ }
74
+
75
+ /**
76
+ * A resolved storage source: the single source of truth that the frontend
77
+ * router and backend registry both derive from.
78
+ *
79
+ * @group Models
80
+ */
81
+ export interface ResolvedStorageSource {
82
+ /** Storage source key (routing key, shared front + back). */
83
+ key: string;
84
+ /** Engine backing the source. */
85
+ engine: string;
86
+ /** Frontend transport. */
87
+ transport: StorageSourceTransport;
88
+ /** Human-readable label. */
89
+ label?: string;
90
+ }
@@ -1,109 +0,0 @@
1
- /**
2
- * Context passed to every backend hook.
3
- * Provides information about the request that triggered the hook.
4
- * @group Backend Hooks
5
- */
6
- export interface BackendHookContext {
7
- /** The currently authenticated user making the request (if any) */
8
- requestUser?: {
9
- userId: string;
10
- roles: string[];
11
- };
12
- /** The HTTP method of the request */
13
- method: "GET" | "POST" | "PUT" | "DELETE";
14
- }
15
- /**
16
- * Hooks for intercepting collection entity data at the REST API boundary.
17
- *
18
- * These run **after** per-collection `EntityCallbacks` (which execute inside
19
- * the DataDriver) and provide a single cross-cutting interception point for
20
- * ALL collections flowing through the REST API.
21
- *
22
- * Every callback receives the collection `slug` so you can target specific
23
- * collections or apply logic globally.
24
- *
25
- * @group Backend Hooks
26
- */
27
- export interface DataHooks {
28
- /**
29
- * Transform an entity after it's read from the database,
30
- * before it's returned to the client.
31
- *
32
- * Runs for both list (GET /:slug) and single (GET /:slug/:id) fetches.
33
- * Return the modified entity, or `null` to filter it out.
34
- *
35
- * @param slug - The collection slug (e.g. "orders", "products")
36
- * @param entity - The flattened entity object (id + values merged)
37
- * @param context - Request context (authenticated user, HTTP method)
38
- */
39
- afterRead?(slug: string, entity: Record<string, unknown>, context: BackendHookContext): Record<string, unknown> | null | Promise<Record<string, unknown> | null>;
40
- /**
41
- * Transform entity values before they are written to the database.
42
- * Runs on POST (create) and PUT (update).
43
- *
44
- * Return the (possibly modified) values. Throw to abort the save.
45
- *
46
- * @param slug - The collection slug
47
- * @param values - The raw request body values
48
- * @param entityId - The entity ID (only present on updates)
49
- * @param context - Request context
50
- */
51
- beforeSave?(slug: string, values: Record<string, unknown>, entityId: string | undefined, context: BackendHookContext): Record<string, unknown> | Promise<Record<string, unknown>>;
52
- /**
53
- * Called after an entity is successfully saved (created or updated).
54
- * Useful for side-effects like syncing to external systems.
55
- *
56
- * @param slug - The collection slug
57
- * @param entity - The saved entity (flattened)
58
- * @param context - Request context
59
- */
60
- afterSave?(slug: string, entity: Record<string, unknown>, context: BackendHookContext): void | Promise<void>;
61
- /**
62
- * Called before an entity is deleted. Throw to prevent deletion.
63
- *
64
- * @param slug - The collection slug
65
- * @param entityId - The entity ID being deleted
66
- * @param context - Request context
67
- */
68
- beforeDelete?(slug: string, entityId: string, context: BackendHookContext): void | Promise<void>;
69
- /**
70
- * Called after an entity is successfully deleted.
71
- *
72
- * @param slug - The collection slug
73
- * @param entityId - The deleted entity ID
74
- * @param context - Request context
75
- */
76
- afterDelete?(slug: string, entityId: string, context: BackendHookContext): void | Promise<void>;
77
- }
78
- /**
79
- * Backend-level hooks for intercepting data at the API boundary.
80
- *
81
- * These hooks run server-side after database operations complete and before
82
- * API responses are sent.
83
- *
84
- * `data` hooks complement per-collection `EntityCallbacks`. Entity callbacks
85
- * run inside the DataDriver (close to the DB); data hooks run at the HTTP
86
- * boundary (close to the client). Use data hooks for cross-cutting concerns
87
- * like audit logging, response enrichment, or field masking.
88
- *
89
- * @example
90
- * ```typescript
91
- * const hooks: BackendHooks = {
92
- * data: {
93
- * afterRead(slug, entity, ctx) {
94
- * // Mask PII for non-admin users across all collections
95
- * if (!ctx.requestUser?.roles.includes("admin") && entity.email) {
96
- * return { ...entity, email: "***" };
97
- * }
98
- * return entity;
99
- * }
100
- * }
101
- * };
102
- * ```
103
- *
104
- * @group Backend Hooks
105
- */
106
- export interface BackendHooks {
107
- /** Hooks for intercepting ALL collection entity data via the REST API */
108
- data?: DataHooks;
109
- }
@@ -1,10 +0,0 @@
1
- import type { DataDriver } from "../controllers/data_driver";
2
- import type { StorageSource } from "../controllers/storage";
3
- export type EntityOverrides = {
4
- /**
5
- * Internal driver override for this collection.
6
- * Used by the CMS engine to route data operations.
7
- */
8
- driver?: DataDriver;
9
- storageSource?: StorageSource;
10
- };
@@ -1,114 +0,0 @@
1
-
2
- /**
3
- * Context passed to every backend hook.
4
- * Provides information about the request that triggered the hook.
5
- * @group Backend Hooks
6
- */
7
- export interface BackendHookContext {
8
- /** The currently authenticated user making the request (if any) */
9
- requestUser?: { userId: string; roles: string[] };
10
- /** The HTTP method of the request */
11
- method: "GET" | "POST" | "PUT" | "DELETE";
12
- }
13
-
14
-
15
- /**
16
- * Hooks for intercepting collection entity data at the REST API boundary.
17
- *
18
- * These run **after** per-collection `EntityCallbacks` (which execute inside
19
- * the DataDriver) and provide a single cross-cutting interception point for
20
- * ALL collections flowing through the REST API.
21
- *
22
- * Every callback receives the collection `slug` so you can target specific
23
- * collections or apply logic globally.
24
- *
25
- * @group Backend Hooks
26
- */
27
- export interface DataHooks {
28
- /**
29
- * Transform an entity after it's read from the database,
30
- * before it's returned to the client.
31
- *
32
- * Runs for both list (GET /:slug) and single (GET /:slug/:id) fetches.
33
- * Return the modified entity, or `null` to filter it out.
34
- *
35
- * @param slug - The collection slug (e.g. "orders", "products")
36
- * @param entity - The flattened entity object (id + values merged)
37
- * @param context - Request context (authenticated user, HTTP method)
38
- */
39
- afterRead?(slug: string, entity: Record<string, unknown>, context: BackendHookContext): Record<string, unknown> | null | Promise<Record<string, unknown> | null>;
40
-
41
- /**
42
- * Transform entity values before they are written to the database.
43
- * Runs on POST (create) and PUT (update).
44
- *
45
- * Return the (possibly modified) values. Throw to abort the save.
46
- *
47
- * @param slug - The collection slug
48
- * @param values - The raw request body values
49
- * @param entityId - The entity ID (only present on updates)
50
- * @param context - Request context
51
- */
52
- beforeSave?(slug: string, values: Record<string, unknown>, entityId: string | undefined, context: BackendHookContext): Record<string, unknown> | Promise<Record<string, unknown>>;
53
-
54
- /**
55
- * Called after an entity is successfully saved (created or updated).
56
- * Useful for side-effects like syncing to external systems.
57
- *
58
- * @param slug - The collection slug
59
- * @param entity - The saved entity (flattened)
60
- * @param context - Request context
61
- */
62
- afterSave?(slug: string, entity: Record<string, unknown>, context: BackendHookContext): void | Promise<void>;
63
-
64
- /**
65
- * Called before an entity is deleted. Throw to prevent deletion.
66
- *
67
- * @param slug - The collection slug
68
- * @param entityId - The entity ID being deleted
69
- * @param context - Request context
70
- */
71
- beforeDelete?(slug: string, entityId: string, context: BackendHookContext): void | Promise<void>;
72
-
73
- /**
74
- * Called after an entity is successfully deleted.
75
- *
76
- * @param slug - The collection slug
77
- * @param entityId - The deleted entity ID
78
- * @param context - Request context
79
- */
80
- afterDelete?(slug: string, entityId: string, context: BackendHookContext): void | Promise<void>;
81
- }
82
-
83
- /**
84
- * Backend-level hooks for intercepting data at the API boundary.
85
- *
86
- * These hooks run server-side after database operations complete and before
87
- * API responses are sent.
88
- *
89
- * `data` hooks complement per-collection `EntityCallbacks`. Entity callbacks
90
- * run inside the DataDriver (close to the DB); data hooks run at the HTTP
91
- * boundary (close to the client). Use data hooks for cross-cutting concerns
92
- * like audit logging, response enrichment, or field masking.
93
- *
94
- * @example
95
- * ```typescript
96
- * const hooks: BackendHooks = {
97
- * data: {
98
- * afterRead(slug, entity, ctx) {
99
- * // Mask PII for non-admin users across all collections
100
- * if (!ctx.requestUser?.roles.includes("admin") && entity.email) {
101
- * return { ...entity, email: "***" };
102
- * }
103
- * return entity;
104
- * }
105
- * }
106
- * };
107
- * ```
108
- *
109
- * @group Backend Hooks
110
- */
111
- export interface BackendHooks {
112
- /** Hooks for intercepting ALL collection entity data via the REST API */
113
- data?: DataHooks;
114
- }
@@ -1,11 +0,0 @@
1
- import type { DataDriver } from "../controllers/data_driver";
2
- import type { StorageSource } from "../controllers/storage";
3
-
4
- export type EntityOverrides = {
5
- /**
6
- * Internal driver override for this collection.
7
- * Used by the CMS engine to route data operations.
8
- */
9
- driver?: DataDriver;
10
- storageSource?: StorageSource;
11
- };