Skip to content

Commit 0d9ec91

Browse files
authored
perf: up to 5000% faster permissions calculation (#14631)
In large projects, calculating the `permissions` object is one of the slowest parts of Payload. This PR completely rewrites the permission calculation system to make it significantly faster and more reliable. The permissions object is calculated multiple times throughout Payload's lifecycle: for the entire config every time we load or navigate to any admin panel page, on every API endpoint call, and as part of query path validation when calling any Payload operation. This is done by `getAccessResults` without any document data, and in large configs can be one of the slowest operations, noticeably slowing down admin panel navigation. After this rewrite, **speed improvements in permissions calculation without data range from 5.3% (access-control test suite) to 74% (fields test suite - our largest config)**. The larger the config, the more noticeable these improvements become. These performance gains apply to both the Payload Admin Panel and API requests. --- The `permissions` object can also be calculated WITH document data, which triggers evaluation of `Where` conditions in collection/global-level access control and may fetch the document to pass to access control functions. This has been heavily optimized with **speed improvements for permissions calculation with data ranging between 75% and 5138%** (if I craft a collection config that excessively uses aspects this PR improves) in the benchmarks. This optimization affects: - Loading any document (collection/global edit view or drawer) - Saving a document - Loading the list view with query presets applied - Bulk upload initialization (runs twice) These improvements are most noticeable when navigating _to_ documents in the admin panel. ## What's Fixed In addition to performance improvements, the new function is now cleaner, easier to understand and works more reliably. I specifically wanna call out two issues that were fixed: **Field access control data bug**: Added a new e2e test that was previously failing - when saving a document, the data object passed to field-level update access control functions had the wrong shape (or in some cases did not exist at all). This caused fields to show incorrect `readOnly` states after save. The new implementation properly passes document data through all access control checks. **Where query validation**: The old implementation sometimes skipped validating `Where` queries for collections when `req.data` existed, potentially granting incorrect access. The new version always validates where queries correctly when `fetchData: true`. **Global Where queries:**: Where queries were _never_ executed for globals. Instead, [we were just checking if the global existed in general](https://github.com/payloadcms/payload/blob/main/packages/payload/src/utilities/getEntityPolicies.ts#L59). This PR ensures that `Where` queries returned from global access control are respected. ## What's Faster (and Why) **Where query caching:** When multiple operations return identical where queries (common pattern), we now cache the result. Instead of 3-4 separate DB calls, we make 1 call and reuse it. **Parallel execution:** All `Where` query evaluations and async access control functions (for both collections and fields) now execute concurrently with maximum parallelism, rather than sequentially. **Optimized DB operations**: When evaluating returned `Where` queries, we now use direct database `db.count()` queries instead of `payload.find()` operations. This is much faster (especially on Postgres). **Synchronous tree traversal**: The entire field permission tree is now built synchronously with all async work collected and executed in parallel at the end, rather than cascading await calls through each nesting level. This eliminates sequential bottlenecks in deeply nested field structures. ## Benchmarks ### Admin Panel - Fields test suite with access control added - 1000 blocks added to the blocks collection. This is not as excessive as you would expect: - most Payload apps do not run on an M3 Max. CPU/DB is often much, much slower - this is all local, with a local DB - a lot of projects accumulate a huge amount of blocks if you multiply blocks x block fields. They can definitely reach 1000 total blocks - each block is simple - only one text field per block. In real projects, blocks are usually a lot more complex **Before:** https://github.com/user-attachments/assets/37b55f02-6dbc-4005-9da6-d7cd4bfdc925 **After:** https://github.com/user-attachments/assets/8dd796dd-66ed-4d32-a688-27b4169577c6 Branch: https://github.com/payloadcms/payload/tree/fix/update-field-access-control-after-save-benchmarks ### Modified Access-Control Test Suite `cd test && pnpm payload run access-control/benchmark-permissions.ts` ```md 📊 Benchmark 1: getAccessResults (all collections + globals) ────────────────────────────────────────────────────────────────────── ┌─────────┬───────────────────┬─────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼───────────────────┼─────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (optimized)' │ '16.91' │ '59203.986' │ '±0.52%' │ │ 1 │ 'OLD (previous)' │ '16.07' │ '62323.953' │ '±0.57%' │ └─────────┴───────────────────┴─────────┴───────────────────┴──────────┘ ⚡ Speedup: +5.3% 🚀 📊 DB Calls per operation (across all collections + globals): NEW: 0.0 total (0.0 data, 0.0 where) OLD: 0.0 total (0.0 data, 0.0 where) 📊 Benchmark 2: docAccessOperation (with fetchData) ────────────────────────────────────────────────────────────────────── Collection: where-cache-same (same where queries) ┌─────────┬────────────────────┬───────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼────────────────────┼───────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (with cache)' │ '2272.81' │ '442.319' │ '±0.11%' │ │ 1 │ 'OLD (no cache)' │ '1019.72' │ '983.347' │ '±0.12%' │ └─────────┴────────────────────┴───────────┴───────────────────┴──────────┘ ⚡ Speedup: +122.9% 🚀 📊 DB Calls per operation: NEW: 2.0 total (1.0 data, 1.0 where) OLD: 4.0 total (1.0 data, 3.0 where) 📊 Benchmark 3: docAccessOperation (with data passed) ────────────────────────────────────────────────────────────────────── Collection: where-cache-same (same where queries, no DB fetch) ┌─────────┬────────────────────┬───────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼────────────────────┼───────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (with cache)' │ '4945.43' │ '203.252' │ '±0.11%' │ │ 1 │ 'OLD (no cache)' │ '1023.75' │ '979.898' │ '±0.14%' │ └─────────┴────────────────────┴───────────┴───────────────────┴──────────┘ ⚡ Speedup: +383.1% 🚀 📊 DB Calls per operation: NEW: 1.0 total (0.0 data, 1.0 where) OLD: 4.0 total (1.0 data, 3.0 where) 📊 Benchmark 4: docAccessOperation (unique where queries) ────────────────────────────────────────────────────────────────────── Collection: where-cache-unique (unique where queries per operation) ┌─────────┬────────────────────┬───────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼────────────────────┼───────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (parallel)' │ '1693.67' │ '599.091' │ '±0.29%' │ │ 1 │ 'OLD (sequential)' │ '970.37' │ '1036.268' │ '±0.20%' │ └─────────┴────────────────────┴───────────┴───────────────────┴──────────┘ ⚡ Speedup: +74.5% 🚀 📊 DB Calls per operation: NEW: 4.0 total (1.0 data, 3.0 where) OLD: 4.0 total (1.0 data, 3.0 where) 📊 Benchmark 5: Complex Collection (async access, nested blocks, field access) ────────────────────────────────────────────────────────────────────── Collection: complex-content (stress test) ┌─────────┬────────────────────┬──────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼────────────────────┼──────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (optimized)' │ '133.17' │ '7683.346' │ '±0.83%' │ │ 1 │ 'OLD (sequential)' │ '72.86' │ '13901.616' │ '±0.82%' │ └─────────┴────────────────────┴──────────┴───────────────────┴──────────┘ ⚡ Speedup: +82.8% 🚀 📊 DB Calls per operation: NEW: 2.0 total (1.0 data, 1.0 where) OLD: 2.0 total (1.0 data, 1.0 where) 📊 Benchmark 6: Sync-Heavy Collection (same where, many sync field access) ────────────────────────────────────────────────────────────────────── Collection: sync-heavy (where cache + field access) ┌─────────┬────────────────────┬───────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼────────────────────┼───────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (with cache)' │ '3607.72' │ '279.559' │ '±0.15%' │ │ 1 │ 'OLD (no cache)' │ '68.87' │ '15136.557' │ '±1.44%' │ └─────────┴────────────────────┴───────────┴───────────────────┴──────────┘ ⚡ Speedup: +5138.5% 🚀 📊 DB Calls per operation: NEW: 1.0 total (0.0 data, 1.0 where) OLD: 5.0 total (1.0 data, 4.0 where) ══════════════════════════════════════════════════════════════════════ 📈 Summary: ══════════════════════════════════════════════════════════════════════ 1. getAccessResults: (see above) 2. docAccessOperation (with fetchData): (see above) 3. docAccessOperation (with data passed): (see above) 4. docAccessOperation (unique where): (see above) 5. Complex collection (async + nested): (see above) 6. Sync-heavy (where cache + fields): (see above) ══════════════════════════════════════════════════════════════════════ ``` ### Fields Test Suite `cd test && pnpm payload run fields/benchmark-getAccessResults.ts` ```md 📊 Benchmark: getAccessResults (all fields test collections + globals) ────────────────────────────────────────────────────────────────────── ┌─────────┬───────────────────┬───────────┬───────────────────┬──────────┐ │ (index) │ Task Name │ ops/sec │ Average Time (ms) │ Margin │ ├─────────┼───────────────────┼───────────┼───────────────────┼──────────┤ │ 0 │ 'NEW (optimized)' │ '2104.06' │ '478.382' │ '±0.18%' │ │ 1 │ 'OLD (previous)' │ '1208.14' │ '834.974' │ '±0.21%' │ └─────────┴───────────────────┴───────────┴───────────────────┴──────────┘ ⚡ Speedup: +74.2% 🚀 📊 DB Calls per operation (across all collections + globals): NEW: 0.0 total (0.0 data, 0.0 where) OLD: 0.0 total (0.0 data, 0.0 where) ```
1 parent caf68e4 commit 0d9ec91

File tree

28 files changed

+2554
-1346
lines changed

28 files changed

+2554
-1346
lines changed

docs/access-control/overview.mdx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,14 @@ To accomplish this, Payload exposes the [Access Operation](../authentication/ope
5656

5757
<Banner type="warning">
5858
**Important:** When your access control functions are executed via the [Access
59-
Operation](../authentication/operations#access), the `id` and `data` arguments
60-
will be `undefined`. This is because Payload is executing your functions
61-
without referencing a specific Document.
59+
Operation](../authentication/operations#access), the `id`, `data`, `siblingData`, `blockData` and `doc` arguments
60+
will be `undefined`. Additionally, `Where` queries returned from access control functions will not be run - we'll assume the user does not have access instead.
61+
62+
This is because Payload is executing your functions without referencing a specific Document.
63+
6264
</Banner>
6365

64-
If you use `id` or `data` within your access control functions, make sure to check that they are defined first. If they are not, then you can assume that your Access Control is being executed via the Access Operation to determine solely what the user can do within the Admin Panel.
66+
If you use `id`, `data`, `siblingData`, `blockData` and `doc` within your access control functions, make sure to check that they are defined first. If they are not, then you can assume that your Access Control is being executed via the Access Operation to determine solely what the user can do within the Admin Panel.
6567

6668
## Locale Specific Access Control
6769

packages/next/src/views/Document/getDocumentPermissions.tsx

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ export const getDocumentPermissions = async (args: {
1616
collectionConfig?: SanitizedCollectionConfig
1717
data: Data
1818
globalConfig?: SanitizedGlobalConfig
19+
/**
20+
* When called for creating a new document, id is not provided.
21+
*/
1922
id?: number | string
2023
req: PayloadRequest
2124
}): Promise<{
@@ -35,29 +38,27 @@ export const getDocumentPermissions = async (args: {
3538
collection: {
3639
config: collectionConfig,
3740
},
38-
req: {
39-
...req,
40-
data: {
41-
...data,
42-
_status: 'draft',
43-
},
41+
data: {
42+
...data,
43+
_status: 'draft',
4444
},
45+
req,
4546
})
4647

4748
if (collectionConfig.versions?.drafts) {
48-
hasPublishPermission = await docAccessOperation({
49-
id,
50-
collection: {
51-
config: collectionConfig,
52-
},
53-
req: {
54-
...req,
49+
hasPublishPermission = (
50+
await docAccessOperation({
51+
id,
52+
collection: {
53+
config: collectionConfig,
54+
},
5555
data: {
5656
...data,
5757
_status: 'published',
5858
},
59-
},
60-
}).then((permissions) => permissions.update)
59+
req,
60+
})
61+
).update
6162
}
6263
} catch (err) {
6364
logError({ err, payload: req.payload })
@@ -67,24 +68,22 @@ export const getDocumentPermissions = async (args: {
6768
if (globalConfig) {
6869
try {
6970
docPermissions = await docAccessOperationGlobal({
71+
data,
7072
globalConfig,
71-
req: {
72-
...req,
73-
data,
74-
},
73+
req,
7574
})
7675

7776
if (globalConfig.versions?.drafts) {
78-
hasPublishPermission = await docAccessOperationGlobal({
79-
globalConfig,
80-
req: {
81-
...req,
77+
hasPublishPermission = (
78+
await docAccessOperationGlobal({
8279
data: {
8380
...data,
8481
_status: 'published',
8582
},
86-
},
87-
}).then((permissions) => permissions.update)
83+
globalConfig,
84+
req,
85+
})
86+
).update
8887
}
8988
} catch (err) {
9089
logError({ err, payload: req.payload })

packages/payload/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
"types": "./src/index.ts",
4646
"default": "./src/index.ts"
4747
},
48+
"./internal": {
49+
"import": "./src/exports/internal.ts",
50+
"types": "./src/exports/internal.ts",
51+
"default": "./src/exports/internal.ts"
52+
},
4853
"./shared": {
4954
"import": "./src/exports/shared.ts",
5055
"types": "./src/exports/shared.ts",
@@ -150,6 +155,11 @@
150155
"types": "./dist/index.d.ts",
151156
"default": "./dist/index.js"
152157
},
158+
"./internal": {
159+
"import": "./dist/exports/internal.js",
160+
"types": "./dist/exports/internal.d.ts",
161+
"default": "./dist/exports/internal.js"
162+
},
153163
"./node": {
154164
"import": "./dist/exports/node.js",
155165
"types": "./dist/exports/node.d.ts",

packages/payload/src/auth/getAccessResults.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { AllOperations, PayloadRequest } from '../types/index.js'
22
import type { Permissions, SanitizedPermissions } from './types.js'
33

4-
import { getEntityPolicies } from '../utilities/getEntityPolicies.js'
4+
import { getEntityPermissions } from '../utilities/getEntityPermissions/getEntityPermissions.js'
55
import { sanitizePermissions } from '../utilities/sanitizePermissions.js'
66

77
type GetAccessResultsArgs = {
@@ -27,7 +27,7 @@ export async function getAccessResults({
2727
} else {
2828
results.canAccessAdmin = false
2929
}
30-
const blockPolicies = {}
30+
const blockReferencesPermissions = {}
3131

3232
await Promise.all(
3333
payload.config.collections.map(async (collection) => {
@@ -45,14 +45,15 @@ export async function getAccessResults({
4545
collectionOperations.push('readVersions')
4646
}
4747

48-
const collectionPolicy = await getEntityPolicies({
49-
type: 'collection',
50-
blockPolicies,
48+
const collectionPermissions = await getEntityPermissions({
49+
blockReferencesPermissions,
5150
entity: collection,
51+
entityType: 'collection',
52+
fetchData: false,
5253
operations: collectionOperations,
5354
req,
5455
})
55-
results.collections![collection.slug] = collectionPolicy
56+
results.collections![collection.slug] = collectionPermissions
5657
}),
5758
)
5859

@@ -64,14 +65,15 @@ export async function getAccessResults({
6465
globalOperations.push('readVersions')
6566
}
6667

67-
const globalPolicy = await getEntityPolicies({
68-
type: 'global',
69-
blockPolicies,
68+
const globalPermissions = await getEntityPermissions({
69+
blockReferencesPermissions,
7070
entity: global,
71+
entityType: 'global',
72+
fetchData: false,
7173
operations: globalOperations,
7274
req,
7375
})
74-
results.globals![global.slug] = globalPolicy
76+
results.globals![global.slug] = globalPermissions
7577
}),
7678
)
7779

packages/payload/src/auth/types.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,9 @@ export type SanitizedBlockPermissions =
2828
}
2929
| true
3030

31-
export type BlocksPermissions =
32-
| {
33-
[blockSlug: string]: BlockPermissions
34-
}
35-
| true
31+
export type BlocksPermissions = {
32+
[blockSlug: string]: BlockPermissions
33+
}
3634

3735
export type SanitizedBlocksPermissions =
3836
| {
@@ -42,10 +40,10 @@ export type SanitizedBlocksPermissions =
4240

4341
export type FieldPermissions = {
4442
blocks?: BlocksPermissions
45-
create: Permission
43+
create?: Permission
4644
fields?: FieldsPermissions
47-
read: Permission
48-
update: Permission
45+
read?: Permission
46+
update?: Permission
4947
}
5048

5149
export type SanitizedFieldPermissions =
@@ -65,12 +63,14 @@ export type SanitizedFieldsPermissions =
6563
| true
6664

6765
export type CollectionPermission = {
68-
create: Permission
69-
delete: Permission
66+
create?: Permission
67+
delete?: Permission
7068
fields: FieldsPermissions
71-
read: Permission
69+
read?: Permission
7270
readVersions?: Permission
73-
update: Permission
71+
// Auth-enabled Collections only
72+
unlock?: Permission
73+
update?: Permission
7474
}
7575

7676
export type SanitizedCollectionPermission = {
@@ -79,14 +79,16 @@ export type SanitizedCollectionPermission = {
7979
fields: SanitizedFieldsPermissions
8080
read?: true
8181
readVersions?: true
82+
// Auth-enabled Collections only
83+
unlock?: true
8284
update?: true
8385
}
8486

8587
export type GlobalPermission = {
8688
fields: FieldsPermissions
87-
read: Permission
89+
read?: Permission
8890
readVersions?: Permission
89-
update: Permission
91+
update?: Permission
9092
}
9193

9294
export type SanitizedGlobalPermission = {

packages/payload/src/collections/operations/docAccess.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
import type { SanitizedCollectionPermission } from '../../auth/index.js'
2-
import type { AllOperations, PayloadRequest } from '../../types/index.js'
2+
import type { AllOperations, JsonObject, PayloadRequest } from '../../types/index.js'
33
import type { Collection } from '../config/types.js'
44

5-
import { getEntityPolicies } from '../../utilities/getEntityPolicies.js'
5+
import { getEntityPermissions } from '../../utilities/getEntityPermissions/getEntityPermissions.js'
66
import { killTransaction } from '../../utilities/killTransaction.js'
77
import { sanitizePermissions } from '../../utilities/sanitizePermissions.js'
88

99
const allOperations: AllOperations[] = ['create', 'read', 'update', 'delete']
1010

1111
type Arguments = {
1212
collection: Collection
13-
id: number | string
13+
/**
14+
* If the document data is passed, it will be used to check access instead of fetching the document from the database.
15+
*/
16+
data?: JsonObject
17+
/**
18+
* When called for creating a new document, id is not provided.
19+
*/
20+
id?: number | string
1421
req: PayloadRequest
1522
}
1623

1724
export async function docAccessOperation(args: Arguments): Promise<SanitizedCollectionPermission> {
1825
const {
1926
id,
2027
collection: { config },
28+
data,
2129
req,
2230
} = args
2331

@@ -36,11 +44,13 @@ export async function docAccessOperation(args: Arguments): Promise<SanitizedColl
3644
}
3745

3846
try {
39-
const result = await getEntityPolicies({
40-
id,
41-
type: 'collection',
42-
blockPolicies: {},
47+
const result = await getEntityPermissions({
48+
id: id!,
49+
blockReferencesPermissions: {},
50+
data,
4351
entity: config,
52+
entityType: 'collection',
53+
fetchData: id ? true : (false as true),
4454
operations: collectionOperations,
4555
req,
4656
})

packages/payload/src/config/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import type { RootFoldersConfiguration } from '../folders/types.js'
4343
import type { GlobalConfig, Globals, SanitizedGlobalConfig } from '../globals/config/types.js'
4444
import type {
4545
Block,
46+
DefaultDocumentIDType,
4647
FlattenedBlock,
4748
JobsConfig,
4849
KVAdapterResult,
@@ -314,7 +315,7 @@ export type AccessArgs<TData = any> = {
314315
*/
315316
data?: TData
316317
/** ID of the resource being accessed */
317-
id?: number | string
318+
id?: DefaultDocumentIDType
318319
/** If true, the request is for a static file */
319320
isReadingStaticFile?: boolean
320321
/** The original request that requires an access check */

packages/payload/src/database/queryValidation/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { CollectionPermission, GlobalPermission } from '../../auth/index.js'
22
import type { FlattenedField } from '../../fields/config/types.js'
33

4+
// TODO: Rename to EntityPermissions in 4.0
45
export type EntityPolicies = {
56
collections?: {
67
[collectionSlug: string]: CollectionPermission

packages/payload/src/database/queryValidation/validateQueryPaths.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { validateSearchParam } from './validateSearchParams.js'
1111
type Args = {
1212
errors?: { path: string }[]
1313
overrideAccess: boolean
14+
// TODO: Rename to permissions or entityPermissions in 4.0
1415
policies?: EntityPolicies
1516
polymorphicJoin?: boolean
1617
req: PayloadRequest

packages/payload/src/database/queryValidation/validateSearchParams.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { PayloadRequest, WhereField } from '../../types/index.js'
55
import type { EntityPolicies, PathToQuery } from './types.js'
66

77
import { fieldAffectsData } from '../../fields/config/types.js'
8-
import { getEntityPolicies } from '../../utilities/getEntityPolicies.js'
8+
import { getEntityPermissions } from '../../utilities/getEntityPermissions/getEntityPermissions.js'
99
import { isolateObjectProperty } from '../../utilities/isolateObjectProperty.js'
1010
import { getLocalizedPaths } from '../getLocalizedPaths.js'
1111
import { validateQueryPaths } from './validateQueryPaths.js'
@@ -20,6 +20,7 @@ type Args = {
2020
overrideAccess: boolean
2121
parentIsLocalized?: boolean
2222
path: string
23+
// TODO: Rename to permissions or entityPermissions in 4.0
2324
policies: EntityPolicies
2425
polymorphicJoin?: boolean
2526
req: PayloadRequest
@@ -56,13 +57,14 @@ export async function validateSearchParam({
5657
let paths: PathToQuery[] = []
5758
const { slug } = (collectionConfig || globalConfig)!
5859

59-
const blockPolicies = {}
60+
const blockReferencesPermissions = {}
6061

6162
if (globalConfig && !policies.globals![slug]) {
62-
policies.globals![slug] = await getEntityPolicies({
63-
type: 'global',
64-
blockPolicies,
63+
policies.globals![slug] = await getEntityPermissions({
64+
blockReferencesPermissions,
6565
entity: globalConfig,
66+
entityType: 'global',
67+
fetchData: false,
6668
operations: ['read'],
6769
req,
6870
})
@@ -123,10 +125,11 @@ export async function validateSearchParam({
123125
if (!overrideAccess && fieldAffectsData(field)) {
124126
if (collectionSlug) {
125127
if (!policies.collections![collectionSlug]) {
126-
policies.collections![collectionSlug] = await getEntityPolicies({
127-
type: 'collection',
128-
blockPolicies,
128+
policies.collections![collectionSlug] = await getEntityPermissions({
129+
blockReferencesPermissions,
129130
entity: req.payload.collections[collectionSlug]!.config,
131+
entityType: 'collection',
132+
fetchData: false,
130133
operations: ['read'],
131134
req: isolateObjectProperty(req, 'transactionID'),
132135
})

0 commit comments

Comments
 (0)