@rebasepro/common 0.1.0 → 0.2.1
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/LICENSE +1 -1
- package/README.md +178 -110
- package/dist/index.es.js +71 -9
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +72 -9
- package/dist/index.umd.js.map +1 -1
- package/dist/util/entities.d.ts +2 -2
- package/dist/util/relations.d.ts +1 -1
- package/package.json +12 -15
- package/src/collections/CollectionRegistry.d.ts +56 -0
- package/src/collections/CollectionRegistry.ts +17 -42
- package/src/collections/index.d.ts +1 -0
- package/src/data/buildRebaseData.d.ts +14 -0
- package/src/index.d.ts +3 -0
- package/src/types/json-logic-js.d.ts +1 -1
- package/src/util/builders.d.ts +57 -0
- package/src/util/builders.ts +1 -0
- package/src/util/callbacks.d.ts +6 -0
- package/src/util/collections.d.ts +11 -0
- package/src/util/common.d.ts +2 -0
- package/src/util/conditions.d.ts +26 -0
- package/src/util/entities.d.ts +58 -0
- package/src/util/entities.ts +6 -2
- package/src/util/enums.d.ts +3 -0
- package/src/util/index.d.ts +16 -0
- package/src/util/navigation_from_path.d.ts +34 -0
- package/src/util/navigation_utils.d.ts +20 -0
- package/src/util/parent_references_from_path.d.ts +6 -0
- package/src/util/paths.d.ts +14 -0
- package/src/util/permissions.d.ts +5 -0
- package/src/util/references.d.ts +2 -0
- package/src/util/relations.d.ts +22 -0
- package/src/util/relations.ts +69 -8
- package/src/util/resolutions.d.ts +72 -0
- package/src/util/resolutions.ts +3 -3
- package/src/util/storage.d.ts +24 -0
package/dist/util/entities.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export declare function isReadOnly(property: Property): boolean;
|
|
|
3
3
|
export declare function isHidden(property: Property): boolean;
|
|
4
4
|
export declare function isPropertyBuilder(property?: Property): boolean;
|
|
5
5
|
export declare function getDefaultValuesFor<M extends Record<string, unknown>>(properties: Properties): Partial<EntityValues<M>>;
|
|
6
|
-
export declare function getDefaultValueFor(property?: Property):
|
|
7
|
-
export declare function getDefaultValueFortype(type: DataType):
|
|
6
|
+
export declare function getDefaultValueFor(property?: Property): unknown;
|
|
7
|
+
export declare function getDefaultValueFortype(type: DataType): unknown;
|
|
8
8
|
/**
|
|
9
9
|
* Update the automatic values in an entity before save
|
|
10
10
|
* @group Driver
|
package/dist/util/relations.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EntityCollection, Property, Relation } from "@rebasepro/types";
|
|
2
|
-
export declare function sanitizeRelation(relation: Partial<Relation>, sourceCollection: EntityCollection): Relation;
|
|
2
|
+
export declare function sanitizeRelation(relation: Partial<Relation>, sourceCollection: EntityCollection, resolveCollection?: (slugOrTable: string) => EntityCollection | undefined): Relation;
|
|
3
3
|
export declare function resolveCollectionRelations(collection: EntityCollection): Record<string, Relation>;
|
|
4
4
|
export declare function resolvePropertyRelation({ propertyKey, property, sourceCollection }: {
|
|
5
5
|
propertyKey: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/common",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"exports": {
|
|
33
33
|
".": {
|
|
34
34
|
"types": "./dist/index.d.ts",
|
|
35
|
-
"development": "./
|
|
35
|
+
"development": "./dist/index.es.js",
|
|
36
36
|
"import": "./dist/index.es.js",
|
|
37
37
|
"require": "./dist/index.umd.js"
|
|
38
38
|
},
|
|
@@ -41,30 +41,27 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"fast-equals": "6.0.0",
|
|
43
43
|
"json-logic-js": "^2.0.5",
|
|
44
|
-
"@rebasepro/types": "0.1
|
|
45
|
-
"@rebasepro/utils": "0.1
|
|
44
|
+
"@rebasepro/types": "0.2.1",
|
|
45
|
+
"@rebasepro/utils": "0.2.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@jest/globals": "^29.7.0",
|
|
49
|
-
"@testing-library/react": "^16.3.
|
|
49
|
+
"@testing-library/react": "^16.3.2",
|
|
50
50
|
"@testing-library/user-event": "^14.6.1",
|
|
51
51
|
"@types/jest": "^29.5.14",
|
|
52
|
-
"@types/
|
|
53
|
-
"@types/node": "^20.17.14",
|
|
52
|
+
"@types/node": "^20.19.41",
|
|
54
53
|
"@types/object-hash": "^3.0.6",
|
|
55
|
-
"@types/react": "^19.
|
|
56
|
-
"@types/react-dom": "^19.
|
|
54
|
+
"@types/react": "^19.2.15",
|
|
55
|
+
"@types/react-dom": "^19.2.3",
|
|
57
56
|
"@types/react-measure": "^2.0.12",
|
|
58
|
-
"@vitejs/plugin-react": "^4.
|
|
57
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
59
58
|
"babel-plugin-react-compiler": "beta",
|
|
60
59
|
"cross-env": "^7.0.3",
|
|
61
|
-
"eslint-plugin-react-compiler": "beta",
|
|
62
60
|
"jest": "^29.7.0",
|
|
63
|
-
"
|
|
64
|
-
"ts-jest": "^29.3.1",
|
|
61
|
+
"ts-jest": "^29.4.10",
|
|
65
62
|
"tsd": "^0.31.2",
|
|
66
|
-
"typescript": "^5.
|
|
67
|
-
"vite": "^5.4.
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"vite": "^5.4.21"
|
|
68
65
|
},
|
|
69
66
|
"files": [
|
|
70
67
|
"dist",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { EntityCollection } from "@rebasepro/types";
|
|
2
|
+
export declare class CollectionRegistry {
|
|
3
|
+
private collectionsByTableName;
|
|
4
|
+
private collectionsBySlug;
|
|
5
|
+
private rootCollections;
|
|
6
|
+
private cachedCollectionsList;
|
|
7
|
+
private rawCollectionsByTableName;
|
|
8
|
+
private rawCollectionsBySlug;
|
|
9
|
+
private rawRootCollections;
|
|
10
|
+
private cachedRawCollectionsList;
|
|
11
|
+
private lastRawInputSnapshot;
|
|
12
|
+
constructor(collections?: EntityCollection[]);
|
|
13
|
+
reset(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Registers a collection and its subcollections recursively.
|
|
16
|
+
* Returns true if the collections have changed, false otherwise.
|
|
17
|
+
*
|
|
18
|
+
* Idempotent: compares the raw input (before normalization) against a stored
|
|
19
|
+
* snapshot. Only re-normalizes and re-registers when the raw input actually changed.
|
|
20
|
+
* @param collections
|
|
21
|
+
*/
|
|
22
|
+
registerMultiple(collections: EntityCollection[]): boolean;
|
|
23
|
+
register(collection: EntityCollection, rawCollection?: EntityCollection): void;
|
|
24
|
+
private _registerRecursively;
|
|
25
|
+
normalizeCollection(collection: EntityCollection): EntityCollection;
|
|
26
|
+
/**
|
|
27
|
+
* Extract Relation[] from properties that have inline relation config (i.e. `target` is set).
|
|
28
|
+
* This allows developers to define relations directly on properties without a separate
|
|
29
|
+
* `relations[]` entry on the collection.
|
|
30
|
+
*/
|
|
31
|
+
private extractRelationsFromProperties;
|
|
32
|
+
private normalizeProperties;
|
|
33
|
+
private normalizeProperty;
|
|
34
|
+
get(path: string): EntityCollection | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Gets the pristine, un-normalized collection exactly as it was provided.
|
|
37
|
+
* Useful for the AST editor so it doesn't accidentally serialize injected metadata back to disk.
|
|
38
|
+
*/
|
|
39
|
+
getRaw(path: string): EntityCollection | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Get collection by resolving multi-segment paths through relations
|
|
42
|
+
* e.g., "authors/70/posts" resolves to the posts collection
|
|
43
|
+
*/
|
|
44
|
+
getCollectionByPath(collectionPath: string): EntityCollection | undefined;
|
|
45
|
+
getCollections(): EntityCollection[];
|
|
46
|
+
getRawCollections(): EntityCollection[];
|
|
47
|
+
/**
|
|
48
|
+
* Resolves a multi-segment path like "products/123/locales" and returns
|
|
49
|
+
* information about the collections and entity IDs along the path
|
|
50
|
+
*/
|
|
51
|
+
resolvePathToCollections(path: string): {
|
|
52
|
+
collections: EntityCollection[];
|
|
53
|
+
entityIds: (string | number)[];
|
|
54
|
+
finalCollection: EntityCollection;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -9,15 +9,12 @@ import {
|
|
|
9
9
|
Relation,
|
|
10
10
|
RelationProperty,
|
|
11
11
|
StringProperty,
|
|
12
|
-
OnAction,
|
|
13
|
-
JoinStep,
|
|
14
12
|
getDataSourceCapabilities
|
|
15
13
|
} from "@rebasepro/types";
|
|
16
14
|
import { deepEqual } from "fast-equals";
|
|
17
15
|
|
|
18
16
|
import { enumToObjectEntries, getSubcollections, getTableName, resolveCollectionRelations, findRelation, sanitizeRelation } from "../util";
|
|
19
|
-
import
|
|
20
|
-
import { removeFunctions, mergeDeep } from "@rebasepro/utils";
|
|
17
|
+
import { removeFunctions, mergeDeep, deepClone } from "@rebasepro/utils";
|
|
21
18
|
|
|
22
19
|
export class CollectionRegistry {
|
|
23
20
|
|
|
@@ -72,8 +69,14 @@ export class CollectionRegistry {
|
|
|
72
69
|
return false;
|
|
73
70
|
}
|
|
74
71
|
|
|
75
|
-
// Raw input has changed — normalize and register
|
|
76
72
|
this.reset();
|
|
73
|
+
// Phase 0: Populate maps with raw collections first for string target resolution
|
|
74
|
+
collections.forEach((c) => {
|
|
75
|
+
if (c.slug) {
|
|
76
|
+
this.collectionsBySlug.set(c.slug, c);
|
|
77
|
+
}
|
|
78
|
+
this.collectionsByTableName.set(getTableName(c), c);
|
|
79
|
+
});
|
|
77
80
|
|
|
78
81
|
const normalizedCollections = collections.map(c => this.normalizeCollection({ ...c }));
|
|
79
82
|
|
|
@@ -83,7 +86,7 @@ export class CollectionRegistry {
|
|
|
83
86
|
// (e.g. Tags from Posts.relations) using the raw module object (without injected views)
|
|
84
87
|
// before the top-level Tags collection (with injected views) gets its turn.
|
|
85
88
|
normalizedCollections.forEach((c, index) => {
|
|
86
|
-
const raw =
|
|
89
|
+
const raw = deepClone(collections[index]);
|
|
87
90
|
this.rootCollections.push(c);
|
|
88
91
|
this.rawRootCollections.push(raw);
|
|
89
92
|
|
|
@@ -105,7 +108,7 @@ export class CollectionRegistry {
|
|
|
105
108
|
subcollections.forEach((subCollection) => {
|
|
106
109
|
if (!subCollection) return;
|
|
107
110
|
// Spread to avoid mutating the original target() return value
|
|
108
|
-
this._registerRecursively(this.normalizeCollection({ ...subCollection }),
|
|
111
|
+
this._registerRecursively(this.normalizeCollection({ ...subCollection }), deepClone(subCollection));
|
|
109
112
|
});
|
|
110
113
|
}
|
|
111
114
|
});
|
|
@@ -117,7 +120,7 @@ export class CollectionRegistry {
|
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
register(collection: EntityCollection, rawCollection?: EntityCollection) {
|
|
120
|
-
const raw = rawCollection ?
|
|
123
|
+
const raw = rawCollection ? deepClone(rawCollection) : deepClone(collection);
|
|
121
124
|
|
|
122
125
|
this.rootCollections.push(collection);
|
|
123
126
|
this.rawRootCollections.push(raw);
|
|
@@ -149,7 +152,7 @@ export class CollectionRegistry {
|
|
|
149
152
|
subcollections.forEach((subCollection) => {
|
|
150
153
|
if (!subCollection) return;
|
|
151
154
|
// Spread to avoid mutating the original target() return value
|
|
152
|
-
this._registerRecursively(this.normalizeCollection({ ...subCollection }),
|
|
155
|
+
this._registerRecursively(this.normalizeCollection({ ...subCollection }), deepClone(subCollection));
|
|
153
156
|
});
|
|
154
157
|
}
|
|
155
158
|
}
|
|
@@ -165,7 +168,7 @@ export class CollectionRegistry {
|
|
|
165
168
|
|
|
166
169
|
// 2. Merge with manual relations[] (manual entries win on name conflict)
|
|
167
170
|
const relResult = result as CollectionWithRelations;
|
|
168
|
-
const manualRelations = getDataSourceCapabilities(result.driver).supportsRelations ? (
|
|
171
|
+
const manualRelations = getDataSourceCapabilities(result.driver).supportsRelations ? (relResult.relations ?? []) : [];
|
|
169
172
|
const mergedRelationsRaw = [...extractedRelations];
|
|
170
173
|
for (const manual of manualRelations) {
|
|
171
174
|
const name = manual.relationName;
|
|
@@ -183,7 +186,7 @@ export class CollectionRegistry {
|
|
|
183
186
|
if (getDataSourceCapabilities(result.driver).supportsRelations) {
|
|
184
187
|
mergedRelations = mergedRelationsRaw.map(r => {
|
|
185
188
|
try {
|
|
186
|
-
return sanitizeRelation(r, result);
|
|
189
|
+
return sanitizeRelation(r, result, (slug) => this.get(slug));
|
|
187
190
|
} catch {
|
|
188
191
|
// sanitizeRelation may throw for incomplete configs
|
|
189
192
|
// (e.g. missing target). Keep the raw relation as-is.
|
|
@@ -192,7 +195,7 @@ export class CollectionRegistry {
|
|
|
192
195
|
});
|
|
193
196
|
|
|
194
197
|
// 3. Set the merged relations on the result copy
|
|
195
|
-
|
|
198
|
+
relResult.relations = mergedRelations;
|
|
196
199
|
}
|
|
197
200
|
|
|
198
201
|
// 4. Normalize properties (which stamps relation on each property)
|
|
@@ -203,8 +206,8 @@ export class CollectionRegistry {
|
|
|
203
206
|
if (!result.childCollections) {
|
|
204
207
|
if (getDataSourceCapabilities(result.driver).supportsSubcollections && (result as CollectionWithSubcollections).subcollections) {
|
|
205
208
|
result.childCollections = (result as CollectionWithSubcollections).subcollections;
|
|
206
|
-
} else if (getDataSourceCapabilities(result.driver).supportsRelations &&
|
|
207
|
-
const manyRelations =
|
|
209
|
+
} else if (getDataSourceCapabilities(result.driver).supportsRelations && relResult.relations) {
|
|
210
|
+
const manyRelations = relResult.relations.filter((r: Relation) => r.cardinality === "many");
|
|
208
211
|
if (manyRelations.length > 0) {
|
|
209
212
|
result.childCollections = () => manyRelations.map((r: Relation) => {
|
|
210
213
|
const target = r.target();
|
|
@@ -464,31 +467,3 @@ export class CollectionRegistry {
|
|
|
464
467
|
|
|
465
468
|
}
|
|
466
469
|
|
|
467
|
-
function areCollectionListsEqual(a: EntityCollection[], b: EntityCollection[]) {
|
|
468
|
-
// console.log("Comparing collection lists", a, b);
|
|
469
|
-
// return true;
|
|
470
|
-
if (a.length !== b.length) {
|
|
471
|
-
return false;
|
|
472
|
-
}
|
|
473
|
-
const aCopy = [...a];
|
|
474
|
-
const bCopy = [...b];
|
|
475
|
-
const aSorted = aCopy.sort((x, y) => x.slug.localeCompare(y.slug));
|
|
476
|
-
const bSorted = bCopy.sort((x, y) => x.slug.localeCompare(y.slug));
|
|
477
|
-
return aSorted.every((value, index) => areCollectionsEqual(value, bSorted[index]));
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function areCollectionsEqual(a: EntityCollection, b: EntityCollection) {
|
|
481
|
-
const subcollectionsA = getSubcollections(a);
|
|
482
|
-
const subcollectionsB = getSubcollections(b);
|
|
483
|
-
const { driver: _dA, ...restA } = a as EntityCollection & Record<string, unknown>;
|
|
484
|
-
const { driver: _dB, ...restB } = b as EntityCollection & Record<string, unknown>;
|
|
485
|
-
// Remove subcollections/relations from comparison objects (already handled above)
|
|
486
|
-
delete restA.subcollections;
|
|
487
|
-
delete restB.subcollections;
|
|
488
|
-
delete (restA as any).relations;
|
|
489
|
-
delete (restB as any).relations;
|
|
490
|
-
if (!areCollectionListsEqual(subcollectionsA, subcollectionsB)) {
|
|
491
|
-
return false;
|
|
492
|
-
}
|
|
493
|
-
return deepEqual(removeFunctions(restA), removeFunctions(restB));
|
|
494
|
-
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./CollectionRegistry";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DataDriver, RebaseData } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Build a `RebaseData` object from a `DataDriver` using JavaScript Proxy.
|
|
4
|
+
*
|
|
5
|
+
* This is the key bridge: any property access like `data.products` returns
|
|
6
|
+
* a `CollectionAccessor` backed by the underlying DataDriver, without
|
|
7
|
+
* needing per-collection code generation.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const data = buildRebaseData(driver);
|
|
11
|
+
* await data.products.create({ name: "Camera", price: 299 });
|
|
12
|
+
* const { data: items } = await data.products.find({ where: { status: "eq.published" } });
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildRebaseData(driver: DataDriver): RebaseData;
|
package/src/index.d.ts
ADDED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
declare module "json-logic-js" {
|
|
2
2
|
interface JsonLogic {
|
|
3
3
|
apply(logic: unknown, data?: unknown): unknown;
|
|
4
|
-
add_operation<T extends
|
|
4
|
+
add_operation<T extends unknown[]>(name: string, fn: (...args: T) => unknown): void;
|
|
5
5
|
}
|
|
6
6
|
const jsonLogic: JsonLogic;
|
|
7
7
|
export default jsonLogic;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AdditionalFieldDelegate, ArrayProperty, BooleanProperty, DateProperty, EntityCallbacks, EntityCollection, EnumValueConfig, EnumValues, GeopointProperty, MapProperty, NumberProperty, Properties, Property, ReferenceProperty, StringProperty, User } from "@rebasepro/types";
|
|
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
|
|
6
|
+
* @group Builder
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(collection: EntityCollection<M, USER>): EntityCollection<M, USER>;
|
|
9
|
+
/**
|
|
10
|
+
* Identity function we use to defeat the type system of Typescript and preserve
|
|
11
|
+
* the property keys.
|
|
12
|
+
* @param property
|
|
13
|
+
* @group Builder
|
|
14
|
+
*/
|
|
15
|
+
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;
|
|
16
|
+
/**
|
|
17
|
+
* Identity function we use to defeat the type system of Typescript and preserve
|
|
18
|
+
* the properties keys.
|
|
19
|
+
* @param properties
|
|
20
|
+
* @group Builder
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildProperties<M extends Record<string, unknown>>(properties: Properties): Properties;
|
|
23
|
+
/**
|
|
24
|
+
* Identity function we use to defeat the type system of Typescript and preserve
|
|
25
|
+
* the properties keys.
|
|
26
|
+
* @param propertiesOrBuilder
|
|
27
|
+
* @group Builder
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildPropertiesOrBuilder<M extends Record<string, unknown>>(propertiesOrBuilder: Properties): Properties;
|
|
30
|
+
/**
|
|
31
|
+
* Identity function we use to defeat the type system of Typescript and preserve
|
|
32
|
+
* the properties keys.
|
|
33
|
+
* @param enumValues
|
|
34
|
+
* @group Builder
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildEnum(enumValues: EnumValues): EnumValues;
|
|
37
|
+
/**
|
|
38
|
+
* Identity function we use to defeat the type system of Typescript and preserve
|
|
39
|
+
* the properties keys.
|
|
40
|
+
* @param enumValueConfig
|
|
41
|
+
* @group Builder
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildEnumValueConfig(enumValueConfig: EnumValueConfig): EnumValueConfig;
|
|
44
|
+
/**
|
|
45
|
+
* Identity function we use to defeat the type system of Typescript and preserve
|
|
46
|
+
* the properties keys.
|
|
47
|
+
* @param callbacks
|
|
48
|
+
* @group Builder
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildEntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>>(callbacks: EntityCallbacks<M>): EntityCallbacks<M>;
|
|
51
|
+
/**
|
|
52
|
+
* Identity function we use to defeat the type system of Typescript and build
|
|
53
|
+
* additional field delegates views with all its properties
|
|
54
|
+
* @param additionalFieldDelegate
|
|
55
|
+
* @group Builder
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildAdditionalFieldDelegate<M extends Record<string, unknown>, USER extends User = User>(additionalFieldDelegate: AdditionalFieldDelegate<M, USER>): AdditionalFieldDelegate<M, USER>;
|
package/src/util/builders.ts
CHANGED
|
@@ -50,6 +50,7 @@ export function buildProperty<T, P extends Property = Property>(
|
|
|
50
50
|
P extends ArrayProperty ? ArrayProperty :
|
|
51
51
|
P extends MapProperty ? MapProperty : never {
|
|
52
52
|
|
|
53
|
+
// SAFETY: Identity function — P is a subtype of the conditional return type by definition
|
|
53
54
|
return property as unknown as ReturnType<typeof buildProperty<T, P>>;
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EntityCallbacks, Properties } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Helper function to extract field-level PropertyCallbacks from a properties schema
|
|
4
|
+
* and wrap them into an EntityCallbacks object recursively.
|
|
5
|
+
*/
|
|
6
|
+
export declare const buildPropertyCallbacks: (properties: Properties) => EntityCallbacks | undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DefaultSelectedViewBuilder, DefaultSelectedViewParams, EntityCollection, Properties } from "@rebasepro/types";
|
|
2
|
+
export declare function sortProperties<M extends Record<string, unknown>>(properties: Properties, propertiesOrder?: string[]): Properties;
|
|
3
|
+
export declare function resolveDefaultSelectedView(defaultSelectedView: string | DefaultSelectedViewBuilder | undefined, params: DefaultSelectedViewParams): string | undefined;
|
|
4
|
+
export declare function getLocalChangesBackup(collection: EntityCollection): "manual_apply" | "auto_apply";
|
|
5
|
+
/**
|
|
6
|
+
* Returns the primary keys for an entity collection by inspecting the properties
|
|
7
|
+
* and finding any properties with `isId`.
|
|
8
|
+
* Fallbacks to `["id"]` if no properties are marked as `isId: true`.
|
|
9
|
+
* @param collection
|
|
10
|
+
*/
|
|
11
|
+
export declare function getPrimaryKeys<M extends Record<string, unknown>>(collection: EntityCollection<M>): Extract<keyof M, string>[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AuthController, ConditionContext, JsonLogicRule, Property } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Register custom JSON Logic operations for Rebase.
|
|
4
|
+
* Call this once at app initialization.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerConditionOperations(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Evaluate a JSON Logic rule against the given context.
|
|
9
|
+
*/
|
|
10
|
+
export declare function evaluateCondition(rule: JsonLogicRule, context: ConditionContext): unknown;
|
|
11
|
+
/**
|
|
12
|
+
* Build a ConditionContext from the current property resolution context.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildConditionContext(params: {
|
|
15
|
+
propertyKey?: string;
|
|
16
|
+
values?: Record<string, unknown>;
|
|
17
|
+
previousValues?: Record<string, unknown>;
|
|
18
|
+
path: string;
|
|
19
|
+
entityId?: string;
|
|
20
|
+
index?: number;
|
|
21
|
+
authController: AuthController;
|
|
22
|
+
}): ConditionContext;
|
|
23
|
+
/**
|
|
24
|
+
* Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
|
|
25
|
+
*/
|
|
26
|
+
export declare function applyPropertyConditions(property: Property, context: ConditionContext): Property;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { DataType, Entity, EntityReference, EntityRelation, EntityStatus, EntityValues, Properties, Property } from "@rebasepro/types";
|
|
2
|
+
export declare function isReadOnly(property: Property): boolean;
|
|
3
|
+
export declare function isHidden(property: Property): boolean;
|
|
4
|
+
export declare function isPropertyBuilder(property?: Property): boolean;
|
|
5
|
+
export declare function getDefaultValuesFor<M extends Record<string, unknown>>(properties: Properties): Partial<EntityValues<M>>;
|
|
6
|
+
export declare function getDefaultValueFor(property?: Property): unknown;
|
|
7
|
+
export declare function getDefaultValueFortype(type: DataType): unknown;
|
|
8
|
+
/**
|
|
9
|
+
* Update the automatic values in an entity before save
|
|
10
|
+
* @group Driver
|
|
11
|
+
*/
|
|
12
|
+
export declare function updateDateAutoValues<M extends Record<string, unknown>>({ inputValues, properties, status, timestampNowValue }: {
|
|
13
|
+
inputValues: Partial<EntityValues<M>>;
|
|
14
|
+
properties: Properties;
|
|
15
|
+
status: EntityStatus;
|
|
16
|
+
timestampNowValue: unknown;
|
|
17
|
+
}): EntityValues<M>;
|
|
18
|
+
/**
|
|
19
|
+
* Add missing required fields, expected in the collection, to the values of an entity
|
|
20
|
+
* @param values
|
|
21
|
+
* @param properties
|
|
22
|
+
* @group Driver
|
|
23
|
+
*/
|
|
24
|
+
export declare function sanitizeData<M extends Record<string, unknown>>(values: EntityValues<M>, properties: Properties): Record<string, unknown>;
|
|
25
|
+
export declare function getReferenceFrom<M extends Record<string, unknown>>(entity: Entity<M>): EntityReference;
|
|
26
|
+
export declare function getRelationFrom<M extends Record<string, unknown>>(entity: Entity<M>): EntityRelation;
|
|
27
|
+
/**
|
|
28
|
+
* Normalize a value into a proper EntityRelation instance.
|
|
29
|
+
* Handles EntityRelation class instances, and plain objects
|
|
30
|
+
* with `__type === "relation"` or an `isEntityRelation()` method.
|
|
31
|
+
*
|
|
32
|
+
* Returns null if the value cannot be coerced.
|
|
33
|
+
*/
|
|
34
|
+
export declare function normalizeToEntityRelation(value: unknown): EntityRelation | null;
|
|
35
|
+
export declare function traverseValuesProperties<M extends Record<string, unknown>>(inputValues: Partial<EntityValues<M>>, properties: Properties, operation: (value: unknown, property: Property) => unknown): EntityValues<M> | undefined;
|
|
36
|
+
export declare function traverseValueProperty(inputValue: unknown, property: Property, operation: (value: unknown, property: Property) => unknown): unknown;
|
|
37
|
+
/**
|
|
38
|
+
* Relation reference types used throughout the server layer.
|
|
39
|
+
* These replace the 50+ manual `{ id, path, __type: "relation" }` constructions.
|
|
40
|
+
*/
|
|
41
|
+
export interface RelationRef {
|
|
42
|
+
readonly id: string | number;
|
|
43
|
+
readonly path: string;
|
|
44
|
+
readonly __type: "relation";
|
|
45
|
+
}
|
|
46
|
+
export interface RelationRefWithData extends RelationRef {
|
|
47
|
+
readonly data: Entity;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a lightweight relation stub for CMS views.
|
|
51
|
+
* Replaces inline `{ id, path, __type: "relation" }` object literals.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createRelationRef(id: string | number, path: string): RelationRef;
|
|
54
|
+
/**
|
|
55
|
+
* Create a hydrated relation reference that includes the full entity data.
|
|
56
|
+
* Used when entity data has been pre-fetched (e.g., via batch loading or JOINs).
|
|
57
|
+
*/
|
|
58
|
+
export declare function createRelationRefWithData(id: string | number, path: string, data: Entity): RelationRefWithData;
|
package/src/util/entities.ts
CHANGED
|
@@ -44,7 +44,7 @@ export function getDefaultValuesFor<M extends Record<string, unknown>>(propertie
|
|
|
44
44
|
...b }), {}) as EntityValues<M>;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export function getDefaultValueFor(property?: Property) {
|
|
47
|
+
export function getDefaultValueFor(property?: Property): unknown {
|
|
48
48
|
if (!property) return undefined;
|
|
49
49
|
if (isPropertyBuilder(property)) return undefined;
|
|
50
50
|
if (property.defaultValue || property.defaultValue === null) {
|
|
@@ -58,7 +58,7 @@ export function getDefaultValueFor(property?: Property) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export function getDefaultValueFortype(type: DataType) {
|
|
61
|
+
export function getDefaultValueFortype(type: DataType): unknown {
|
|
62
62
|
if (type === "string") {
|
|
63
63
|
return null;
|
|
64
64
|
} else if (type === "number") {
|
|
@@ -71,6 +71,10 @@ export function getDefaultValueFortype(type: DataType) {
|
|
|
71
71
|
return [];
|
|
72
72
|
} else if (type === "map") {
|
|
73
73
|
return {};
|
|
74
|
+
} else if (type === "vector") {
|
|
75
|
+
return null;
|
|
76
|
+
} else if (type === "binary") {
|
|
77
|
+
return null;
|
|
74
78
|
} else {
|
|
75
79
|
return null;
|
|
76
80
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { EnumValueConfig, EnumValues } from "@rebasepro/types";
|
|
2
|
+
export declare function enumToObjectEntries(enumValues: EnumValues): EnumValueConfig[];
|
|
3
|
+
export declare function getLabelOrConfigFrom(enumValues: EnumValueConfig[], key?: string | number): EnumValueConfig | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./collections";
|
|
2
|
+
export * from "./common";
|
|
3
|
+
export * from "./entities";
|
|
4
|
+
export * from "./enums";
|
|
5
|
+
export * from "./paths";
|
|
6
|
+
export * from "./resolutions";
|
|
7
|
+
export * from "./permissions";
|
|
8
|
+
export * from "./references";
|
|
9
|
+
export * from "./navigation_from_path";
|
|
10
|
+
export * from "./parent_references_from_path";
|
|
11
|
+
export * from "./builders";
|
|
12
|
+
export * from "./storage";
|
|
13
|
+
export * from "./callbacks";
|
|
14
|
+
export * from "./relations";
|
|
15
|
+
export * from "./conditions";
|
|
16
|
+
export * from "./navigation_utils";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EntityCollection } from "@rebasepro/types";
|
|
2
|
+
type EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = {
|
|
3
|
+
key: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
export type NavigationViewInternal<M extends Record<string, unknown> = Record<string, unknown>> = NavigationViewEntityInternal<M> | NavigationViewCollectionInternal<M> | NavigationViewEntityCustomInternal<M>;
|
|
7
|
+
export interface NavigationViewEntityInternal<M extends Record<string, unknown>> {
|
|
8
|
+
type: "entity";
|
|
9
|
+
entityId: string | number;
|
|
10
|
+
slug: string;
|
|
11
|
+
path: string;
|
|
12
|
+
parentCollection: EntityCollection<M>;
|
|
13
|
+
}
|
|
14
|
+
export interface NavigationViewCollectionInternal<M extends Record<string, unknown>> {
|
|
15
|
+
type: "collection";
|
|
16
|
+
id: string;
|
|
17
|
+
slug: string;
|
|
18
|
+
path: string;
|
|
19
|
+
collection: EntityCollection<M>;
|
|
20
|
+
}
|
|
21
|
+
export interface NavigationViewEntityCustomInternal<M extends Record<string, unknown>> {
|
|
22
|
+
type: "custom_view";
|
|
23
|
+
slug: string;
|
|
24
|
+
path: string;
|
|
25
|
+
entityId: string | number;
|
|
26
|
+
view: EntityCustomView<M>;
|
|
27
|
+
}
|
|
28
|
+
export declare function getNavigationEntriesFromPath(props: {
|
|
29
|
+
path: string;
|
|
30
|
+
collections: EntityCollection[] | undefined;
|
|
31
|
+
currentFullPath?: string;
|
|
32
|
+
contextEntityViews?: EntityCustomView[];
|
|
33
|
+
}): NavigationViewInternal[];
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EntityCollection } from "@rebasepro/types";
|
|
2
|
+
export declare function removeInitialAndTrailingSlashes(s: string): string;
|
|
3
|
+
export declare function removeInitialSlash(s: string): string;
|
|
4
|
+
export declare function removeTrailingSlash(s: string): string;
|
|
5
|
+
export declare function addInitialSlash(s: string): string;
|
|
6
|
+
export declare function getLastSegment(path: string): string;
|
|
7
|
+
export declare function resolveCollectionPathIds(path: string, allCollections: EntityCollection[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* Find the corresponding view at any depth for a given path.
|
|
10
|
+
* Note that path or segments of the paths can be collection aliases.
|
|
11
|
+
* @param slugOrPath
|
|
12
|
+
* @param collections
|
|
13
|
+
*/
|
|
14
|
+
export declare function getCollectionBySlugWithin(slugOrPath: string, collections: EntityCollection[]): EntityCollection | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Get the subcollection combinations from a path:
|
|
17
|
+
* "sites/es/locales" => ["sites/es/locales", "sites"]
|
|
18
|
+
* @param subpaths
|
|
19
|
+
*/
|
|
20
|
+
export declare function getCollectionPathsCombinations(subpaths: string[]): string[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const COLLECTION_PATH_SEPARATOR = "::";
|
|
2
|
+
/**
|
|
3
|
+
* Remove the entity ids from a given path
|
|
4
|
+
* `products/B44RG6APH/locales` => `products::locales`
|
|
5
|
+
* @param path
|
|
6
|
+
*/
|
|
7
|
+
export declare function stripCollectionPath(path: string): string;
|
|
8
|
+
export declare function segmentsToStrippedPath(paths: string[]): string;
|
|
9
|
+
/**
|
|
10
|
+
* Extract the collection path routes
|
|
11
|
+
* `products/B44RG6APH/locales` => [`products`, `locales`]
|
|
12
|
+
* @param path
|
|
13
|
+
*/
|
|
14
|
+
export declare function fullPathToCollectionSegments(path: string): string[];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AuthController, Entity, EntityCollection, User } from "@rebasepro/types";
|
|
2
|
+
export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>): boolean;
|
|
3
|
+
export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
|
|
4
|
+
export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
|
|
5
|
+
export declare function canDeleteEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
|