{"version":3,"sources":["../../../src/utilities/getEntityPermissions/populateFieldPermissions.ts"],"sourcesContent":["import type {\n BlockPermissions,\n BlocksPermissions,\n CollectionPermission,\n FieldPermissions,\n FieldsPermissions,\n GlobalPermission,\n Permission,\n} from '../../auth/types.js'\nimport type { DefaultDocumentIDType } from '../../index.js'\nimport type { AllOperations, JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { BlockReferencesPermissions } from './getEntityPermissions.js'\n\nimport { type Field, tabHasName } from '../../fields/config/types.js'\n\nconst isThenable = (value: unknown): value is Promise =>\n value != null && typeof (value as { then?: unknown }).then === 'function'\n\n/**\n * Helper to set a permission value that might be a promise.\n * If it's a promise, creates a chained promise that resolves to update the target,\n * stores the promise temporarily, and adds it to the promises array for later resolution.\n */\nconst setPermission = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n target: any,\n operation: AllOperations,\n value: boolean | Promise | undefined,\n promises: Promise[],\n): void => {\n if (isThenable(value)) {\n // Create a single permission object that will be mutated in place\n // This ensures all references (including cached blocks) see the resolved value\n const permissionObj = { permission: value as any }\n target[operation] = permissionObj\n\n const permissionPromise = value.then((result) => {\n // Mutate the permission property in place so all references see the update\n permissionObj.permission = result\n })\n\n promises.push(permissionPromise)\n } else {\n target[operation] = { permission: value }\n }\n}\n\n/**\n * Build up permissions object and run access functions for each field of an entity\n * This function is synchronous and collects all async work into the promises array\n */\nexport const populateFieldPermissions = ({\n id,\n blockReferencesPermissions,\n data,\n fields,\n operations,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n}: {\n blockReferencesPermissions: BlockReferencesPermissions\n data: JsonObject | undefined\n fields: Field[]\n id?: DefaultDocumentIDType\n /**\n * Operations to check access for\n */\n operations: AllOperations[]\n parentPermissionsObject: CollectionPermission | FieldPermissions | GlobalPermission\n permissionsObject: FieldsPermissions\n promises: Promise[]\n req: PayloadRequest\n}): void => {\n for (const field of fields) {\n // Set up permissions for all operations\n for (const operation of operations) {\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n if ('name' in field && field.name) {\n if (!permissionsObject[field.name]) {\n permissionsObject[field.name] = {} as FieldPermissions\n }\n const fieldPermissions: FieldPermissions = permissionsObject[field.name]!\n\n if ('access' in field && field.access && typeof field.access[operation] === 'function') {\n const accessResult = field.access[operation]({\n id,\n data,\n doc: data,\n req,\n // We cannot include siblingData or blockData here, as we do not have siblingData/blockData available once we reach block or array\n // rows, as we're calculating schema permissions, which do not include individual rows.\n // For consistency, it's thus better to never include the siblingData and blockData\n })\n\n // Handle both sync and async access results\n if (isThenable(accessResult)) {\n const booleanPromise = accessResult.then((result) => Boolean(result))\n setPermission(fieldPermissions, operation, booleanPromise, promises)\n } else {\n setPermission(fieldPermissions, operation, Boolean(accessResult), promises)\n }\n } else {\n // Inherit from parent (which might be a promise)\n setPermission(fieldPermissions, operation, parentPermissionForOperation, promises)\n }\n }\n }\n\n // Handle named fields with nested content\n if ('name' in field && field.name) {\n const fieldPermissions: FieldPermissions = permissionsObject[field.name]!\n\n if ('fields' in field && field.fields) {\n if (!fieldPermissions.fields) {\n fieldPermissions.fields = {}\n }\n\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: field.fields,\n operations,\n parentPermissionsObject: fieldPermissions,\n permissionsObject: fieldPermissions.fields,\n promises,\n req,\n })\n }\n\n if (\n ('blocks' in field && field.blocks?.length) ||\n ('blockReferences' in field && field.blockReferences?.length)\n ) {\n if (!fieldPermissions.blocks) {\n fieldPermissions.blocks = {}\n }\n const blocksPermissions: BlocksPermissions = fieldPermissions.blocks\n\n // Set up permissions for all operations for all blocks\n for (const operation of operations) {\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n for (const _block of field.blockReferences ?? field.blocks) {\n const block = typeof _block === 'string' ? req.payload.blocks[_block] : _block\n\n // Skip if block doesn't exist (invalid block reference)\n if (!block) {\n continue\n }\n\n // Handle block references - check if we've seen this block before\n if (typeof _block === 'string') {\n const blockReferencePermissions = blockReferencesPermissions[_block]\n if (blockReferencePermissions) {\n // Reference the cached permissions (may be a promise or resolved object)\n blocksPermissions[block.slug] = blockReferencePermissions as BlockPermissions\n continue\n }\n }\n\n // Initialize block permissions object if needed\n if (!blocksPermissions[block.slug]) {\n blocksPermissions[block.slug] = {} as BlockPermissions\n }\n\n const blockPermission = blocksPermissions[block.slug]!\n\n // Set permission for this operation\n if (!blockPermission[operation]) {\n const fieldPermission =\n fieldPermissions[operation]?.permission ?? parentPermissionForOperation\n\n // Inherit from field permission (which might be a promise)\n setPermission(blockPermission, operation, fieldPermission, promises)\n }\n }\n }\n\n // Process nested content for each unique block (once per block, not once per operation)\n const processedBlocks = new Set()\n for (const _block of field.blockReferences ?? field.blocks) {\n const block = typeof _block === 'string' ? req.payload.blocks[_block] : _block\n\n // Skip if block doesn't exist (invalid block reference)\n if (!block || processedBlocks.has(block.slug)) {\n continue\n }\n processedBlocks.add(block.slug)\n\n const blockPermission = blocksPermissions[block.slug]\n if (!blockPermission) {\n continue\n }\n\n if (!blockPermission.fields) {\n blockPermission.fields = {}\n }\n\n // Handle block references with caching - store as promise that will be resolved later\n if (typeof _block === 'string' && !blockReferencesPermissions[_block]) {\n // Mark this block as being processed by storing a reference\n blockReferencesPermissions[_block] = blockPermission\n }\n\n // Recursively process block fields synchronously\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: block.fields,\n operations,\n parentPermissionsObject: blockPermission,\n permissionsObject: blockPermission.fields,\n promises,\n req,\n })\n }\n }\n }\n\n // Handle unnamed group fields\n if ('fields' in field && field.fields && !('name' in field && field.name)) {\n // Field does not have a name => same parentPermissionsObject\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: field.fields,\n operations,\n // Field does not have a name here => use parent permissions object\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n })\n }\n\n // Handle tabs fields\n if (field.type === 'tabs') {\n // Process tabs for all operations\n for (const operation of operations) {\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n for (const tab of field.tabs) {\n if (tabHasName(tab)) {\n if (!permissionsObject[tab.name]) {\n permissionsObject[tab.name] = { fields: {} } as FieldPermissions\n }\n\n const tabPermissions = permissionsObject[tab.name]!\n if (!tabPermissions[operation]) {\n // Inherit from parent (which might be a promise)\n setPermission(tabPermissions, operation, parentPermissionForOperation, promises)\n }\n }\n }\n }\n\n for (const tab of field.tabs) {\n if (tabHasName(tab)) {\n const tabPermissions: FieldPermissions = permissionsObject[tab.name]!\n\n if (!tabPermissions.fields) {\n tabPermissions.fields = {}\n }\n\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: tab.fields,\n operations,\n parentPermissionsObject: tabPermissions,\n permissionsObject: tabPermissions.fields,\n promises,\n req,\n })\n } else {\n // Tab does not have a name => same parentPermissionsObject\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: tab.fields,\n operations,\n // Tab does not have a name here => use parent permissions object\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n })\n }\n }\n }\n }\n}\n"],"names":["tabHasName","isThenable","value","then","setPermission","target","operation","promises","permissionObj","permission","permissionPromise","result","push","populateFieldPermissions","id","blockReferencesPermissions","data","fields","operations","parentPermissionsObject","permissionsObject","req","field","parentPermissionForOperation","name","fieldPermissions","access","accessResult","doc","booleanPromise","Boolean","blocks","length","blockReferences","blocksPermissions","_block","block","payload","blockReferencePermissions","slug","blockPermission","fieldPermission","processedBlocks","Set","has","add","type","tab","tabs","tabPermissions"],"mappings":"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"}