@rebasepro/common 0.8.0 → 0.9.1-canary.09aaf62
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 +5 -5
- package/dist/collections/CollectionRegistry.d.ts +16 -16
- package/dist/collections/default-collections.d.ts +5 -1
- package/dist/data/buildRebaseData.d.ts +44 -3
- 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 +1236 -179
- package/dist/index.es.js.map +1 -1
- package/dist/util/auth-default-policies.d.ts +22 -0
- 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/identity.d.ts +83 -0
- package/dist/util/index.d.ts +4 -0
- package/dist/util/junction-policies.d.ts +108 -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/evaluatePolicy.d.ts +8 -1
- package/dist/util/policy/index.d.ts +1 -0
- package/dist/util/policy/policyToPostgres.d.ts +14 -2
- package/dist/util/policy/sqlToPolicy.d.ts +24 -14
- 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 +7 -8
- package/src/collections/CollectionRegistry.ts +36 -36
- package/src/collections/default-collections.ts +2 -0
- package/src/data/buildRebaseData.ts +430 -60
- package/src/data/buildRoutedRebaseData.ts +22 -16
- package/src/data/filter-dialect.ts +151 -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/auth-default-policies.ts +152 -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/identity.ts +166 -0
- package/src/util/index.ts +4 -0
- package/src/util/junction-policies.ts +353 -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 +26 -4
- package/src/util/policy/index.ts +1 -0
- package/src/util/policy/policyToPostgres.ts +123 -17
- package/src/util/policy/sqlToPolicy.ts +190 -13
- package/src/util/references.ts +2 -2
- package/src/util/relations.ts +12 -12
- package/src/util/resolutions.ts +5 -5
- package/dist/index.umd.js +0 -2901
- package/dist/index.umd.js.map +0 -1
|
@@ -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.1-canary.09aaf62",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"url": "https://github.com/rebasepro/rebase.git",
|
|
14
14
|
"directory": "packages/common"
|
|
15
15
|
},
|
|
16
|
-
"main": "./dist/index.
|
|
16
|
+
"main": "./dist/index.es.js",
|
|
17
17
|
"module": "./dist/index.es.js",
|
|
18
18
|
"types": "./dist/index.d.ts",
|
|
19
19
|
"source": "src/index.ts",
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": ">=
|
|
21
|
+
"node": ">=20"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"rebase",
|
|
@@ -33,16 +33,15 @@
|
|
|
33
33
|
".": {
|
|
34
34
|
"types": "./dist/index.d.ts",
|
|
35
35
|
"development": "./dist/index.es.js",
|
|
36
|
-
"import": "./dist/index.es.js"
|
|
37
|
-
"require": "./dist/index.umd.js"
|
|
36
|
+
"import": "./dist/index.es.js"
|
|
38
37
|
},
|
|
39
38
|
"./package.json": "./package.json"
|
|
40
39
|
},
|
|
41
40
|
"dependencies": {
|
|
42
41
|
"fast-equals": "6.0.0",
|
|
43
42
|
"json-logic-js": "^2.0.5",
|
|
44
|
-
"@rebasepro/
|
|
45
|
-
"@rebasepro/
|
|
43
|
+
"@rebasepro/types": "0.9.1-canary.09aaf62",
|
|
44
|
+
"@rebasepro/utils": "0.9.1-canary.09aaf62"
|
|
46
45
|
},
|
|
47
46
|
"devDependencies": {
|
|
48
47
|
"@jest/globals": "^30.4.1",
|
|
@@ -100,7 +99,7 @@
|
|
|
100
99
|
},
|
|
101
100
|
"scripts": {
|
|
102
101
|
"watch": "vite build --watch",
|
|
103
|
-
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
102
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../scripts/assert-build-output.mjs",
|
|
104
103
|
"test:lint": "eslint \"src/**\" --quiet",
|
|
105
104
|
"test": "jest --passWithNoTests",
|
|
106
105
|
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f",
|
|
@@ -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
|
}
|
|
@@ -68,6 +68,7 @@ unique: true }
|
|
|
68
68
|
name: "Password Hash",
|
|
69
69
|
type: "string",
|
|
70
70
|
columnName: "password_hash",
|
|
71
|
+
excludeFromApi: true,
|
|
71
72
|
ui: { hideFromCollection: true,
|
|
72
73
|
disabled: { hidden: true } }
|
|
73
74
|
},
|
|
@@ -83,6 +84,7 @@ disabled: { hidden: true } }
|
|
|
83
84
|
name: "Email Verification Token",
|
|
84
85
|
type: "string",
|
|
85
86
|
columnName: "email_verification_token",
|
|
87
|
+
excludeFromApi: true,
|
|
86
88
|
ui: { hideFromCollection: true,
|
|
87
89
|
disabled: { hidden: true } }
|
|
88
90
|
},
|