@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.
Files changed (65) hide show
  1. package/README.md +5 -5
  2. package/dist/collections/CollectionRegistry.d.ts +16 -16
  3. package/dist/collections/default-collections.d.ts +5 -1
  4. package/dist/data/buildRebaseData.d.ts +44 -3
  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 +1236 -179
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/util/auth-default-policies.d.ts +22 -0
  14. package/dist/util/builders.d.ts +19 -56
  15. package/dist/util/callbacks.d.ts +3 -3
  16. package/dist/util/collections.d.ts +4 -4
  17. package/dist/util/entities.d.ts +2 -2
  18. package/dist/util/filter-operator-resolution.d.ts +32 -0
  19. package/dist/util/identity.d.ts +83 -0
  20. package/dist/util/index.d.ts +4 -0
  21. package/dist/util/junction-policies.d.ts +108 -0
  22. package/dist/util/navigation_from_path.d.ts +4 -4
  23. package/dist/util/navigation_utils.d.ts +3 -3
  24. package/dist/util/parent_references_from_path.d.ts +2 -2
  25. package/dist/util/permissions.d.ts +6 -6
  26. package/dist/util/policy/evaluatePolicy.d.ts +8 -1
  27. package/dist/util/policy/index.d.ts +1 -0
  28. package/dist/util/policy/policyToPostgres.d.ts +14 -2
  29. package/dist/util/policy/sqlToPolicy.d.ts +24 -14
  30. package/dist/util/references.d.ts +2 -2
  31. package/dist/util/relations.d.ts +5 -5
  32. package/dist/util/resolutions.d.ts +2 -2
  33. package/package.json +7 -8
  34. package/src/collections/CollectionRegistry.ts +36 -36
  35. package/src/collections/default-collections.ts +2 -0
  36. package/src/data/buildRebaseData.ts +430 -60
  37. package/src/data/buildRoutedRebaseData.ts +22 -16
  38. package/src/data/filter-dialect.ts +151 -60
  39. package/src/data/query_builder.ts +11 -2
  40. package/src/data/resolveDataSource.ts +1 -1
  41. package/src/data/sort-dialect.ts +56 -0
  42. package/src/index.ts +1 -0
  43. package/src/util/auth-default-policies.ts +152 -0
  44. package/src/util/builders.ts +25 -99
  45. package/src/util/callbacks.ts +8 -8
  46. package/src/util/collections.ts +4 -4
  47. package/src/util/entities.ts +4 -4
  48. package/src/util/filter-operator-resolution.ts +81 -0
  49. package/src/util/identity.ts +166 -0
  50. package/src/util/index.ts +4 -0
  51. package/src/util/junction-policies.ts +353 -0
  52. package/src/util/navigation_from_path.ts +4 -4
  53. package/src/util/navigation_utils.ts +8 -8
  54. package/src/util/parent_references_from_path.ts +3 -3
  55. package/src/util/permissions.test.ts +2 -2
  56. package/src/util/permissions.ts +7 -7
  57. package/src/util/policy/evaluatePolicy.ts +26 -4
  58. package/src/util/policy/index.ts +1 -0
  59. package/src/util/policy/policyToPostgres.ts +123 -17
  60. package/src/util/policy/sqlToPolicy.ts +190 -13
  61. package/src/util/references.ts +2 -2
  62. package/src/util/relations.ts +12 -12
  63. package/src/util/resolutions.ts +5 -5
  64. package/dist/index.umd.js +0 -2901
  65. package/dist/index.umd.js.map +0 -1
@@ -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.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.umd.js",
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": ">=14"
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/utils": "0.8.0",
45
- "@rebasepro/types": "0.8.0"
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
- 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
  }
@@ -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
  },