@rebasepro/common 0.7.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 +30 -15
- package/dist/collections/default-collections.d.ts +255 -2
- package/dist/data/buildRebaseData.d.ts +30 -2
- package/dist/data/buildRoutedRebaseData.d.ts +14 -9
- package/dist/data/filter-dialect.d.ts +75 -0
- package/dist/data/query_builder.d.ts +4 -4
- package/dist/data/resolveDataSource.d.ts +8 -8
- package/dist/data/sort-dialect.d.ts +41 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +1125 -299
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1138 -303
- package/dist/index.umd.js.map +1 -1
- package/dist/util/builders.d.ts +52 -42
- package/dist/util/callbacks.d.ts +8 -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 +2 -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 +30 -6
- package/dist/util/policy/evaluatePolicy.d.ts +31 -0
- package/dist/util/policy/index.d.ts +3 -0
- package/dist/util/policy/policyToPostgres.d.ts +22 -0
- package/dist/util/policy/securityRuleToConditions.d.ts +24 -0
- package/dist/util/policy/sqlToPolicy.d.ts +20 -0
- 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/dist/util/storage.d.ts +26 -1
- package/package.json +13 -13
- package/src/collections/CollectionRegistry.ts +92 -61
- package/src/collections/default-collections.ts +4 -4
- package/src/data/buildRebaseData.ts +336 -172
- package/src/data/buildRoutedRebaseData.ts +22 -16
- package/src/data/filter-dialect.ts +403 -0
- package/src/data/query_builder.ts +19 -10
- package/src/data/resolveDataSource.ts +10 -10
- package/src/data/sort-dialect.ts +56 -0
- package/src/index.ts +2 -0
- package/src/util/builders.ts +87 -84
- package/src/util/callbacks.ts +15 -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 +2 -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 +7 -5
- package/src/util/permissions.ts +90 -163
- package/src/util/policy/evaluatePolicy.ts +152 -0
- package/src/util/policy/index.ts +3 -0
- package/src/util/policy/policyToPostgres.ts +165 -0
- package/src/util/policy/securityRuleToConditions.ts +67 -0
- package/src/util/policy/sqlToPolicy.ts +88 -0
- package/src/util/references.ts +3 -3
- package/src/util/relations.ts +19 -20
- package/src/util/resolutions.ts +11 -11
- package/src/util/storage.ts +34 -1
package/dist/util/builders.d.ts
CHANGED
|
@@ -1,57 +1,67 @@
|
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
+
* Define a PostgreSQL-backed collection with full type inference.
|
|
14
|
+
*
|
|
15
|
+
* The `const P` generic captures literal property types from your
|
|
16
|
+
* `properties` object, which enables autocomplete on `titleProperty`,
|
|
17
|
+
* `sort`, `propertiesOrder`, `fixedFilter`, and entity callbacks.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const products = defineCollection({
|
|
22
|
+
* name: "Products",
|
|
23
|
+
* slug: "products",
|
|
24
|
+
* table: "products",
|
|
25
|
+
* properties: {
|
|
26
|
+
* name: { name: "Name", type: "string", validation: { required: true } },
|
|
27
|
+
* price: { name: "Price", type: "number" },
|
|
28
|
+
* },
|
|
29
|
+
* titleProperty: "name", // ✅ autocomplete: "name" | "price"
|
|
30
|
+
* sort: ["price", "asc"], // ✅ autocomplete on first element
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
13
34
|
* @group Builder
|
|
14
35
|
*/
|
|
15
|
-
export declare function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @group Builder
|
|
21
|
-
*/
|
|
22
|
-
export declare function buildProperties<M extends Record<string, unknown>>(properties: Properties): Properties;
|
|
36
|
+
export declare function defineCollection<const P extends PostgresProperties, USER extends User = User>(collection: Omit<PostgresCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
|
|
37
|
+
properties: P;
|
|
38
|
+
}): PostgresCollectionConfig<InferEntityType<P>, USER> & {
|
|
39
|
+
properties: P;
|
|
40
|
+
};
|
|
23
41
|
/**
|
|
24
|
-
*
|
|
25
|
-
* the properties keys.
|
|
26
|
-
* @param propertiesOrBuilder
|
|
42
|
+
* Define a Firestore-backed collection with full type inference.
|
|
27
43
|
* @group Builder
|
|
28
44
|
*/
|
|
29
|
-
export declare function
|
|
45
|
+
export declare function defineCollection<const P extends FirebaseProperties, USER extends User = User>(collection: Omit<FirebaseCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
|
|
46
|
+
properties: P;
|
|
47
|
+
}): FirebaseCollectionConfig<InferEntityType<P>, USER> & {
|
|
48
|
+
properties: P;
|
|
49
|
+
};
|
|
30
50
|
/**
|
|
31
|
-
*
|
|
32
|
-
* the properties keys.
|
|
33
|
-
* @param enumValues
|
|
51
|
+
* Define a MongoDB-backed collection with full type inference.
|
|
34
52
|
* @group Builder
|
|
35
53
|
*/
|
|
36
|
-
export declare function
|
|
54
|
+
export declare function defineCollection<const P extends MongoProperties, USER extends User = User>(collection: Omit<MongoDBCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
|
|
55
|
+
properties: P;
|
|
56
|
+
}): MongoDBCollectionConfig<InferEntityType<P>, USER> & {
|
|
57
|
+
properties: P;
|
|
58
|
+
};
|
|
37
59
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
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
|
+
*
|
|
41
65
|
* @group Builder
|
|
42
66
|
*/
|
|
43
|
-
export declare function
|
|
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>;
|
|
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;
|
package/dist/util/callbacks.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CollectionCallbacks, Properties, RebaseCallContext } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Context passed to entity lifecycle callbacks.
|
|
4
|
+
* @group Models
|
|
5
|
+
*/
|
|
6
|
+
export type EntityCallbackContext = RebaseCallContext;
|
|
2
7
|
/**
|
|
3
8
|
* Helper function to extract field-level PropertyCallbacks from a properties schema
|
|
4
|
-
* and wrap them into an
|
|
9
|
+
* and wrap them into an CollectionCallbacks object recursively.
|
|
5
10
|
*/
|
|
6
|
-
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
|
@@ -4,6 +4,7 @@ export * from "./entities";
|
|
|
4
4
|
export * from "./enums";
|
|
5
5
|
export * from "./paths";
|
|
6
6
|
export * from "./resolutions";
|
|
7
|
+
export * from "./policy";
|
|
7
8
|
export * from "./permissions";
|
|
8
9
|
export * from "./references";
|
|
9
10
|
export * from "./navigation_from_path";
|
|
@@ -14,3 +15,4 @@ export * from "./callbacks";
|
|
|
14
15
|
export * from "./relations";
|
|
15
16
|
export * from "./conditions";
|
|
16
17
|
export * from "./navigation_utils";
|
|
18
|
+
export * from "./filter-operator-resolution";
|
|
@@ -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
|
|
@@ -7,8 +7,32 @@ import { Entity, EntityCollection, User } from "@rebasepro/types";
|
|
|
7
7
|
export interface AuthContext<USER extends User = User> {
|
|
8
8
|
user: USER | null;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
/**
|
|
11
|
+
* How to resolve a policy result that cannot be decided client-side (a raw-SQL
|
|
12
|
+
* escape-hatch rule, or a row-column reference with no row in hand).
|
|
13
|
+
*
|
|
14
|
+
* - `"allow"` (default): optimistic — used for admin-UI gating, where Postgres
|
|
15
|
+
* remains the authoritative gate and hiding a working action is worse than
|
|
16
|
+
* showing one the server may reject.
|
|
17
|
+
* - `"deny"`: fail-closed — used by real enforcement callers (e.g. a driver
|
|
18
|
+
* applying policies in-process), so an undecidable rule never silently allows.
|
|
19
|
+
*/
|
|
20
|
+
export type UnknownResolution = "allow" | "deny";
|
|
21
|
+
export interface CheckOperationOptions {
|
|
22
|
+
onUnknown?: UnknownResolution;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Decide whether an operation is permitted for a user on a (possibly null) row,
|
|
26
|
+
* by evaluating the collection's security rules with the shared policy model —
|
|
27
|
+
* the same model compiled to Postgres RLS DDL, so the decision matches database
|
|
28
|
+
* enforcement for every non-raw rule.
|
|
29
|
+
*
|
|
30
|
+
* @param options.onUnknown how to treat rules that cannot be decided
|
|
31
|
+
* client-side (raw SQL, or row predicates with no row). Defaults to `"allow"`
|
|
32
|
+
* for optimistic UI gating; enforcement callers should pass `"deny"`.
|
|
33
|
+
*/
|
|
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;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Entity, PolicyExpression } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Result of evaluating a policy client-side. `"unknown"` means the expression
|
|
4
|
+
* could not be decided without more information — either a raw-SQL escape-hatch
|
|
5
|
+
* node (which the client deliberately never guesses) or a row-column reference
|
|
6
|
+
* with no entity in hand (e.g. list-level gating). Callers decide how to resolve
|
|
7
|
+
* `"unknown"`: fail-closed for an enforcement decision, optimistic for pure
|
|
8
|
+
* visibility gating.
|
|
9
|
+
*/
|
|
10
|
+
export type TriState = boolean | "unknown";
|
|
11
|
+
/**
|
|
12
|
+
* Context for {@link evaluatePolicy}: the acting user (or none) and the row
|
|
13
|
+
* being evaluated (or none, for collection-level gating).
|
|
14
|
+
*/
|
|
15
|
+
export interface PolicyEvalContext {
|
|
16
|
+
/** The current user's id, or null/undefined when unauthenticated. */
|
|
17
|
+
uid?: string | null;
|
|
18
|
+
/** The current user's application roles. */
|
|
19
|
+
roles?: string[];
|
|
20
|
+
/** The row being evaluated, or null when no specific row is available. */
|
|
21
|
+
entity: Entity | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Evaluates a {@link PolicyExpression} against a user + row, using three-valued
|
|
25
|
+
* (Kleene) logic so that `"unknown"` sub-results propagate soundly.
|
|
26
|
+
*
|
|
27
|
+
* This is the JavaScript twin of {@link policyToPostgres}: both derive from the
|
|
28
|
+
* same expression, so the admin UI matches database enforcement by construction
|
|
29
|
+
* for every non-raw rule.
|
|
30
|
+
*/
|
|
31
|
+
export declare function evaluatePolicy(expr: PolicyExpression, ctx: PolicyEvalContext): TriState;
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compiles a {@link PolicyExpression} to a PostgreSQL boolean SQL string,
|
|
16
|
+
* suitable for a `USING (...)` / `WITH CHECK (...)` clause.
|
|
17
|
+
*
|
|
18
|
+
* This is one of the two consumers of the shared policy model (the other being
|
|
19
|
+
* {@link evaluatePolicy}); the Postgres schema generators call it so that DDL
|
|
20
|
+
* and the admin UI derive from the exact same expression.
|
|
21
|
+
*/
|
|
22
|
+
export declare function policyToPostgres(expr: PolicyExpression, collection?: CollectionConfig, options?: PolicyCompileOptions): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PolicyExpression, SecurityRule } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The normalized `USING` / `WITH CHECK` conditions for a single security rule,
|
|
4
|
+
* expressed in the engine-agnostic {@link PolicyExpression} model.
|
|
5
|
+
*
|
|
6
|
+
* A `null` clause means "this rule contributes no condition for that clause";
|
|
7
|
+
* consumers apply the default (Postgres denies with `false`).
|
|
8
|
+
*/
|
|
9
|
+
export interface RuleConditions {
|
|
10
|
+
usingExpr: PolicyExpression | null;
|
|
11
|
+
withCheckExpr: PolicyExpression | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Desugars a {@link SecurityRule} — its `access`/`ownerField`/`roles` shortcuts,
|
|
15
|
+
* structured `condition`/`check`, and raw `using`/`withCheck` — into a single
|
|
16
|
+
* normalized {@link PolicyExpression} pair.
|
|
17
|
+
*
|
|
18
|
+
* **This is the linchpin against drift:** both the Postgres DDL generators and
|
|
19
|
+
* the client-side evaluator consume this one function, so there is exactly one
|
|
20
|
+
* definition of what a rule means. In particular, application `roles` are folded
|
|
21
|
+
* into the expression here (AND'd with the base condition, matching how Postgres
|
|
22
|
+
* generates the clause) rather than being handled separately by each consumer.
|
|
23
|
+
*/
|
|
24
|
+
export declare function securityRuleToConditions(rule: SecurityRule): RuleConditions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PolicyExpression } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* A tiny, regex-based SQL "parser" for security rules.
|
|
4
|
+
*
|
|
5
|
+
* This is NOT a full SQL parser. It is designed to handle the subset of SQL
|
|
6
|
+
* commonly used in `USING` and `WITH CHECK` clauses, enough to drive the
|
|
7
|
+
* optimistic client-side UI decision.
|
|
8
|
+
*
|
|
9
|
+
* It handles:
|
|
10
|
+
* - `field = 'literal'`
|
|
11
|
+
* - `field != 'literal'`
|
|
12
|
+
* - `field = current_setting('app.user_id')`
|
|
13
|
+
* - `A AND B`
|
|
14
|
+
* - `true`
|
|
15
|
+
* - `IN (...)` (as optimistic true)
|
|
16
|
+
*
|
|
17
|
+
* For anything it doesn't understand, it returns a `raw` expression, which
|
|
18
|
+
* the evaluator treats as "unknown" (and usually optimistic true).
|
|
19
|
+
*/
|
|
20
|
+
export declare function sqlToPolicy(sql: string): PolicyExpression;
|
|
@@ -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/dist/util/storage.d.ts
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
import { ArrayProperty, EntityValues, StorageConfig, StringProperty, UploadedFileContext } from "@rebasepro/types";
|
|
1
|
+
import { ArrayProperty, EntityValues, StorageConfig, StorageSource, StorageSourceRegistry, StringProperty, UploadedFileContext } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the {@link StorageSource} to use for a property, given the key
|
|
4
|
+
* referenced by `StorageConfig.storageSource`.
|
|
5
|
+
*
|
|
6
|
+
* Resolution priority:
|
|
7
|
+
* 1. No `sourceKey` → the default source (backward compatible).
|
|
8
|
+
* 2. An explicit {@link StorageSourceRegistry} (e.g. `client.storageRegistry`).
|
|
9
|
+
* 3. A `sources` lookup map (e.g. the `StorageSourcesContext`).
|
|
10
|
+
* 4. Fall back to the default source.
|
|
11
|
+
*
|
|
12
|
+
* Shared by the upload hook, the markdown editor, and the read-only previews
|
|
13
|
+
* so the resolution logic lives in one place.
|
|
14
|
+
*
|
|
15
|
+
* @group Storage
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveStorageSource(params: {
|
|
18
|
+
/** Key from `StorageConfig.storageSource`. */
|
|
19
|
+
sourceKey?: string | null;
|
|
20
|
+
/** Built sources keyed by storage-source key (e.g. from context). */
|
|
21
|
+
sources?: Record<string, StorageSource>;
|
|
22
|
+
/** Optional explicit registry — takes precedence over `sources`. */
|
|
23
|
+
registry?: StorageSourceRegistry;
|
|
24
|
+
/** Default source, used when no key is set or the key cannot be resolved. */
|
|
25
|
+
defaultSource: StorageSource;
|
|
26
|
+
}): StorageSource;
|
|
2
27
|
interface ResolveFilenameStringParams<M extends Record<string, unknown>> {
|
|
3
28
|
input: string | ((context: UploadedFileContext) => (Promise<string> | string));
|
|
4
29
|
storage: StorageConfig;
|
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"
|
|
@@ -29,14 +29,6 @@
|
|
|
29
29
|
"headless cms",
|
|
30
30
|
"content manager"
|
|
31
31
|
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"watch": "vite build --watch",
|
|
34
|
-
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
35
|
-
"test:lint": "eslint \"src/**\" --quiet",
|
|
36
|
-
"test": "jest --passWithNoTests",
|
|
37
|
-
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f",
|
|
38
|
-
"generateIcons": "ts-node --esm src/icons/generateIcons.ts"
|
|
39
|
-
},
|
|
40
32
|
"exports": {
|
|
41
33
|
".": {
|
|
42
34
|
"types": "./dist/index.d.ts",
|
|
@@ -47,10 +39,10 @@
|
|
|
47
39
|
"./package.json": "./package.json"
|
|
48
40
|
},
|
|
49
41
|
"dependencies": {
|
|
50
|
-
"@rebasepro/types": "workspace:*",
|
|
51
|
-
"@rebasepro/utils": "workspace:*",
|
|
52
42
|
"fast-equals": "6.0.0",
|
|
53
|
-
"json-logic-js": "^2.0.5"
|
|
43
|
+
"json-logic-js": "^2.0.5",
|
|
44
|
+
"@rebasepro/types": "0.9.0",
|
|
45
|
+
"@rebasepro/utils": "0.9.0"
|
|
54
46
|
},
|
|
55
47
|
"devDependencies": {
|
|
56
48
|
"@jest/globals": "^30.4.1",
|
|
@@ -105,5 +97,13 @@
|
|
|
105
97
|
"^@rebasepro/types$": "<rootDir>/../types/src/index.ts",
|
|
106
98
|
"^@rebasepro/utils$": "<rootDir>/../utils/src/index.ts"
|
|
107
99
|
}
|
|
100
|
+
},
|
|
101
|
+
"scripts": {
|
|
102
|
+
"watch": "vite build --watch",
|
|
103
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
104
|
+
"test:lint": "eslint \"src/**\" --quiet",
|
|
105
|
+
"test": "jest --passWithNoTests",
|
|
106
|
+
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f",
|
|
107
|
+
"generateIcons": "ts-node --esm src/icons/generateIcons.ts"
|
|
108
108
|
}
|
|
109
|
-
}
|
|
109
|
+
}
|