@rebasepro/common 0.10.0 → 0.10.1-canary.0a881d4

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.
@@ -1,11 +1,3 @@
1
- import { DefaultSelectedViewBuilder, DefaultSelectedViewParams, CollectionConfig, Properties } from "@rebasepro/types";
1
+ import { CollectionConfig, Properties } from "@rebasepro/types";
2
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: CollectionConfig): "manual_apply" | "auto_apply";
5
- /**
6
- * Returns the primary keys for a 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
3
  export declare function getPrimaryKeys<M extends Record<string, unknown>>(collection: CollectionConfig<M>): Extract<keyof M, string>[];
@@ -1,4 +1,4 @@
1
- import { AuthController, ConditionContext, JsonLogicRule, Property } from "@rebasepro/types";
1
+ import { AuthState, ConditionContext, JsonLogicRule } from "@rebasepro/types";
2
2
  /**
3
3
  * Register custom JSON Logic operations for Rebase.
4
4
  * Call this once at app initialization.
@@ -18,9 +18,8 @@ export declare function buildConditionContext(params: {
18
18
  path: string;
19
19
  entityId?: string;
20
20
  index?: number;
21
- authController: AuthController;
21
+ authController: AuthState;
22
22
  }): ConditionContext;
23
23
  /**
24
24
  * Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
25
25
  */
26
- export declare function applyPropertyConditions(property: Property, context: ConditionContext): Property;
@@ -1,6 +1,4 @@
1
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
2
  export declare function isPropertyBuilder(property?: Property): boolean;
5
3
  export declare function getDefaultValuesFor<M extends Record<string, unknown>>(properties: Properties): Partial<EntityValues<M>>;
6
4
  export declare function getDefaultValueFor(property?: Property): unknown;
@@ -7,9 +7,6 @@ export * from "./paths";
7
7
  export * from "./resolutions";
8
8
  export * from "./policy";
9
9
  export * from "./permissions";
10
- export * from "./references";
11
- export * from "./navigation_from_path";
12
- export * from "./parent_references_from_path";
13
10
  export * from "./builders";
14
11
  export * from "./storage";
15
12
  export * from "./callbacks";
@@ -17,5 +14,3 @@ export * from "./relations";
17
14
  export * from "./auth-default-policies";
18
15
  export * from "./junction-policies";
19
16
  export * from "./conditions";
20
- export * from "./navigation_utils";
21
- export * from "./filter-operator-resolution";
@@ -1,12 +1,15 @@
1
- import { Entity, CollectionConfig, SecurityOperation, User } from "@rebasepro/types";
1
+ import { AuthState, 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
5
5
  * a full AuthController just to check permissions.
6
+ *
7
+ * An alias, not a second definition: {@link AuthState} in `@rebasepro/types` is
8
+ * the same shape and is what `dynamicProps` and the JSON-Logic condition context
9
+ * now take, so declaring it twice would be the `WhereFilterOp` mistake again —
10
+ * two copies that agree only by luck.
6
11
  */
7
- export interface AuthContext<USER extends User = User> {
8
- user: USER | null;
9
- }
12
+ export type AuthContext<USER extends User = User> = AuthState<USER>;
10
13
  /**
11
14
  * How to resolve a policy result that cannot be decided client-side (a raw-SQL
12
15
  * escape-hatch rule, or a row-column reference with no row in hand).
@@ -1,4 +1,4 @@
1
- import { ArrayProperty, AuthController, CollectionConfig, EnumValueConfig, EnumValues, NumberProperty, Properties, Property, Relation, RelationProperty, StringProperty } from "@rebasepro/types";
1
+ import { ArrayProperty, AuthState, 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;
@@ -16,7 +16,7 @@ export type ResolvePropertyProps<M extends Record<string, unknown> = Record<stri
16
16
  index?: number;
17
17
  propertyConfigs?: Record<string, PropertyConfig>;
18
18
  ignoreMissingFields?: boolean;
19
- authController: AuthController;
19
+ authController: AuthState;
20
20
  };
21
21
  export declare function resolveProperty<M extends Record<string, unknown> = Record<string, unknown>>(props: ResolvePropertyProps<M>): Property | null;
22
22
  export declare function resolveRelationProperty(property: RelationProperty, relations: Relation[], propertyKey?: string): RelationProperty;
@@ -40,7 +40,7 @@ export declare function resolveProperties<M extends Record<string, unknown>>({ p
40
40
  index?: number;
41
41
  propertyConfigs?: Record<string, PropertyConfig>;
42
42
  ignoreMissingFields?: boolean;
43
- authController: AuthController;
43
+ authController: AuthState;
44
44
  }): Properties;
45
45
  export declare function resolveArrayProperties<M>({ propertyKey, property, ignoreMissingFields, ...props }: {
46
46
  propertyKey?: string;
@@ -52,7 +52,7 @@ export declare function resolveArrayProperties<M>({ propertyKey, property, ignor
52
52
  index?: number;
53
53
  propertyConfigs?: Record<string, PropertyConfig>;
54
54
  ignoreMissingFields?: boolean;
55
- authController: AuthController;
55
+ authController: AuthState;
56
56
  }): Property[];
57
57
  export declare function getArrayResolvedProperties({ propertyKey, propertyValue, property, ...props }: {
58
58
  propertyValue: unknown;
@@ -65,7 +65,7 @@ export declare function getArrayResolvedProperties({ propertyKey, propertyValue,
65
65
  entityId?: string | number;
66
66
  index?: number;
67
67
  propertyConfigs?: Record<string, PropertyConfig>;
68
- authController: AuthController;
68
+ authController: AuthState;
69
69
  }): Property[];
70
70
  export declare function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined;
71
71
  export declare function getSubcollections<M extends Record<string, unknown> = Record<string, unknown>>(collection: CollectionConfig<M>): CollectionConfig<Record<string, unknown>>[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/common",
3
3
  "type": "module",
4
- "version": "0.10.0",
4
+ "version": "0.10.1-canary.0a881d4",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -40,8 +40,8 @@
40
40
  "dependencies": {
41
41
  "fast-equals": "6.0.0",
42
42
  "json-logic-js": "^2.0.5",
43
- "@rebasepro/types": "0.10.0",
44
- "@rebasepro/utils": "0.10.0"
43
+ "@rebasepro/types": "0.10.1-canary.0a881d4",
44
+ "@rebasepro/utils": "0.10.1-canary.0a881d4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@jest/globals": "^30.4.1",
@@ -50,10 +50,7 @@
50
50
  "@types/jest": "^30.0.0",
51
51
  "@types/node": "^25.9.3",
52
52
  "@types/object-hash": "^3.0.6",
53
- "@types/react": "^19.2.17",
54
- "@types/react-dom": "^19.2.3",
55
53
  "@types/react-measure": "^2.0.12",
56
- "@vitejs/plugin-react": "^6.0.2",
57
54
  "babel-plugin-react-compiler": "beta",
58
55
  "cross-env": "^10.1.0",
59
56
  "jest": "^30.4.2",
@@ -92,6 +89,7 @@
92
89
  "testEnvironment": "node",
93
90
  "moduleNameMapper": {
94
91
  "\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js",
92
+ "^@rebasepro/admin-types$": "<rootDir>/../admin-types/src/index.ts",
95
93
  "^@rebasepro/client$": "<rootDir>/../client/src/index.ts",
96
94
  "^@rebasepro/types$": "<rootDir>/../types/src/index.ts",
97
95
  "^@rebasepro/utils$": "<rootDir>/../utils/src/index.ts"
@@ -6,6 +6,12 @@ import { defineCollection } from "../util/builders";
6
6
  * Prepended to the developer's collections array by the admin and server.
7
7
  * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers
8
8
  * override by defining their own collection with `slug: "users"`.
9
+ *
10
+ * Schema only — no `admin` block. This package is on the backend's dependency path,
11
+ * where that field does not exist: `@rebasepro/admin-types` adds it by declaration
12
+ * merging, and a BaaS install never installs that. The scaffolded
13
+ * `config/collections/users.ts` carries the presentation for projects that want this
14
+ * collection in their panel, which is also where it is editable.
9
15
  */
10
16
  export const defaultUsersCollection = defineCollection({
11
17
  name: "Users",
@@ -14,23 +20,17 @@ export const defaultUsersCollection = defineCollection({
14
20
  auth: true,
15
21
  table: "users",
16
22
  schema: "rebase",
17
- icon: "Users",
18
- group: "Settings",
19
- openEntityMode: "dialog",
20
- disableDefaultActions: ["copy"],
21
23
  securityRules: [
22
24
  { operation: "select",
23
25
  roles: ["admin"] },
24
26
  { operations: ["insert", "update", "delete"],
25
27
  roles: ["admin"] }
26
28
  ],
27
- sort: ["createdAt", "desc"],
28
29
  properties: {
29
30
  id: {
30
31
  name: "ID",
31
32
  type: "string",
32
- isId: "uuid",
33
- ui: { readOnly: true }
33
+ isId: "uuid"
34
34
  },
35
35
  email: {
36
36
  name: "Email",
@@ -47,8 +47,7 @@ unique: true }
47
47
  photoURL: {
48
48
  name: "Photo URL",
49
49
  type: "string",
50
- columnName: "photo_url",
51
- ui: { url: "image" }
50
+ columnName: "photo_url"
52
51
  },
53
52
  roles: {
54
53
  name: "Roles",
@@ -68,58 +67,43 @@ unique: true }
68
67
  name: "Password Hash",
69
68
  type: "string",
70
69
  columnName: "password_hash",
71
- excludeFromApi: true,
72
- ui: { hideFromCollection: true,
73
- disabled: { hidden: true } }
70
+ excludeFromApi: true
74
71
  },
75
72
  emailVerified: {
76
73
  name: "Email Verified",
77
74
  type: "boolean",
78
75
  columnName: "email_verified",
79
- defaultValue: false,
80
- ui: { hideFromCollection: true,
81
- disabled: { hidden: true } }
76
+ defaultValue: false
82
77
  },
83
78
  emailVerificationToken: {
84
79
  name: "Email Verification Token",
85
80
  type: "string",
86
81
  columnName: "email_verification_token",
87
- excludeFromApi: true,
88
- ui: { hideFromCollection: true,
89
- disabled: { hidden: true } }
82
+ excludeFromApi: true
90
83
  },
91
84
  emailVerificationSentAt: {
92
85
  name: "Email Verification Sent At",
93
86
  type: "date",
94
- columnName: "email_verification_sent_at",
95
- ui: { hideFromCollection: true,
96
- disabled: { hidden: true } }
87
+ columnName: "email_verification_sent_at"
97
88
  },
98
89
  metadata: {
99
90
  name: "Metadata",
100
91
  type: "map",
101
92
  keyValue: true,
102
93
  properties: {},
103
- defaultValue: {},
104
- ui: { hideFromCollection: true,
105
- disabled: { hidden: true } }
94
+ defaultValue: {}
106
95
  },
107
96
  createdAt: {
108
97
  name: "Created At",
109
98
  type: "date",
110
99
  columnName: "created_at",
111
- autoValue: "on_create",
112
- ui: { readOnly: true }
100
+ autoValue: "on_create"
113
101
  },
114
102
  updatedAt: {
115
103
  name: "Updated At",
116
104
  type: "date",
117
105
  columnName: "updated_at",
118
- autoValue: "on_update",
119
- ui: { hideFromCollection: true,
120
- disabled: { hidden: true } }
106
+ autoValue: "on_update"
121
107
  }
122
- },
123
- listProperties: ["displayName", "email", "roles", "createdAt"],
124
- propertiesOrder: ["id", "email", "displayName", "roles", "createdAt"]
108
+ }
125
109
  });
@@ -1,6 +1,4 @@
1
1
  import {
2
- DefaultSelectedViewBuilder,
3
- DefaultSelectedViewParams,
4
2
  CollectionConfig,
5
3
  Properties,
6
4
  Property
@@ -85,34 +83,8 @@ export function sortProperties<M extends Record<string, unknown>>(properties: Pr
85
83
  }
86
84
  }
87
85
 
88
- export function resolveDefaultSelectedView(
89
- defaultSelectedView: string | DefaultSelectedViewBuilder | undefined,
90
- params: DefaultSelectedViewParams
91
- ) {
92
- if (!defaultSelectedView) {
93
- return undefined;
94
- } else if (typeof defaultSelectedView === "string") {
95
- return defaultSelectedView;
96
- } else {
97
- return defaultSelectedView(params);
98
- }
99
- }
100
-
101
86
 
102
- export function getLocalChangesBackup(collection: CollectionConfig) {
103
- if (!collection.localChangesBackup) {
104
- return "manual_apply";
105
- }
106
-
107
- return collection.localChangesBackup;
108
- }
109
87
 
110
- /**
111
- * Returns the primary keys for a entity collection by inspecting the properties
112
- * and finding any properties with `isId`.
113
- * Fallbacks to `["id"]` if no properties are marked as `isId: true`.
114
- * @param collection
115
- */
116
88
  export function getPrimaryKeys<M extends Record<string, unknown>>(collection: CollectionConfig<M>): Extract<keyof M, string>[] {
117
89
  const properties = collection.properties;
118
90
  if (!properties) {
@@ -1,7 +1,7 @@
1
1
  import jsonLogic from "json-logic-js";
2
2
  import {
3
3
  ArrayProperty,
4
- AuthController,
4
+ AuthState,
5
5
  ConditionContext,
6
6
  EnumValueConfig,
7
7
  JsonLogicRule,
@@ -123,7 +123,7 @@ export function buildConditionContext(params: {
123
123
  path: string;
124
124
  entityId?: string;
125
125
  index?: number;
126
- authController: AuthController;
126
+ authController: AuthState;
127
127
  }): ConditionContext {
128
128
  const {
129
129
  propertyKey,
@@ -161,191 +161,3 @@ export function buildConditionContext(params: {
161
161
  /**
162
162
  * Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
163
163
  */
164
- export function applyPropertyConditions(
165
- property: Property,
166
- context: ConditionContext
167
- ): Property {
168
- const { conditions } = property;
169
- if (!conditions) return property;
170
-
171
- const result = { ...property };
172
-
173
- // ═══════════════════════════════════════════════════════════════════════
174
- // FIELD STATE CONDITIONS
175
- // ═══════════════════════════════════════════════════════════════════════
176
-
177
- // Evaluate disabled condition
178
- if (conditions.disabled) {
179
- const isDisabled = evaluateCondition(conditions.disabled, context);
180
- if (isDisabled) {
181
- result.ui = result.ui || {};
182
- result.ui.disabled = {
183
- clearOnDisabled: conditions.clearOnDisabled ?? false,
184
- disabledMessage: conditions.disabledMessage,
185
- hidden: false
186
- };
187
- }
188
- }
189
-
190
- // Evaluate hidden condition
191
- if (conditions.hidden) {
192
- const isHidden = evaluateCondition(conditions.hidden, context);
193
- if (isHidden) {
194
- result.ui = result.ui || {};
195
- result.ui.disabled = {
196
- ...(typeof result.ui?.disabled === "object" ? result.ui.disabled : {}),
197
- hidden: true,
198
- clearOnDisabled: conditions.clearOnDisabled ?? false
199
- };
200
- }
201
- }
202
-
203
- // Evaluate readOnly condition
204
- if (conditions.readOnly) {
205
- const isReadOnly = evaluateCondition(conditions.readOnly, context);
206
- if (isReadOnly) {
207
- result.ui = result.ui || {};
208
- result.ui.readOnly = true;
209
- }
210
- }
211
-
212
- // ═══════════════════════════════════════════════════════════════════════
213
- // VALIDATION CONDITIONS
214
- // ═══════════════════════════════════════════════════════════════════════
215
-
216
- // Evaluate required condition
217
- if (conditions.required !== undefined) {
218
- const isRequired = evaluateCondition(conditions.required, context) as boolean;
219
- result.validation = {
220
- ...result.validation,
221
- required: isRequired as boolean | undefined,
222
- requiredMessage: conditions.requiredMessage
223
- };
224
- }
225
-
226
- // ═══════════════════════════════════════════════════════════════════════
227
- // VALUE CONDITIONS
228
- // ═══════════════════════════════════════════════════════════════════════
229
-
230
- // Apply default value for new entities
231
- if (context.isNew && conditions.defaultValue !== undefined) {
232
- result.defaultValue = evaluateCondition(conditions.defaultValue, context) as Property["defaultValue"];
233
- }
234
-
235
- // ═══════════════════════════════════════════════════════════════════════
236
- // ENUM CONDITIONS
237
- // ═══════════════════════════════════════════════════════════════════════
238
-
239
- if ("enum" in result && result.enum && (conditions.enumConditions || conditions.allowedEnumValues || conditions.excludedEnumValues)) {
240
- (result as Record<string, unknown>).enum = applyEnumConditions(
241
- result.enum as EnumValueConfig[],
242
- conditions,
243
- context
244
- );
245
- }
246
-
247
- // ═══════════════════════════════════════════════════════════════════════
248
- // REFERENCE CONDITIONS
249
- // ═══════════════════════════════════════════════════════════════════════
250
-
251
- if (result.type === "reference") {
252
- if (conditions.referencePath) {
253
- (result as ReferenceProperty).path = evaluateCondition(conditions.referencePath, context) as string;
254
- }
255
- if (conditions.referenceFilter) {
256
- (result as ReferenceProperty).fixedFilter = evaluateCondition(conditions.referenceFilter, context) as ReferenceProperty["fixedFilter"];
257
- }
258
- }
259
-
260
- // ═══════════════════════════════════════════════════════════════════════
261
- // ARRAY CONDITIONS
262
- // ═══════════════════════════════════════════════════════════════════════
263
-
264
- if (result.type === "array") {
265
- if (conditions.canAddElements !== undefined) {
266
- (result as ArrayProperty).canAddElements = evaluateCondition(conditions.canAddElements, context) as boolean;
267
- }
268
- if (conditions.sortable !== undefined) {
269
- (result as ArrayProperty).sortable = evaluateCondition(conditions.sortable, context) as boolean;
270
- }
271
- }
272
-
273
- return result;
274
- }
275
-
276
- /**
277
- * Convert an object with numeric keys back to an array.
278
- * Firestore stores arrays as {"0": "a", "1": "b"} to avoid nested arrays.
279
- */
280
- function objectToArray(obj: unknown): string[] {
281
- if (Array.isArray(obj)) return obj.map(String);
282
- if (obj && typeof obj === "object") {
283
- const keys = Object.keys(obj);
284
- if (keys.length > 0 && keys.every(k => !isNaN(Number(k)))) {
285
- return keys
286
- .sort((a, b) => Number(a) - Number(b))
287
- .map(k => (obj as Record<string, unknown>)[k])
288
- .filter((v): v is string => typeof v === "string" || typeof v === "number")
289
- .map(String);
290
- }
291
- }
292
- return [];
293
- }
294
-
295
- /**
296
- * Apply enum-specific conditions to filter and modify enum values.
297
- */
298
- function applyEnumConditions(
299
- enumValues: EnumValueConfig[],
300
- conditions: PropertyConditions,
301
- context: ConditionContext
302
- ): EnumValueConfig[] {
303
- let result = [...enumValues];
304
-
305
- // Apply allowedEnumValues filter
306
- if (conditions.allowedEnumValues) {
307
- const allowed = evaluateCondition(conditions.allowedEnumValues, context);
308
- // Handle both array format and object-with-numeric-keys format (Firestore workaround)
309
- const allowedArray = objectToArray(allowed);
310
- if (allowedArray.length > 0) {
311
- result = result.filter(ev => allowedArray.includes(String(ev.id)));
312
- }
313
- }
314
-
315
- // Apply excludedEnumValues filter
316
- if (conditions.excludedEnumValues) {
317
- const excluded = evaluateCondition(conditions.excludedEnumValues, context);
318
- // Handle both array format and object-with-numeric-keys format
319
- const excludedArray = objectToArray(excluded);
320
- if (excludedArray.length > 0) {
321
- result = result.filter(ev => !excludedArray.includes(String(ev.id)));
322
- }
323
- }
324
-
325
- // Apply individual enum conditions
326
- if (conditions.enumConditions) {
327
- result = result
328
- .map(ev => {
329
- const evConditions = conditions.enumConditions?.[ev.id];
330
- if (!evConditions) return ev;
331
-
332
- // Check hidden condition first
333
- if (evConditions.hidden && evaluateCondition(evConditions.hidden, context)) {
334
- return null; // Will be filtered out
335
- }
336
-
337
- // Check disabled condition
338
- if (evConditions.disabled && evaluateCondition(evConditions.disabled, context)) {
339
- return {
340
- ...ev,
341
- disabled: true
342
- };
343
- }
344
-
345
- return ev;
346
- })
347
- .filter((ev): ev is EnumValueConfig => ev !== null);
348
- }
349
-
350
- return result;
351
- }
@@ -11,23 +11,6 @@ import {
11
11
  import { DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE } from "./common";
12
12
  import { mergeDeep } from "@rebasepro/utils";
13
13
 
14
- export function isReadOnly(property: Property): boolean {
15
- if (property.ui?.readOnly)
16
- return true;
17
- if (property.type === "date") {
18
- if (property.autoValue)
19
- return true;
20
- }
21
- if (property.type === "reference") {
22
- return !property.path && !("Field" in (property.ui || {}) && property.ui?.Field);
23
- }
24
- return false;
25
- }
26
-
27
- export function isHidden(property: Property): boolean {
28
- return typeof property.ui?.disabled === "object" && Boolean(property.ui?.disabled.hidden);
29
- }
30
-
31
14
  export function isPropertyBuilder(property?: Property) {
32
15
  return typeof property?.dynamicProps === "function";
33
16
  }
package/src/util/index.ts CHANGED
@@ -7,9 +7,6 @@ export * from "./paths";
7
7
  export * from "./resolutions";
8
8
  export * from "./policy";
9
9
  export * from "./permissions";
10
- export * from "./references";
11
- export * from "./navigation_from_path";
12
- export * from "./parent_references_from_path";
13
10
  export * from "./builders";
14
11
  export * from "./storage";
15
12
  export * from "./callbacks";
@@ -17,5 +14,3 @@ export * from "./relations";
17
14
  export * from "./auth-default-policies";
18
15
  export * from "./junction-policies";
19
16
  export * from "./conditions";
20
- export * from "./navigation_utils";
21
- export * from "./filter-operator-resolution";
@@ -1,5 +1,5 @@
1
1
  import { canCreateEntity, canEditEntity, canDeleteEntity, canReadCollection } from "./permissions";
2
- import { CollectionConfig, AuthController, Entity, User, SecurityRule } from "@rebasepro/types";
2
+ import { AuthState, CollectionConfig, Entity, User, SecurityRule } from "@rebasepro/types";
3
3
 
4
4
  describe("Permissions Evaluator", () => {
5
5
 
@@ -25,23 +25,18 @@ describe("Permissions Evaluator", () => {
25
25
  roles: ["admin"]
26
26
  };
27
27
 
28
- const mockAuthController: AuthController<User> = {
29
- user: mockUser,
30
- initialLoading: false,
31
- authLoading: false,
32
- loginSkipped: false,
33
- signOut: async () => { },
34
- getAuthToken: async () => "token",
35
- setExtra: () => { },
36
- extra: undefined
28
+ // Just the user now. Faking `signOut`, `getAuthToken`, `authLoading` and the
29
+ // rest of a frontend controller was never anything these assertions read.
30
+ const mockAuthController: AuthState<User> = {
31
+ user: mockUser
37
32
  };
38
33
 
39
- const adminAuthController: AuthController<User> = {
34
+ const adminAuthController: AuthState<User> = {
40
35
  ...mockAuthController,
41
36
  user: adminUser
42
37
  };
43
38
 
44
- const unauthenticatedController: AuthController<User> = {
39
+ const unauthenticatedController: AuthState<User> = {
45
40
  ...mockAuthController,
46
41
  user: null
47
42
  };
@@ -709,7 +704,7 @@ isAnonymous: false,
709
704
  photoURL: null,
710
705
  roles: ["editor"]
711
706
  };
712
- const editorAuth: AuthController<User> = { ...mockAuthController,
707
+ const editorAuth: AuthState<User> = { ...mockAuthController,
713
708
  user: editorUser };
714
709
 
715
710
  const collection = createMockCollection([
@@ -820,7 +815,7 @@ using: "status = 'draft'" }
820
815
  test("58. Missing authController ('blankAuth') handled gracefully", () => {
821
816
  const collection = createMockCollection([{ operation: "insert",
822
817
  roles: ["admin"] }]);
823
- const blankAuth = { user: null } as unknown as AuthController<User>;
818
+ const blankAuth = { user: null } as unknown as AuthState<User>;
824
819
  expect(canCreateEntity(collection, blankAuth, "test", null)).toBe(false);
825
820
  });
826
821
 
@@ -1,4 +1,4 @@
1
- import { Entity, CollectionConfig, getDataSourceCapabilities, SecurityOperation, SecurityRule, User } from "@rebasepro/types";
1
+ import { AuthState, Entity, CollectionConfig, getDataSourceCapabilities, SecurityOperation, SecurityRule, User } from "@rebasepro/types";
2
2
  import { securityRuleToConditions } from "./policy/securityRuleToConditions";
3
3
  import { evaluatePolicy, PolicyEvalContext, TriState } from "./policy/evaluatePolicy";
4
4
 
@@ -6,10 +6,13 @@ import { evaluatePolicy, PolicyEvalContext, TriState } from "./policy/evaluatePo
6
6
  * Minimal auth context for permission checking.
7
7
  * Only requires the user object — avoids forcing callers to construct
8
8
  * a full AuthController just to check permissions.
9
+ *
10
+ * An alias, not a second definition: {@link AuthState} in `@rebasepro/types` is
11
+ * the same shape and is what `dynamicProps` and the JSON-Logic condition context
12
+ * now take, so declaring it twice would be the `WhereFilterOp` mistake again —
13
+ * two copies that agree only by luck.
9
14
  */
10
- export interface AuthContext<USER extends User = User> {
11
- user: USER | null;
12
- }
15
+ export type AuthContext<USER extends User = User> = AuthState<USER>;
13
16
 
14
17
  /**
15
18
  * How to resolve a policy result that cannot be decided client-side (a raw-SQL