@stoker-platform/utils 0.5.77 → 0.5.79

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.
@@ -3,7 +3,7 @@ export declare const collectionAuthAccess: (permissions: CollectionPermissions)
3
3
  export declare const collectionAccess: (operation: "Read" | "Create" | "Update" | "Delete", permissions: CollectionPermissions) => boolean | undefined;
4
4
  export declare const collectionSomeWriteAccess: (permissions: CollectionPermissions) => boolean | undefined;
5
5
  export declare const collectionAllWriteAccess: (permissions: CollectionPermissions) => boolean | undefined;
6
- export declare const privateFieldAccess: (field: CollectionField, permissions?: StokerPermissions) => boolean | undefined;
7
- export declare const restrictCreateAccess: (field: CollectionField, permissions?: StokerPermissions) => boolean;
8
- export declare const restrictUpdateAccess: (field: CollectionField, permissions?: StokerPermissions) => boolean;
9
- export declare const canUpdateField: (collection: CollectionSchema, field: CollectionField, permissions: StokerPermissions) => boolean | undefined;
6
+ export declare const privateFieldAccess: (field: CollectionField, permissions?: StokerPermissions, collection?: CollectionSchema, claims?: Record<string, unknown>) => boolean | undefined;
7
+ export declare const restrictCreateAccess: (field: CollectionField, permissions?: StokerPermissions, collectionName?: string, claims?: Record<string, unknown>) => boolean;
8
+ export declare const restrictUpdateAccess: (field: CollectionField, permissions?: StokerPermissions, collectionName?: string, claims?: Record<string, unknown>) => boolean;
9
+ export declare const canUpdateField: (collection: CollectionSchema, field: CollectionField, permissions: StokerPermissions, claims: Record<string, unknown>) => boolean | undefined;
@@ -1,3 +1,4 @@
1
+ import { evaluateFieldAccessCondition, fieldAccessGroupAccess, isFieldAccessGroupReference } from "./fieldAccess.js";
1
2
  export const collectionAuthAccess = (permissions) => {
2
3
  return !!permissions.auth;
3
4
  };
@@ -19,44 +20,53 @@ export const collectionAllWriteAccess = (permissions) => {
19
20
  }
20
21
  return;
21
22
  };
22
- export const privateFieldAccess = (field, permissions) => {
23
+ export const privateFieldAccess = (field, permissions, collection, claims) => {
23
24
  if (!permissions)
24
25
  return true;
25
26
  if (!permissions.Role)
26
27
  return false;
28
+ if (isFieldAccessGroupReference(field.access)) {
29
+ if (!collection || !claims)
30
+ return false;
31
+ return fieldAccessGroupAccess(field, collection, permissions, claims);
32
+ }
27
33
  return field.access?.includes(permissions.Role);
28
34
  };
29
- export const restrictCreateAccess = (field, permissions) => {
30
- if (!permissions)
31
- return true;
32
- if (!permissions.Role)
33
- return false;
34
- if (field.restrictCreate === true)
35
+ const restrictWriteAccess = (restriction, permissions, collectionName, claims) => {
36
+ if (restriction === true)
35
37
  return false;
36
- else if (typeof field.restrictCreate === "object") {
37
- return field.restrictCreate?.includes(permissions.Role);
38
+ if (Array.isArray(restriction)) {
39
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
40
+ return restriction.includes(permissions.Role);
41
+ }
42
+ if (typeof restriction === "object" && restriction !== null) {
43
+ if (!collectionName || !claims)
44
+ return false;
45
+ return evaluateFieldAccessCondition(restriction, collectionName, permissions, claims);
38
46
  }
39
47
  return true;
40
48
  };
41
- export const restrictUpdateAccess = (field, permissions) => {
49
+ export const restrictCreateAccess = (field, permissions, collectionName, claims) => {
42
50
  if (!permissions)
43
51
  return true;
44
52
  if (!permissions.Role)
45
53
  return false;
46
- if (field.restrictUpdate === true)
54
+ return restrictWriteAccess(field.restrictCreate, permissions, collectionName, claims);
55
+ };
56
+ export const restrictUpdateAccess = (field, permissions, collectionName, claims) => {
57
+ if (!permissions)
58
+ return true;
59
+ if (!permissions.Role)
47
60
  return false;
48
- else if (typeof field.restrictUpdate === "object") {
49
- return field.restrictUpdate?.includes(permissions.Role);
50
- }
51
- return true;
61
+ return restrictWriteAccess(field.restrictUpdate, permissions, collectionName, claims);
52
62
  };
53
- export const canUpdateField = (collection, field, permissions) => {
63
+ export const canUpdateField = (collection, field, permissions, claims) => {
54
64
  const { labels } = collection;
55
65
  return (permissions.collections &&
56
66
  // eslint-disable-next-line security/detect-object-injection
57
67
  collectionAccess("Update", permissions.collections[labels.collection]) &&
58
- (!field.access || privateFieldAccess(field, permissions)) &&
59
- restrictUpdateAccess(field, permissions) &&
68
+ (!field.access || privateFieldAccess(field, permissions, collection, claims)) &&
69
+ restrictUpdateAccess(field, permissions, labels.collection, claims) &&
60
70
  !(collection.auth &&
61
71
  !permissions.collections?.[labels.collection].auth &&
62
72
  ["Enabled", "Role", "Name", "Email", "Photo_URL"].includes(field.name)));
@@ -1,3 +1,3 @@
1
1
  import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
2
2
  export declare const documentAccess: (operation: "Read" | "Create" | "Update" | "Delete", collectionSchema: CollectionSchema, schema: CollectionsSchema, userId: string, permissions: StokerPermissions, record: StokerRecord) => boolean;
3
- export declare const dependencyAccess: (collectionSchema: CollectionSchema, schema: CollectionsSchema, userId: string, permissions: StokerPermissions, record: StokerRecord) => boolean;
3
+ export declare const dependencyAccess: (collectionSchema: CollectionSchema, schema: CollectionsSchema, userId: string, permissions: StokerPermissions, record: StokerRecord, claims: Record<string, unknown>) => boolean;
@@ -177,13 +177,13 @@ export const documentAccess = (operation, collectionSchema, schema, userId, perm
177
177
  granted = false;
178
178
  return granted;
179
179
  };
180
- export const dependencyAccess = (collectionSchema, schema, userId, permissions, record) => {
180
+ export const dependencyAccess = (collectionSchema, schema, userId, permissions, record, claims) => {
181
181
  let granted = true;
182
182
  if (!permissions.Role) {
183
183
  granted = false;
184
184
  return granted;
185
185
  }
186
- if (hasDependencyAccess(collectionSchema, schema, permissions).length === 0)
186
+ if (hasDependencyAccess(collectionSchema, schema, permissions, claims).length === 0)
187
187
  granted = false;
188
188
  if (!filterAccess("Read", collectionSchema, schema, userId, permissions, record, true))
189
189
  granted = false;
@@ -0,0 +1,8 @@
1
+ import { CollectionField, CollectionSchema, FieldAccessCondition, FieldAccessGroupReference, StokerPermissions, StokerRole } from "@stoker-platform/types";
2
+ export declare const isFieldAccessGroupReference: (access?: StokerRole[] | FieldAccessGroupReference) => access is FieldAccessGroupReference;
3
+ export declare const getFieldAccessRoles: (access?: StokerRole[] | FieldAccessGroupReference) => StokerRole[] | undefined;
4
+ export declare const fieldRoleProjectionAccess: (field: CollectionField, role: StokerRole) => boolean;
5
+ export declare const getFieldAccessGroupCondition: (field: CollectionField, collection: CollectionSchema) => FieldAccessCondition | undefined;
6
+ export declare const getFieldAccessGroupFields: (collection: CollectionSchema) => Record<string, CollectionField[]>;
7
+ export declare const evaluateFieldAccessCondition: (condition: FieldAccessCondition, collectionName: string, permissions?: StokerPermissions, claims?: Record<string, unknown>) => boolean;
8
+ export declare const fieldAccessGroupAccess: (field: CollectionField, collection: CollectionSchema, permissions: StokerPermissions, claims: Record<string, unknown>) => boolean;
@@ -0,0 +1,78 @@
1
+ export const isFieldAccessGroupReference = (access) => {
2
+ return !!access && !Array.isArray(access);
3
+ };
4
+ export const getFieldAccessRoles = (access) => {
5
+ return Array.isArray(access) ? access : undefined;
6
+ };
7
+ export const fieldRoleProjectionAccess = (field, role) => {
8
+ if (!field.access)
9
+ return true;
10
+ if (isFieldAccessGroupReference(field.access))
11
+ return false;
12
+ return field.access.includes(role);
13
+ };
14
+ export const getFieldAccessGroupCondition = (field, collection) => {
15
+ if (!isFieldAccessGroupReference(field.access))
16
+ return;
17
+ return collection.fieldAccessGroups?.[field.access.group];
18
+ };
19
+ export const getFieldAccessGroupFields = (collection) => {
20
+ const groups = {};
21
+ Object.keys(collection.fieldAccessGroups || {}).forEach((key) => {
22
+ // eslint-disable-next-line security/detect-object-injection
23
+ groups[key] = [];
24
+ });
25
+ collection.fields.forEach((field) => {
26
+ if (isFieldAccessGroupReference(field.access)) {
27
+ const { group } = field.access;
28
+ // eslint-disable-next-line security/detect-object-injection
29
+ if (groups[group])
30
+ groups[group].push(field);
31
+ }
32
+ });
33
+ return groups;
34
+ };
35
+ export const evaluateFieldAccessCondition = (condition, collectionName, permissions, claims) => {
36
+ if (!permissions)
37
+ return true;
38
+ if (permissions.Role && !condition.applicableRoles.includes(permissions.Role))
39
+ return false;
40
+ // eslint-disable-next-line security/detect-object-injection
41
+ const collectionPermissions = permissions.collections?.[collectionName];
42
+ const checks = [];
43
+ if (condition.collectionAuth !== undefined) {
44
+ checks.push(!!collectionPermissions?.auth === condition.collectionAuth);
45
+ }
46
+ if (condition.roles) {
47
+ checks.push(!!permissions.Role && condition.roles.includes(permissions.Role));
48
+ }
49
+ if (condition.claims) {
50
+ checks.push(Object.entries(condition.claims).every(([claim, expected]) => {
51
+ // eslint-disable-next-line security/detect-object-injection
52
+ let value = claims?.[claim];
53
+ if (value === undefined && claim === "role")
54
+ value = permissions.Role;
55
+ if (Array.isArray(expected))
56
+ return expected.some((item) => item === value);
57
+ return value === expected;
58
+ }));
59
+ }
60
+ if (condition.restrictions) {
61
+ const { recordOwner, recordUser, recordProperty, restrictEntities } = condition.restrictions;
62
+ checks.push((recordOwner === undefined || !!collectionPermissions?.recordOwner?.active === recordOwner) &&
63
+ (recordUser === undefined || !!collectionPermissions?.recordUser?.active === recordUser) &&
64
+ (recordProperty === undefined || !!collectionPermissions?.recordProperty?.active === recordProperty) &&
65
+ (restrictEntities === undefined || !!collectionPermissions?.restrictEntities === restrictEntities));
66
+ }
67
+ if (checks.length === 0)
68
+ return false;
69
+ if (condition.match === "all")
70
+ return checks.every(Boolean);
71
+ return checks.some(Boolean);
72
+ };
73
+ export const fieldAccessGroupAccess = (field, collection, permissions, claims) => {
74
+ const condition = getFieldAccessGroupCondition(field, collection);
75
+ if (!condition)
76
+ return false;
77
+ return evaluateFieldAccessCondition(condition, collection.labels.collection, permissions, claims);
78
+ };
@@ -1,2 +1,2 @@
1
1
  import { CollectionSchema, CollectionsSchema, StokerPermissions } from "@stoker-platform/types";
2
- export declare const getRelatedCollections: (collectionSchema: CollectionSchema, schema: CollectionsSchema, permissions?: StokerPermissions) => string[];
2
+ export declare const getRelatedCollections: (collectionSchema: CollectionSchema, schema: CollectionsSchema, permissions?: StokerPermissions, claims?: Record<string, unknown>) => string[];
@@ -1,11 +1,11 @@
1
1
  import { isRelationField } from "../schema/isRelationField.js";
2
2
  import { collectionAccess, privateFieldAccess } from "../access/collection.js";
3
3
  import { hasDependencyAccess } from "./hasDependencyAccess.js";
4
- export const getRelatedCollections = (collectionSchema, schema, permissions) => {
4
+ export const getRelatedCollections = (collectionSchema, schema, permissions, claims) => {
5
5
  const relatedCollections = [];
6
6
  for (const field of collectionSchema.fields) {
7
7
  if (isRelationField(field)) {
8
- if (field.access && (!permissions || !privateFieldAccess(field, permissions)))
8
+ if (field.access && (!permissions || !privateFieldAccess(field, permissions, collectionSchema, claims)))
9
9
  continue;
10
10
  const relatedCollection = schema.collections[field.collection];
11
11
  if (!relatedCollection)
@@ -15,7 +15,7 @@ export const getRelatedCollections = (collectionSchema, schema, permissions) =>
15
15
  continue;
16
16
  if (!permissions ||
17
17
  collectionAccess("Read", relatedCollectionPermissions) ||
18
- hasDependencyAccess(collectionSchema, schema, permissions)) {
18
+ hasDependencyAccess(collectionSchema, schema, permissions, claims ?? {})) {
19
19
  relatedCollections.push(field.collection);
20
20
  }
21
21
  }
@@ -1,2 +1,2 @@
1
1
  import { CollectionSchema, CollectionsSchema, DependencyField, StokerPermissions } from "@stoker-platform/types";
2
- export declare const hasDependencyAccess: (collection: CollectionSchema, schema: CollectionsSchema, permissions: StokerPermissions) => DependencyField[];
2
+ export declare const hasDependencyAccess: (collection: CollectionSchema, schema: CollectionsSchema, permissions: StokerPermissions, claims: Record<string, unknown>) => DependencyField[];
@@ -1,13 +1,13 @@
1
1
  import { privateFieldAccess } from "./collection.js";
2
2
  import { isRelationField } from "../schema/isRelationField.js";
3
- export const hasDependencyAccess = (collection, schema, permissions) => {
3
+ export const hasDependencyAccess = (collection, schema, permissions, claims) => {
4
4
  const collections = Object.values(schema.collections);
5
5
  const { labels } = collection;
6
6
  const hasDependencyAccess = [];
7
7
  for (const collectionSchema of collections) {
8
8
  const { fields: dependencyFields } = collectionSchema;
9
9
  for (const field of dependencyFields) {
10
- if (field.access && !privateFieldAccess(field, permissions))
10
+ if (field.access && !privateFieldAccess(field, permissions, collectionSchema, claims))
11
11
  continue;
12
12
  if (!permissions.Role)
13
13
  continue;
@@ -1,2 +1,2 @@
1
1
  import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
2
- export declare const addRecordAccessControl: (record: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, permissions?: StokerPermissions) => void;
2
+ export declare const addRecordAccessControl: (record: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, permissions?: StokerPermissions, claims?: Record<string, unknown>) => void;
@@ -1,7 +1,7 @@
1
1
  import { collectionAccess, collectionAuthAccess, privateFieldAccess, restrictCreateAccess } from "../collection.js";
2
2
  import { documentAccess } from "../document.js";
3
3
  import { permissionsWriteAccess } from "../permissions.js";
4
- export const addRecordAccessControl = (record, docId, collectionSchema, schema, currentUserId, currentUserPermissions, permissions) => {
4
+ export const addRecordAccessControl = (record, docId, collectionSchema, schema, currentUserId, currentUserPermissions, permissions, claims) => {
5
5
  const { labels, fields } = collectionSchema;
6
6
  // eslint-disable-next-line security/detect-object-injection
7
7
  const collectionPermissions = currentUserPermissions?.collections?.[labels.collection];
@@ -27,11 +27,11 @@ export const addRecordAccessControl = (record, docId, collectionSchema, schema,
27
27
  for (const field of fields) {
28
28
  const value = record[field.name];
29
29
  if (field.access) {
30
- if (!privateFieldAccess(field, currentUserPermissions) && value !== undefined) {
30
+ if (!privateFieldAccess(field, currentUserPermissions, collectionSchema, claims) && value !== undefined) {
31
31
  granted = false;
32
32
  }
33
33
  }
34
- if (value !== undefined && !restrictCreateAccess(field, currentUserPermissions))
34
+ if (value !== undefined && !restrictCreateAccess(field, currentUserPermissions, labels.collection, claims))
35
35
  granted = false;
36
36
  }
37
37
  if (!granted)
@@ -1,2 +1,2 @@
1
1
  import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
2
- export declare const updateRecordAccessControl: (partial: StokerRecord, originalRecord: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, userOperation?: string, permissions?: StokerPermissions, originalPermissions?: StokerPermissions | undefined) => void;
2
+ export declare const updateRecordAccessControl: (partial: StokerRecord, originalRecord: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, userOperation?: string, permissions?: StokerPermissions, originalPermissions?: StokerPermissions | undefined, claims?: Record<string, unknown>) => void;
@@ -2,7 +2,7 @@ import { collectionAccess, collectionAuthAccess, privateFieldAccess, restrictUpd
2
2
  import { documentAccess } from "../document.js";
3
3
  import { permissionsWriteAccess } from "../permissions.js";
4
4
  import { removeDeleteSentinels } from "../../operations/removeDeleteSentinels.js";
5
- export const updateRecordAccessControl = (partial, originalRecord, docId, collectionSchema, schema, currentUserId, currentUserPermissions, userOperation, permissions, originalPermissions) => {
5
+ export const updateRecordAccessControl = (partial, originalRecord, docId, collectionSchema, schema, currentUserId, currentUserPermissions, userOperation, permissions, originalPermissions, claims) => {
6
6
  const { labels, fields } = collectionSchema;
7
7
  // eslint-disable-next-line security/detect-object-injection
8
8
  const collectionPermissions = currentUserPermissions?.collections?.[labels.collection];
@@ -50,12 +50,12 @@ export const updateRecordAccessControl = (partial, originalRecord, docId, collec
50
50
  for (const field of fields) {
51
51
  const value = partial[field.name];
52
52
  if (field.access) {
53
- if (!privateFieldAccess(field, currentUserPermissions) && value !== undefined) {
53
+ if (!privateFieldAccess(field, currentUserPermissions, collectionSchema, claims) && value !== undefined) {
54
54
  errorDetails = `Authenticated user does not have access to field ${field.name}`;
55
55
  granted = false;
56
56
  }
57
57
  }
58
- if (value !== undefined && !restrictUpdateAccess(field, currentUserPermissions)) {
58
+ if (value !== undefined && !restrictUpdateAccess(field, currentUserPermissions, labels.collection, claims)) {
59
59
  errorDetails = `Authenticated user does not have Update access to field ${field.name}`;
60
60
  granted = false;
61
61
  }
package/lib/src/main.d.ts CHANGED
@@ -20,7 +20,8 @@ export { getCollection } from "./schema/getCollection.js";
20
20
  export { getDependencyFields } from "./schema/getDependencyFields.js";
21
21
  export { getField } from "./schema/getField.js";
22
22
  export { getFieldNames } from "./schema/getFieldNames.js";
23
- export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
23
+ export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getFieldAccessGroupIndexFields, getFieldAccessGroupRoles, getFieldAccessGroupKey, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
24
+ export { isFieldAccessGroupReference, getFieldAccessRoles, fieldRoleProjectionAccess, getFieldAccessGroupCondition, getFieldAccessGroupFields, evaluateFieldAccessCondition, fieldAccessGroupAccess, } from "./access/fieldAccess.js";
24
25
  export { getAccessFields } from "./schema/getAccessFields.js";
25
26
  export { getSystemFieldsSchema } from "./schema/getSystemFieldsSchema.js";
26
27
  export { isRelationField } from "./schema/isRelationField.js";
package/lib/src/main.js CHANGED
@@ -20,7 +20,8 @@ export { getCollection } from "./schema/getCollection.js";
20
20
  export { getDependencyFields } from "./schema/getDependencyFields.js";
21
21
  export { getField } from "./schema/getField.js";
22
22
  export { getFieldNames } from "./schema/getFieldNames.js";
23
- export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
23
+ export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getFieldAccessGroupIndexFields, getFieldAccessGroupRoles, getFieldAccessGroupKey, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
24
+ export { isFieldAccessGroupReference, getFieldAccessRoles, fieldRoleProjectionAccess, getFieldAccessGroupCondition, getFieldAccessGroupFields, evaluateFieldAccessCondition, fieldAccessGroupAccess, } from "./access/fieldAccess.js";
24
25
  export { getAccessFields } from "./schema/getAccessFields.js";
25
26
  export { getSystemFieldsSchema } from "./schema/getSystemFieldsSchema.js";
26
27
  export { isRelationField } from "./schema/isRelationField.js";
@@ -1,2 +1,2 @@
1
- import { CollectionSchema, CollectionCustomization, StokerRecord, StokerRole } from "@stoker-platform/types";
2
- export declare const addInitialValues: (data: StokerRecord, collectionSchema: CollectionSchema, customization: CollectionCustomization, role?: StokerRole) => Promise<void>;
1
+ import { CollectionSchema, CollectionCustomization, StokerPermissions, StokerRecord } from "@stoker-platform/types";
2
+ export declare const addInitialValues: (data: StokerRecord, collectionSchema: CollectionSchema, customization: CollectionCustomization, permissions?: StokerPermissions, claims?: Record<string, unknown>) => Promise<void>;
@@ -1,13 +1,14 @@
1
+ import { privateFieldAccess } from "../access/collection.js";
1
2
  import { tryPromise } from "../getConfigValue.js";
2
3
  import { getField } from "../schema/getField.js";
3
4
  import { isRelationField } from "../schema/isRelationField.js";
4
5
  import { getLowercaseFields } from "./getLowercaseFields.js";
5
- export const addInitialValues = async (data, collectionSchema, customization, role) => {
6
+ export const addInitialValues = async (data, collectionSchema, customization, permissions, claims) => {
6
7
  const { fields } = collectionSchema;
7
8
  for (const field of customization.fields) {
8
9
  const fieldSchema = getField(fields, field.name);
9
10
  if (field.custom?.initialValue !== undefined &&
10
- !(role && fieldSchema.access && !fieldSchema.access.includes(role))) {
11
+ (!fieldSchema.access || privateFieldAccess(fieldSchema, permissions, collectionSchema, claims || {}))) {
11
12
  data[field.name] = await tryPromise(field.custom.initialValue, [data]);
12
13
  const lowercaseFields = getLowercaseFields(collectionSchema, [fieldSchema]);
13
14
  if (lowercaseFields.size === 1) {
@@ -16,7 +17,7 @@ export const addInitialValues = async (data, collectionSchema, customization, ro
16
17
  }
17
18
  }
18
19
  for (const field of fields) {
19
- if (!(role && field.access && !field.access.includes(role))) {
20
+ if (!field.access || privateFieldAccess(field, permissions, collectionSchema, claims || {})) {
20
21
  if ("autoIncrement" in field && field.autoIncrement && !data[field.name]) {
21
22
  data[field.name] = "Pending";
22
23
  }
@@ -1,5 +1,6 @@
1
1
  import { isRelationField } from "../schema/isRelationField.js";
2
- import { getDependencyIndexFields, getRoleExcludedFields } from "../schema/getIndexFields.js";
2
+ import { getDependencyIndexFields, getFieldAccessGroupIndexFields, getFieldAccessGroupKey, getRoleExcludedFields, } from "../schema/getIndexFields.js";
3
+ import { getFieldAccessGroupFields } from "../access/fieldAccess.js";
3
4
  import { isDependencyField } from "../schema/isDependencyField.js";
4
5
  import { getFieldNames } from "../schema/getFieldNames.js";
5
6
  import { getField } from "../schema/getField.js";
@@ -65,6 +66,48 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
65
66
  }
66
67
  });
67
68
  const roleGroups = allRoleGroups[collectionSchema.labels.collection];
69
+ const fieldAccessGroups = getFieldAccessGroupFields(collectionSchema);
70
+ Object.entries(fieldAccessGroups).forEach(([groupKey, groupFields]) => {
71
+ if (groupFields.length === 0)
72
+ return;
73
+ for (const roleGroup of roleGroups) {
74
+ const overlayFieldsSchema = getFieldAccessGroupIndexFields(groupKey, collectionSchema, roleGroup);
75
+ if (overlayFieldsSchema.length === 0)
76
+ continue;
77
+ const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
78
+ const overlayRecord = {};
79
+ overlayFieldsSchema.forEach((overlayField) => {
80
+ const names = [
81
+ overlayField.name,
82
+ `${overlayField.name}_Array`,
83
+ `${overlayField.name}_Single`,
84
+ `${overlayField.name}_Lowercase`,
85
+ ];
86
+ names.forEach((name) => {
87
+ // eslint-disable-next-line security/detect-object-injection
88
+ if (record[name] !== undefined)
89
+ overlayRecord[name] = record[name];
90
+ });
91
+ });
92
+ if (operation === "create") {
93
+ overlayRecord.Collection_Path ||= path;
94
+ overlayRecord.Collection_Path_String = path.join("/");
95
+ batch.set(privateRef(overlayKey), overlayRecord);
96
+ if (batchSize)
97
+ batchSize.size++;
98
+ }
99
+ if (operation === "update" && Object.keys(overlayRecord).length > 0) {
100
+ batch.update(privateRef(overlayKey), overlayRecord);
101
+ if (batchSize)
102
+ batchSize.size++;
103
+ }
104
+ if (operation === "delete") {
105
+ batch.delete(privateRef(overlayKey));
106
+ if (batchSize)
107
+ batchSize.size++;
108
+ }
109
+ }
110
+ });
68
111
  for (const group of roleGroups) {
69
112
  const excludedFields = getRoleExcludedFields(group, collectionSchema);
70
113
  const recordToUpdate = { ...record };
@@ -110,6 +153,18 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
110
153
  batchSize++;
111
154
  }
112
155
  }
156
+ const fieldAccessGroups = getFieldAccessGroupFields(targetSchema);
157
+ for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
158
+ if (groupFields.length === 0)
159
+ continue;
160
+ for (const roleGroup of targetRoleGroups) {
161
+ const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, targetSchema, roleGroup);
162
+ if (overlayIndexFields.some((overlayField) => overlayField.name === targetField.name) &&
163
+ isRelationField(targetField)) {
164
+ batchSize++;
165
+ }
166
+ }
167
+ }
113
168
  return batchSize;
114
169
  };
115
170
  const deleteFields = (field, targetSchema, targetField, id, relationPath) => {
@@ -142,6 +197,19 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
142
197
  batch.update(twoWayPrivateRef(field, group.key, id), fieldUpdate);
143
198
  }
144
199
  }
200
+ const fieldAccessGroups = getFieldAccessGroupFields(targetSchema);
201
+ for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
202
+ if (groupFields.length === 0)
203
+ continue;
204
+ for (const roleGroup of targetRoleGroups) {
205
+ const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, targetSchema, roleGroup);
206
+ const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
207
+ if (overlayIndexFields.some((overlayField) => overlayField.name === targetField.name) &&
208
+ isRelationField(targetField)) {
209
+ batch.update(twoWayPrivateRef(field, overlayKey, id), fieldUpdate);
210
+ }
211
+ }
212
+ }
145
213
  };
146
214
  if (operation === "delete")
147
215
  return;
@@ -246,6 +314,28 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
246
314
  }
247
315
  }
248
316
  }
317
+ const fieldAccessGroups = getFieldAccessGroupFields(targetSchema);
318
+ for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
319
+ if (groupFields.length === 0)
320
+ continue;
321
+ for (const roleGroup of targetRoleGroups) {
322
+ const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, targetSchema, roleGroup);
323
+ const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
324
+ if (overlayIndexFields.some((overlayField) => overlayField.name === targetField.name)) {
325
+ const overlayFieldUpdate = { ...fieldUpdate };
326
+ Object.keys(systemFields).forEach((systemField) => {
327
+ if (overlayIndexFields.some((overlayField) => overlayField.name === systemField)) {
328
+ // eslint-disable-next-line security/detect-object-injection
329
+ overlayFieldUpdate[systemField] = systemFields[systemField];
330
+ }
331
+ });
332
+ if (Object.keys(overlayFieldUpdate).length > 0) {
333
+ batch.update(twoWayPrivateRef(field, overlayKey, id), overlayFieldUpdate);
334
+ batchSize.size++;
335
+ }
336
+ }
337
+ }
338
+ }
249
339
  }
250
340
  }
251
341
  }
@@ -2,6 +2,9 @@ import type { CollectionField, CollectionSchema, CollectionsSchema, StokerPermis
2
2
  export declare const getRoleFields: (collection: CollectionSchema, role: StokerRole) => CollectionField[];
3
3
  export declare const getDependencyAccessFields: (field: CollectionField, collection: CollectionSchema, schema: CollectionsSchema) => CollectionField[];
4
4
  export declare const getDependencyIndexFields: (field: CollectionField, collection: CollectionSchema, schema: CollectionsSchema) => CollectionField[];
5
+ export declare const getFieldAccessGroupRoles: (groupKey: string, collection: CollectionSchema, roleGroup: RoleGroup) => string[];
6
+ export declare const getFieldAccessGroupKey: (groupKey: string, roleGroupKey: string) => string;
7
+ export declare const getFieldAccessGroupIndexFields: (groupKey: string, collection: CollectionSchema, roleGroup: RoleGroup) => CollectionField[];
5
8
  export declare const getRoleGroups: (collection: CollectionSchema, schema: CollectionsSchema) => Set<RoleGroup>;
6
9
  export declare const getRoleGroup: (role: StokerRole, collection: CollectionSchema, schema: CollectionsSchema) => RoleGroup | undefined;
7
10
  export declare const getRoleExcludedFields: (roleGroup: RoleGroup, collection: CollectionSchema) => CollectionField[];