@rebasepro/common 0.8.0 → 0.9.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 (53) hide show
  1. package/README.md +4 -4
  2. package/dist/collections/CollectionRegistry.d.ts +16 -16
  3. package/dist/collections/default-collections.d.ts +1 -1
  4. package/dist/data/buildRebaseData.d.ts +30 -2
  5. package/dist/data/buildRoutedRebaseData.d.ts +14 -9
  6. package/dist/data/filter-dialect.d.ts +18 -4
  7. package/dist/data/query_builder.d.ts +1 -1
  8. package/dist/data/resolveDataSource.d.ts +1 -1
  9. package/dist/data/sort-dialect.d.ts +41 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.es.js +569 -159
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.umd.js +573 -163
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/util/builders.d.ts +19 -56
  16. package/dist/util/callbacks.d.ts +3 -3
  17. package/dist/util/collections.d.ts +4 -4
  18. package/dist/util/entities.d.ts +2 -2
  19. package/dist/util/filter-operator-resolution.d.ts +32 -0
  20. package/dist/util/index.d.ts +1 -0
  21. package/dist/util/navigation_from_path.d.ts +4 -4
  22. package/dist/util/navigation_utils.d.ts +3 -3
  23. package/dist/util/parent_references_from_path.d.ts +2 -2
  24. package/dist/util/permissions.d.ts +6 -6
  25. package/dist/util/policy/policyToPostgres.d.ts +14 -2
  26. package/dist/util/references.d.ts +2 -2
  27. package/dist/util/relations.d.ts +5 -5
  28. package/dist/util/resolutions.d.ts +2 -2
  29. package/package.json +3 -3
  30. package/src/collections/CollectionRegistry.ts +36 -36
  31. package/src/data/buildRebaseData.ts +332 -57
  32. package/src/data/buildRoutedRebaseData.ts +22 -16
  33. package/src/data/filter-dialect.ts +145 -60
  34. package/src/data/query_builder.ts +11 -2
  35. package/src/data/resolveDataSource.ts +1 -1
  36. package/src/data/sort-dialect.ts +56 -0
  37. package/src/index.ts +1 -0
  38. package/src/util/builders.ts +25 -99
  39. package/src/util/callbacks.ts +8 -8
  40. package/src/util/collections.ts +4 -4
  41. package/src/util/entities.ts +4 -4
  42. package/src/util/filter-operator-resolution.ts +81 -0
  43. package/src/util/index.ts +1 -0
  44. package/src/util/navigation_from_path.ts +4 -4
  45. package/src/util/navigation_utils.ts +8 -8
  46. package/src/util/parent_references_from_path.ts +3 -3
  47. package/src/util/permissions.test.ts +2 -2
  48. package/src/util/permissions.ts +7 -7
  49. package/src/util/policy/evaluatePolicy.ts +6 -0
  50. package/src/util/policy/policyToPostgres.ts +90 -10
  51. package/src/util/references.ts +2 -2
  52. package/src/util/relations.ts +12 -12
  53. package/src/util/resolutions.ts +5 -5
@@ -1,11 +1,14 @@
1
- import { AdditionalFieldDelegate, ArrayProperty, BooleanProperty, DateProperty, EntityCallbacks, EntityCollection, EnumValueConfig, EnumValues, FirebaseCollection, FirebaseProperties, GeopointProperty, InferEntityType, MapProperty, MongoDBCollection, MongoProperties, NumberProperty, PostgresCollection, PostgresProperties, Properties, Property, ReferenceProperty, StringProperty, User } from "@rebasepro/types";
1
+ import { ArrayProperty, BooleanProperty, DateProperty, CollectionConfig, FirebaseCollectionConfig, FirebaseProperties, GeopointProperty, InferEntityType, MapProperty, MongoDBCollectionConfig, MongoProperties, NumberProperty, PostgresCollectionConfig, PostgresProperties, Property, ReferenceProperty, StringProperty, User } from "@rebasepro/types";
2
2
  /**
3
- * Identity function we use to defeat the type system of Typescript and build
4
- * collection views with all its properties
5
- * @param collection
3
+ * @deprecated Use {@link defineCollection} instead it infers property
4
+ * types automatically (autocomplete on `titleProperty`, `sort`,
5
+ * `propertiesOrder`, callbacks) without manual generics.
6
+ * `buildCollection` is kept for FireCMS migration compatibility and will
7
+ * be removed before 1.0.
8
+ *
6
9
  * @group Builder
7
10
  */
8
- export declare function buildCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(collection: EntityCollection<M, USER>): EntityCollection<M, USER>;
11
+ export declare function buildCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(collection: CollectionConfig<M, USER>): CollectionConfig<M, USER>;
9
12
  /**
10
13
  * Define a PostgreSQL-backed collection with full type inference.
11
14
  *
@@ -30,75 +33,35 @@ export declare function buildCollection<M extends Record<string, unknown> = Reco
30
33
  *
31
34
  * @group Builder
32
35
  */
33
- export declare function defineCollection<const P extends PostgresProperties, USER extends User = User>(collection: Omit<PostgresCollection<InferEntityType<P>, USER>, "properties"> & {
36
+ export declare function defineCollection<const P extends PostgresProperties, USER extends User = User>(collection: Omit<PostgresCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
34
37
  properties: P;
35
- }): PostgresCollection<InferEntityType<P>, USER> & {
38
+ }): PostgresCollectionConfig<InferEntityType<P>, USER> & {
36
39
  properties: P;
37
40
  };
38
41
  /**
39
42
  * Define a Firestore-backed collection with full type inference.
40
43
  * @group Builder
41
44
  */
42
- export declare function defineCollection<const P extends FirebaseProperties, USER extends User = User>(collection: Omit<FirebaseCollection<InferEntityType<P>, USER>, "properties"> & {
45
+ export declare function defineCollection<const P extends FirebaseProperties, USER extends User = User>(collection: Omit<FirebaseCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
43
46
  properties: P;
44
- }): FirebaseCollection<InferEntityType<P>, USER> & {
47
+ }): FirebaseCollectionConfig<InferEntityType<P>, USER> & {
45
48
  properties: P;
46
49
  };
47
50
  /**
48
51
  * Define a MongoDB-backed collection with full type inference.
49
52
  * @group Builder
50
53
  */
51
- export declare function defineCollection<const P extends MongoProperties, USER extends User = User>(collection: Omit<MongoDBCollection<InferEntityType<P>, USER>, "properties"> & {
54
+ export declare function defineCollection<const P extends MongoProperties, USER extends User = User>(collection: Omit<MongoDBCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
52
55
  properties: P;
53
- }): MongoDBCollection<InferEntityType<P>, USER> & {
56
+ }): MongoDBCollectionConfig<InferEntityType<P>, USER> & {
54
57
  properties: P;
55
58
  };
56
59
  /**
57
- * Identity function we use to defeat the type system of Typescript and preserve
58
- * the property keys.
59
- * @param property
60
+ * @deprecated Use plain typed property objects with {@link defineCollection}
61
+ * instead — `defineCollection` infers property types automatically, making
62
+ * this wrapper unnecessary. `buildProperty` is kept for FireCMS migration
63
+ * compatibility and will be removed before 1.0.
64
+ *
60
65
  * @group Builder
61
66
  */
62
67
  export declare function buildProperty<T, P extends Property = Property>(property: P): P extends StringProperty ? StringProperty : P extends NumberProperty ? NumberProperty : P extends BooleanProperty ? BooleanProperty : P extends DateProperty ? DateProperty : P extends GeopointProperty ? GeopointProperty : P extends ReferenceProperty ? ReferenceProperty : P extends ArrayProperty ? ArrayProperty : P extends MapProperty ? MapProperty : never;
63
- /**
64
- * Identity function we use to defeat the type system of Typescript and preserve
65
- * the properties keys.
66
- * @param properties
67
- * @group Builder
68
- */
69
- export declare function buildProperties<M extends Record<string, unknown>>(properties: Properties): Properties;
70
- /**
71
- * Identity function we use to defeat the type system of Typescript and preserve
72
- * the properties keys.
73
- * @param propertiesOrBuilder
74
- * @group Builder
75
- */
76
- export declare function buildPropertiesOrBuilder<M extends Record<string, unknown>>(propertiesOrBuilder: Properties): Properties;
77
- /**
78
- * Identity function we use to defeat the type system of Typescript and preserve
79
- * the properties keys.
80
- * @param enumValues
81
- * @group Builder
82
- */
83
- export declare function buildEnum(enumValues: EnumValues): EnumValues;
84
- /**
85
- * Identity function we use to defeat the type system of Typescript and preserve
86
- * the properties keys.
87
- * @param enumValueConfig
88
- * @group Builder
89
- */
90
- export declare function buildEnumValueConfig(enumValueConfig: EnumValueConfig): EnumValueConfig;
91
- /**
92
- * Identity function we use to defeat the type system of Typescript and preserve
93
- * the properties keys.
94
- * @param callbacks
95
- * @group Builder
96
- */
97
- export declare function buildEntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>>(callbacks: EntityCallbacks<M>): EntityCallbacks<M>;
98
- /**
99
- * Identity function we use to defeat the type system of Typescript and build
100
- * additional field delegates views with all its properties
101
- * @param additionalFieldDelegate
102
- * @group Builder
103
- */
104
- export declare function buildAdditionalFieldDelegate<M extends Record<string, unknown>, USER extends User = User>(additionalFieldDelegate: AdditionalFieldDelegate<M, USER>): AdditionalFieldDelegate<M, USER>;
@@ -1,4 +1,4 @@
1
- import { EntityCallbacks, Properties, RebaseCallContext } from "@rebasepro/types";
1
+ import { CollectionCallbacks, Properties, RebaseCallContext } from "@rebasepro/types";
2
2
  /**
3
3
  * Context passed to entity lifecycle callbacks.
4
4
  * @group Models
@@ -6,6 +6,6 @@ import { EntityCallbacks, Properties, RebaseCallContext } from "@rebasepro/types
6
6
  export type EntityCallbackContext = RebaseCallContext;
7
7
  /**
8
8
  * Helper function to extract field-level PropertyCallbacks from a properties schema
9
- * and wrap them into an EntityCallbacks object recursively.
9
+ * and wrap them into an CollectionCallbacks object recursively.
10
10
  */
11
- export declare const buildPropertyCallbacks: (properties: Properties) => EntityCallbacks | undefined;
11
+ export declare const buildPropertyCallbacks: (properties: Properties) => CollectionCallbacks | undefined;
@@ -1,11 +1,11 @@
1
- import { DefaultSelectedViewBuilder, DefaultSelectedViewParams, EntityCollection, Properties } from "@rebasepro/types";
1
+ import { DefaultSelectedViewBuilder, DefaultSelectedViewParams, CollectionConfig, Properties } from "@rebasepro/types";
2
2
  export declare function sortProperties<M extends Record<string, unknown>>(properties: Properties, propertiesOrder?: string[]): Properties;
3
3
  export declare function resolveDefaultSelectedView(defaultSelectedView: string | DefaultSelectedViewBuilder | undefined, params: DefaultSelectedViewParams): string | undefined;
4
- export declare function getLocalChangesBackup(collection: EntityCollection): "manual_apply" | "auto_apply";
4
+ export declare function getLocalChangesBackup(collection: CollectionConfig): "manual_apply" | "auto_apply";
5
5
  /**
6
- * Returns the primary keys for an entity collection by inspecting the properties
6
+ * Returns the primary keys for a entity collection by inspecting the properties
7
7
  * and finding any properties with `isId`.
8
8
  * Fallbacks to `["id"]` if no properties are marked as `isId: true`.
9
9
  * @param collection
10
10
  */
11
- export declare function getPrimaryKeys<M extends Record<string, unknown>>(collection: EntityCollection<M>): Extract<keyof M, string>[];
11
+ export declare function getPrimaryKeys<M extends Record<string, unknown>>(collection: CollectionConfig<M>): Extract<keyof M, string>[];
@@ -6,7 +6,7 @@ export declare function getDefaultValuesFor<M extends Record<string, unknown>>(p
6
6
  export declare function getDefaultValueFor(property?: Property): unknown;
7
7
  export declare function getDefaultValueFortype(type: DataType): unknown;
8
8
  /**
9
- * Update the automatic values in an entity before save
9
+ * Update the automatic values in a entity before save
10
10
  * @group Driver
11
11
  */
12
12
  export declare function updateDateAutoValues<M extends Record<string, unknown>>({ inputValues, properties, status, timestampNowValue }: {
@@ -16,7 +16,7 @@ export declare function updateDateAutoValues<M extends Record<string, unknown>>(
16
16
  timestampNowValue: unknown;
17
17
  }): EntityValues<M>;
18
18
  /**
19
- * Add missing required fields, expected in the collection, to the values of an entity
19
+ * Add missing required fields, expected in the collection, to the values of a entity
20
20
  * @param values
21
21
  * @param properties
22
22
  * @group Driver
@@ -0,0 +1,32 @@
1
+ import { Property, WhereFilterOp } from "@rebasepro/types";
2
+ export interface ResolveFilterOperatorsParams {
3
+ /**
4
+ * The property to filter on. For array properties, pass the **item**
5
+ * property (`property.of`) together with `isArray: true` — the same
6
+ * convention the filter field dispatchers use.
7
+ */
8
+ property: Property;
9
+ /** True when filtering an array of `property`. */
10
+ isArray?: boolean;
11
+ /**
12
+ * The engine backing the collection (`collection.engine`, e.g.
13
+ * `"postgres"`, `"firestore"`). Falls back to the default engine's
14
+ * capabilities when omitted.
15
+ */
16
+ engine?: string;
17
+ }
18
+ /**
19
+ * Resolve which filter operators the UI should offer for a property.
20
+ *
21
+ * The result is the **intersection** of three sets:
22
+ * 1. what the engine can execute — {@link DataSourceCapabilities.filterOperators}
23
+ * (e.g. Firestore cannot run the LIKE family);
24
+ * 2. what makes sense for the property type (e.g. no `>` on booleans);
25
+ * 3. the developer's optional narrowing — `property.ui.filterOperators`.
26
+ *
27
+ * Returns an empty array when the property is not filterable (either by
28
+ * type, or because the developer disabled it with `filterOperators: []`).
29
+ *
30
+ * @group Models
31
+ */
32
+ export declare function resolveFilterOperators({ property, isArray, engine }: ResolveFilterOperatorsParams): WhereFilterOp[];
@@ -15,3 +15,4 @@ export * from "./callbacks";
15
15
  export * from "./relations";
16
16
  export * from "./conditions";
17
17
  export * from "./navigation_utils";
18
+ export * from "./filter-operator-resolution";
@@ -1,4 +1,4 @@
1
- import { EntityCollection } from "@rebasepro/types";
1
+ import { CollectionConfig } from "@rebasepro/types";
2
2
  type EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = {
3
3
  key: string;
4
4
  [key: string]: unknown;
@@ -9,14 +9,14 @@ export interface NavigationViewEntityInternal<M extends Record<string, unknown>>
9
9
  entityId: string | number;
10
10
  slug: string;
11
11
  path: string;
12
- parentCollection: EntityCollection<M>;
12
+ parentCollection: CollectionConfig<M>;
13
13
  }
14
14
  export interface NavigationViewCollectionInternal<M extends Record<string, unknown>> {
15
15
  type: "collection";
16
16
  id: string;
17
17
  slug: string;
18
18
  path: string;
19
- collection: EntityCollection<M>;
19
+ collection: CollectionConfig<M>;
20
20
  }
21
21
  export interface NavigationViewEntityCustomInternal<M extends Record<string, unknown>> {
22
22
  type: "custom_view";
@@ -27,7 +27,7 @@ export interface NavigationViewEntityCustomInternal<M extends Record<string, unk
27
27
  }
28
28
  export declare function getNavigationEntriesFromPath(props: {
29
29
  path: string;
30
- collections: EntityCollection[] | undefined;
30
+ collections: CollectionConfig[] | undefined;
31
31
  currentFullPath?: string;
32
32
  contextEntityViews?: EntityCustomView[];
33
33
  }): NavigationViewInternal[];
@@ -1,17 +1,17 @@
1
- import { EntityCollection } from "@rebasepro/types";
1
+ import { CollectionConfig } from "@rebasepro/types";
2
2
  export declare function removeInitialAndTrailingSlashes(s: string): string;
3
3
  export declare function removeInitialSlash(s: string): string;
4
4
  export declare function removeTrailingSlash(s: string): string;
5
5
  export declare function addInitialSlash(s: string): string;
6
6
  export declare function getLastSegment(path: string): string;
7
- export declare function resolveCollectionPathIds(path: string, allCollections: EntityCollection[]): string;
7
+ export declare function resolveCollectionPathIds(path: string, allCollections: CollectionConfig[]): string;
8
8
  /**
9
9
  * Find the corresponding view at any depth for a given path.
10
10
  * Note that path or segments of the paths can be collection aliases.
11
11
  * @param slugOrPath
12
12
  * @param collections
13
13
  */
14
- export declare function getCollectionBySlugWithin(slugOrPath: string, collections: EntityCollection[]): EntityCollection | undefined;
14
+ export declare function getCollectionBySlugWithin(slugOrPath: string, collections: CollectionConfig[]): CollectionConfig | undefined;
15
15
  /**
16
16
  * Get the subcollection combinations from a path:
17
17
  * "sites/es/locales" => ["sites/es/locales", "sites"]
@@ -1,6 +1,6 @@
1
- import { EntityCollection, EntityReference } from "@rebasepro/types";
1
+ import { CollectionConfig, EntityReference } from "@rebasepro/types";
2
2
  export declare function getParentReferencesFromPath(props: {
3
3
  path: string;
4
- collections: EntityCollection[] | undefined;
4
+ collections: CollectionConfig[] | undefined;
5
5
  currentFullPath?: string;
6
6
  }): EntityReference[];
@@ -1,4 +1,4 @@
1
- import { Entity, EntityCollection, SecurityOperation, User } from "@rebasepro/types";
1
+ import { Entity, CollectionConfig, SecurityOperation, User } from "@rebasepro/types";
2
2
  /**
3
3
  * Minimal auth context for permission checking.
4
4
  * Only requires the user object — avoids forcing callers to construct
@@ -31,8 +31,8 @@ export interface CheckOperationOptions {
31
31
  * client-side (raw SQL, or row predicates with no row). Defaults to `"allow"`
32
32
  * for optimistic UI gating; enforcement callers should pass `"deny"`.
33
33
  */
34
- export declare function checkOperation<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, entity: Entity<M> | null, targetOperation: SecurityOperation, options?: CheckOperationOptions): boolean;
35
- export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>): boolean;
36
- export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
37
- export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
38
- export declare function canDeleteEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
34
+ export declare function checkOperation<M extends Record<string, unknown>, USER extends User>(collection: CollectionConfig<M>, authContext: AuthContext<USER>, entity: Entity<M> | null, targetOperation: SecurityOperation, options?: CheckOperationOptions): boolean;
35
+ export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection: CollectionConfig<M>, authContext: AuthContext<USER>): boolean;
36
+ export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection: CollectionConfig<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
37
+ export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection: CollectionConfig<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
38
+ export declare function canDeleteEntity<M extends Record<string, unknown>, USER extends User>(collection: CollectionConfig<M>, authContext: AuthContext<USER>, path: string, entity: Entity<M> | null): boolean;
@@ -1,4 +1,16 @@
1
- import { EntityCollection, PolicyExpression } from "@rebasepro/types";
1
+ import { CollectionConfig, PolicyExpression } from "@rebasepro/types";
2
+ /**
3
+ * Options for {@link policyToPostgres}.
4
+ */
5
+ export interface PolicyCompileOptions {
6
+ /**
7
+ * Resolve a collection by slug. Required to compile
8
+ * {@link ExistsInPolicyExpression} (`policy.existsIn`) — the compiler needs
9
+ * the joined collection to derive its table name / schema. When omitted, the
10
+ * join table falls back to a snake_cased slug.
11
+ */
12
+ resolveCollection?: (slug: string) => CollectionConfig | undefined;
13
+ }
2
14
  /**
3
15
  * Compiles a {@link PolicyExpression} to a PostgreSQL boolean SQL string,
4
16
  * suitable for a `USING (...)` / `WITH CHECK (...)` clause.
@@ -7,4 +19,4 @@ import { EntityCollection, PolicyExpression } from "@rebasepro/types";
7
19
  * {@link evaluatePolicy}); the Postgres schema generators call it so that DDL
8
20
  * and the admin UI derive from the exact same expression.
9
21
  */
10
- export declare function policyToPostgres(expr: PolicyExpression, collection?: EntityCollection): string;
22
+ export declare function policyToPostgres(expr: PolicyExpression, collection?: CollectionConfig, options?: PolicyCompileOptions): string;
@@ -1,2 +1,2 @@
1
- import { EntityCollection } from "@rebasepro/types";
2
- export declare function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: EntityCollection<M>): string | undefined;
1
+ import { CollectionConfig } from "@rebasepro/types";
2
+ export declare function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined;
@@ -1,12 +1,12 @@
1
- import { EntityCollection, Property, Relation } from "@rebasepro/types";
2
- export declare function sanitizeRelation(relation: Partial<Relation>, sourceCollection: EntityCollection, resolveCollection?: (slugOrTable: string) => EntityCollection | undefined): Relation;
3
- export declare function resolveCollectionRelations(collection: EntityCollection): Record<string, Relation>;
1
+ import { CollectionConfig, Property, Relation } from "@rebasepro/types";
2
+ export declare function sanitizeRelation(relation: Partial<Relation>, sourceCollection: CollectionConfig, resolveCollection?: (slugOrTable: string) => CollectionConfig | undefined): Relation;
3
+ export declare function resolveCollectionRelations(collection: CollectionConfig): Record<string, Relation>;
4
4
  export declare function resolvePropertyRelation({ propertyKey, property, sourceCollection }: {
5
5
  propertyKey: string;
6
6
  property: Property;
7
- sourceCollection: EntityCollection;
7
+ sourceCollection: CollectionConfig;
8
8
  }): Relation | undefined;
9
- export declare function getTableName(collection: EntityCollection): string;
9
+ export declare function getTableName(collection: CollectionConfig): string;
10
10
  export declare function getTableVarName(tableName: string): string;
11
11
  export declare function getEnumVarName(tableName: string, propName: string): string;
12
12
  export declare function getColumnName(fullColumn: string): string;
@@ -1,4 +1,4 @@
1
- import { ArrayProperty, AuthController, EntityCollection, EnumValueConfig, EnumValues, NumberProperty, Properties, Property, Relation, RelationProperty, StringProperty } from "@rebasepro/types";
1
+ import { ArrayProperty, AuthController, CollectionConfig, EnumValueConfig, EnumValues, NumberProperty, Properties, Property, Relation, RelationProperty, StringProperty } from "@rebasepro/types";
2
2
  type PropertyConfig = {
3
3
  property: unknown;
4
4
  [key: string]: unknown;
@@ -68,5 +68,5 @@ export declare function getArrayResolvedProperties({ propertyKey, propertyValue,
68
68
  authController: AuthController;
69
69
  }): Property[];
70
70
  export declare function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined;
71
- export declare function getSubcollections<M extends Record<string, unknown> = Record<string, unknown>>(collection: EntityCollection<M>): EntityCollection<Record<string, unknown>>[];
71
+ export declare function getSubcollections<M extends Record<string, unknown> = Record<string, unknown>>(collection: CollectionConfig<M>): CollectionConfig<Record<string, unknown>>[];
72
72
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/common",
3
3
  "type": "module",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -41,8 +41,8 @@
41
41
  "dependencies": {
42
42
  "fast-equals": "6.0.0",
43
43
  "json-logic-js": "^2.0.5",
44
- "@rebasepro/utils": "0.8.0",
45
- "@rebasepro/types": "0.8.0"
44
+ "@rebasepro/types": "0.9.0",
45
+ "@rebasepro/utils": "0.9.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@jest/globals": "^30.4.1",
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  ArrayProperty,
3
- EntityCallbacks,
3
+ CollectionCallbacks,
4
4
  EngineProperties,
5
- EntityCollection,
5
+ CollectionConfig,
6
6
  getDataSourceCapabilities,
7
7
  getDeclaredSubcollections,
8
8
  NumberProperty,
@@ -39,40 +39,40 @@ export class CollectionRegistry {
39
39
  * Runs on all data paths (REST, WebSocket, `rebase.data`).
40
40
  * Execution order: global → collection → property callbacks.
41
41
  */
42
- private _globalCallbacks?: EntityCallbacks;
42
+ private _globalCallbacks?: CollectionCallbacks;
43
43
 
44
44
  /**
45
45
  * Set global lifecycle callbacks that apply to every collection.
46
46
  * Typically called once during backend initialization.
47
47
  */
48
- setGlobalCallbacks(callbacks: EntityCallbacks): void {
48
+ setGlobalCallbacks(callbacks: CollectionCallbacks): void {
49
49
  this._globalCallbacks = callbacks;
50
50
  }
51
51
 
52
52
  /**
53
53
  * Get the currently registered global callbacks, if any.
54
54
  */
55
- getGlobalCallbacks(): EntityCallbacks | undefined {
55
+ getGlobalCallbacks(): CollectionCallbacks | undefined {
56
56
  return this._globalCallbacks;
57
57
  }
58
58
 
59
59
  // Normalized runtime layer (used by Data Grid / UI)
60
- private collectionsByTableName = new Map<string, EntityCollection>();
61
- private collectionsBySlug = new Map<string, EntityCollection>();
62
- private rootCollections: EntityCollection[] = [];
63
- private cachedCollectionsList: EntityCollection[] | null = null;
60
+ private collectionsByTableName = new Map<string, CollectionConfig>();
61
+ private collectionsBySlug = new Map<string, CollectionConfig>();
62
+ private rootCollections: CollectionConfig[] = [];
63
+ private cachedCollectionsList: CollectionConfig[] | null = null;
64
64
 
65
65
  // Raw configuration layer (used by Collection Editor AST generator)
66
- private rawCollectionsByTableName = new Map<string, EntityCollection>();
67
- private rawCollectionsBySlug = new Map<string, EntityCollection>();
68
- private rawRootCollections: EntityCollection[] = [];
69
- private cachedRawCollectionsList: EntityCollection[] | null = null;
66
+ private rawCollectionsByTableName = new Map<string, CollectionConfig>();
67
+ private rawCollectionsBySlug = new Map<string, CollectionConfig>();
68
+ private rawRootCollections: CollectionConfig[] = [];
69
+ private cachedRawCollectionsList: CollectionConfig[] | null = null;
70
70
 
71
- // Snapshot of raw input for idempotency check — compared BEFORE normalization
71
+ // Entity of raw input for idempotency check — compared BEFORE normalization
72
72
  // to avoid the issue where normalization creates new objects that always fail equality.
73
- private lastRawInputSnapshot: ReturnType<typeof removeFunctions>[] | null = null;
73
+ private lastRawInputEntity: ReturnType<typeof removeFunctions>[] | null = null;
74
74
 
75
- constructor(collections?: EntityCollection[], dataSources?: DataSourceRegistry) {
75
+ constructor(collections?: CollectionConfig[], dataSources?: DataSourceRegistry) {
76
76
  if (dataSources) this.dataSources = dataSources;
77
77
  if (collections) {
78
78
  this.registerMultiple(collections);
@@ -107,15 +107,15 @@ export class CollectionRegistry {
107
107
  * Returns true if the collections have changed, false otherwise.
108
108
  *
109
109
  * Idempotent: compares the raw input (before normalization) against a stored
110
- * snapshot. Only re-normalizes and re-registers when the raw input actually changed.
110
+ * entity. Only re-normalizes and re-registers when the raw input actually changed.
111
111
  * @param collections
112
112
  */
113
- registerMultiple(collections: EntityCollection[]): boolean {
113
+ registerMultiple(collections: CollectionConfig[]): boolean {
114
114
  // Compare raw input BEFORE normalization to detect actual changes.
115
115
  // This avoids the old issue where normalization creates new objects
116
116
  // that always fail deep-equal even when the source data is identical.
117
- const rawSnapshot = collections.map(c => removeFunctions(c));
118
- if (this.lastRawInputSnapshot && deepEqual(this.lastRawInputSnapshot, rawSnapshot)) {
117
+ const rawEntity = collections.map(c => removeFunctions(c));
118
+ if (this.lastRawInputEntity && deepEqual(this.lastRawInputEntity, rawEntity)) {
119
119
  return false;
120
120
  }
121
121
 
@@ -163,13 +163,13 @@ export class CollectionRegistry {
163
163
  }
164
164
  });
165
165
 
166
- // Store the snapshot for future comparisons
167
- this.lastRawInputSnapshot = rawSnapshot;
166
+ // Store the entity for future comparisons
167
+ this.lastRawInputEntity = rawEntity;
168
168
 
169
169
  return true;
170
170
  }
171
171
 
172
- register(collection: EntityCollection, rawCollection?: EntityCollection) {
172
+ register(collection: CollectionConfig, rawCollection?: CollectionConfig) {
173
173
  const raw = rawCollection ? deepClone(rawCollection) : deepClone(collection);
174
174
 
175
175
  this.rootCollections.push(collection);
@@ -178,7 +178,7 @@ export class CollectionRegistry {
178
178
  this._registerRecursively(collection, raw);
179
179
  }
180
180
 
181
- private _registerRecursively(collection: EntityCollection, rawCollection: EntityCollection) {
181
+ private _registerRecursively(collection: CollectionConfig, rawCollection: CollectionConfig) {
182
182
  if (this.collectionsByTableName.has(getTableName(collection))) {
183
183
  return;
184
184
  }
@@ -207,11 +207,11 @@ export class CollectionRegistry {
207
207
  }
208
208
  }
209
209
 
210
- public normalizeCollection(collection: EntityCollection): EntityCollection {
210
+ public normalizeCollection(collection: CollectionConfig): CollectionConfig {
211
211
  // Work on a shallow copy to avoid mutating the caller's reference.
212
212
  // This is critical for idempotency (the raw input must not be changed)
213
213
  // and for preventing mutation of module-level collection singletons.
214
- const result = { ...collection } as EntityCollection;
214
+ const result = { ...collection } as CollectionConfig;
215
215
 
216
216
  // 0. Resolve and stamp `dataSource` and `engine` on the normalized copy.
217
217
  // After this block every normalized collection has both fields set,
@@ -378,7 +378,7 @@ export class CollectionRegistry {
378
378
  return newProperty;
379
379
  }
380
380
 
381
- get(path: string): EntityCollection | undefined {
381
+ get(path: string): CollectionConfig | undefined {
382
382
  // First try slug lookup
383
383
  const bySlug = this.collectionsBySlug.get(path);
384
384
  if (bySlug) return bySlug;
@@ -398,7 +398,7 @@ export class CollectionRegistry {
398
398
  * Gets the pristine, un-normalized collection exactly as it was provided.
399
399
  * Useful for the AST editor so it doesn't accidentally serialize injected metadata back to disk.
400
400
  */
401
- getRaw(path: string): EntityCollection | undefined {
401
+ getRaw(path: string): CollectionConfig | undefined {
402
402
  const bySlug = this.rawCollectionsBySlug.get(path);
403
403
  if (bySlug) return bySlug;
404
404
 
@@ -416,7 +416,7 @@ export class CollectionRegistry {
416
416
  * Get collection by resolving multi-segment paths through relations
417
417
  * e.g., "authors/70/posts" resolves to the posts collection
418
418
  */
419
- getCollectionByPath(collectionPath: string): EntityCollection | undefined {
419
+ getCollectionByPath(collectionPath: string): CollectionConfig | undefined {
420
420
  // Handle simple single collection path
421
421
  if (!collectionPath.includes("/")) {
422
422
  return this.get(collectionPath);
@@ -467,14 +467,14 @@ export class CollectionRegistry {
467
467
  return currentCollection;
468
468
  }
469
469
 
470
- getCollections(): EntityCollection[] {
470
+ getCollections(): CollectionConfig[] {
471
471
  if (!this.cachedCollectionsList) {
472
472
  this.cachedCollectionsList = Array.from(this.collectionsByTableName.values());
473
473
  }
474
474
  return this.cachedCollectionsList;
475
475
  }
476
476
 
477
- getRawCollections(): EntityCollection[] {
477
+ getRawCollections(): CollectionConfig[] {
478
478
  if (!this.cachedRawCollectionsList) {
479
479
  this.cachedRawCollectionsList = Array.from(this.rawCollectionsByTableName.values());
480
480
  }
@@ -486,9 +486,9 @@ export class CollectionRegistry {
486
486
  * information about the collections and entity IDs along the path
487
487
  */
488
488
  resolvePathToCollections(path: string): {
489
- collections: EntityCollection[],
489
+ collections: CollectionConfig[],
490
490
  entityIds: (string | number)[],
491
- finalCollection: EntityCollection
491
+ finalCollection: CollectionConfig
492
492
  } {
493
493
  const pathSegments = path.split("/").filter(p => p);
494
494
 
@@ -500,7 +500,7 @@ export class CollectionRegistry {
500
500
  throw new Error(`Invalid collection path: ${path}. It must have an odd number of segments.`);
501
501
  }
502
502
 
503
- const collections: EntityCollection[] = [];
503
+ const collections: CollectionConfig[] = [];
504
504
  const entityIds: (string | number)[] = [];
505
505
 
506
506
  // Start with the first collection
@@ -519,12 +519,12 @@ export class CollectionRegistry {
519
519
 
520
520
  if (i + 1 < pathSegments.length) {
521
521
  const subcollectionSlug = pathSegments[i + 1];
522
- const subcollections: EntityCollection[] | undefined = getSubcollections(currentCollection);
522
+ const subcollections: CollectionConfig[] | undefined = getSubcollections(currentCollection);
523
523
  if (!subcollections || subcollections.length === 0) {
524
524
  throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);
525
525
  }
526
526
 
527
- const subcollection: EntityCollection | undefined = subcollections.find(c => c.slug === subcollectionSlug);
527
+ const subcollection: CollectionConfig | undefined = subcollections.find(c => c.slug === subcollectionSlug);
528
528
  if (!subcollection) {
529
529
  throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
530
530
  }