@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.
- package/README.md +4 -4
- package/dist/collections/CollectionRegistry.d.ts +16 -16
- package/dist/collections/default-collections.d.ts +1 -1
- package/dist/data/buildRebaseData.d.ts +30 -2
- package/dist/data/buildRoutedRebaseData.d.ts +14 -9
- package/dist/data/filter-dialect.d.ts +18 -4
- package/dist/data/query_builder.d.ts +1 -1
- package/dist/data/resolveDataSource.d.ts +1 -1
- package/dist/data/sort-dialect.d.ts +41 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +569 -159
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +573 -163
- package/dist/index.umd.js.map +1 -1
- package/dist/util/builders.d.ts +19 -56
- package/dist/util/callbacks.d.ts +3 -3
- package/dist/util/collections.d.ts +4 -4
- package/dist/util/entities.d.ts +2 -2
- package/dist/util/filter-operator-resolution.d.ts +32 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_from_path.d.ts +4 -4
- package/dist/util/navigation_utils.d.ts +3 -3
- package/dist/util/parent_references_from_path.d.ts +2 -2
- package/dist/util/permissions.d.ts +6 -6
- package/dist/util/policy/policyToPostgres.d.ts +14 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/relations.d.ts +5 -5
- package/dist/util/resolutions.d.ts +2 -2
- package/package.json +3 -3
- package/src/collections/CollectionRegistry.ts +36 -36
- package/src/data/buildRebaseData.ts +332 -57
- package/src/data/buildRoutedRebaseData.ts +22 -16
- package/src/data/filter-dialect.ts +145 -60
- package/src/data/query_builder.ts +11 -2
- package/src/data/resolveDataSource.ts +1 -1
- package/src/data/sort-dialect.ts +56 -0
- package/src/index.ts +1 -0
- package/src/util/builders.ts +25 -99
- package/src/util/callbacks.ts +8 -8
- package/src/util/collections.ts +4 -4
- package/src/util/entities.ts +4 -4
- package/src/util/filter-operator-resolution.ts +81 -0
- package/src/util/index.ts +1 -0
- package/src/util/navigation_from_path.ts +4 -4
- package/src/util/navigation_utils.ts +8 -8
- package/src/util/parent_references_from_path.ts +3 -3
- package/src/util/permissions.test.ts +2 -2
- package/src/util/permissions.ts +7 -7
- package/src/util/policy/evaluatePolicy.ts +6 -0
- package/src/util/policy/policyToPostgres.ts +90 -10
- package/src/util/references.ts +2 -2
- package/src/util/relations.ts +12 -12
- package/src/util/resolutions.ts +5 -5
package/dist/util/builders.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
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
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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:
|
|
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<
|
|
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
|
-
}):
|
|
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<
|
|
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
|
-
}):
|
|
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<
|
|
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
|
-
}):
|
|
56
|
+
}): MongoDBCollectionConfig<InferEntityType<P>, USER> & {
|
|
54
57
|
properties: P;
|
|
55
58
|
};
|
|
56
59
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
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>;
|
package/dist/util/callbacks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
9
|
+
* and wrap them into an CollectionCallbacks object recursively.
|
|
10
10
|
*/
|
|
11
|
-
export declare const buildPropertyCallbacks: (properties: Properties) =>
|
|
11
|
+
export declare const buildPropertyCallbacks: (properties: Properties) => CollectionCallbacks | undefined;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { DefaultSelectedViewBuilder, DefaultSelectedViewParams,
|
|
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:
|
|
4
|
+
export declare function getLocalChangesBackup(collection: CollectionConfig): "manual_apply" | "auto_apply";
|
|
5
5
|
/**
|
|
6
|
-
* Returns the primary keys for
|
|
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:
|
|
11
|
+
export declare function getPrimaryKeys<M extends Record<string, unknown>>(collection: CollectionConfig<M>): Extract<keyof M, string>[];
|
package/dist/util/entities.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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[];
|
package/dist/util/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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:
|
|
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:
|
|
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:
|
|
30
|
+
collections: CollectionConfig[] | undefined;
|
|
31
31
|
currentFullPath?: string;
|
|
32
32
|
contextEntityViews?: EntityCustomView[];
|
|
33
33
|
}): NavigationViewInternal[];
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
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:
|
|
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:
|
|
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 {
|
|
1
|
+
import { CollectionConfig, EntityReference } from "@rebasepro/types";
|
|
2
2
|
export declare function getParentReferencesFromPath(props: {
|
|
3
3
|
path: string;
|
|
4
|
-
collections:
|
|
4
|
+
collections: CollectionConfig[] | undefined;
|
|
5
5
|
currentFullPath?: string;
|
|
6
6
|
}): EntityReference[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Entity,
|
|
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:
|
|
35
|
-
export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection:
|
|
36
|
-
export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection:
|
|
37
|
-
export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection:
|
|
38
|
-
export declare function canDeleteEntity<M extends Record<string, unknown>, USER extends User>(collection:
|
|
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 {
|
|
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?:
|
|
22
|
+
export declare function policyToPostgres(expr: PolicyExpression, collection?: CollectionConfig, options?: PolicyCompileOptions): string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection:
|
|
1
|
+
import { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
export declare function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined;
|
package/dist/util/relations.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function sanitizeRelation(relation: Partial<Relation>, sourceCollection:
|
|
3
|
-
export declare function resolveCollectionRelations(collection:
|
|
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:
|
|
7
|
+
sourceCollection: CollectionConfig;
|
|
8
8
|
}): Relation | undefined;
|
|
9
|
-
export declare function getTableName(collection:
|
|
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,
|
|
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:
|
|
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.
|
|
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/
|
|
45
|
-
"@rebasepro/
|
|
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
|
-
|
|
3
|
+
CollectionCallbacks,
|
|
4
4
|
EngineProperties,
|
|
5
|
-
|
|
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?:
|
|
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:
|
|
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():
|
|
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,
|
|
61
|
-
private collectionsBySlug = new Map<string,
|
|
62
|
-
private rootCollections:
|
|
63
|
-
private cachedCollectionsList:
|
|
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,
|
|
67
|
-
private rawCollectionsBySlug = new Map<string,
|
|
68
|
-
private rawRootCollections:
|
|
69
|
-
private cachedRawCollectionsList:
|
|
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
|
-
//
|
|
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
|
|
73
|
+
private lastRawInputEntity: ReturnType<typeof removeFunctions>[] | null = null;
|
|
74
74
|
|
|
75
|
-
constructor(collections?:
|
|
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
|
-
*
|
|
110
|
+
* entity. Only re-normalizes and re-registers when the raw input actually changed.
|
|
111
111
|
* @param collections
|
|
112
112
|
*/
|
|
113
|
-
registerMultiple(collections:
|
|
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
|
|
118
|
-
if (this.
|
|
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
|
|
167
|
-
this.
|
|
166
|
+
// Store the entity for future comparisons
|
|
167
|
+
this.lastRawInputEntity = rawEntity;
|
|
168
168
|
|
|
169
169
|
return true;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
register(collection:
|
|
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:
|
|
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:
|
|
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
|
|
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):
|
|
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):
|
|
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):
|
|
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():
|
|
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():
|
|
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:
|
|
489
|
+
collections: CollectionConfig[],
|
|
490
490
|
entityIds: (string | number)[],
|
|
491
|
-
finalCollection:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
}
|