Repository: directus/directus
File: api/src/permissions/modules/validate-access/lib/validate-item-access.ts (TypeScript)

Code before:

export interface ValidateItemAccessOptionsWithFields extends ValidateItemAccessOptions {
	returnAllowedRootFields: true;
}

export interface ValidateItemAccessResult {
	accessAllowed: boolean;
	allowedRootFields?: string[];
}

export interface ValidateItemAccessResultWithFields extends ValidateItemAccessResult {
	allowedRootFields: string[];
}

export async function validateItemAccess(
	options: ValidateItemAccessOptionsWithFields,
	context: Context,
): Promise<ValidateItemAccessResultWithFields>;

export async function validateItemAccess(
	options: ValidateItemAccessOptions,
	context: Context,
): Promise<ValidateItemAccessResult>;

export async function validateItemAccess(
	options: ValidateItemAccessOptions | ValidateItemAccessOptionsWithFields,
	context: Context,
): Promise<ValidateItemAccessResult | ValidateItemAccessResultWithFields> {
	const primaryKeyField = context.schema.collections[options.collection]?.primary;

	if (!primaryKeyField) {
		throw new Error(`Cannot find primary key for collection "${options.collection}"`);
	}

	// When we're looking up access to specific items, we have to read them from the database to
	// make sure you are allowed to access them.

	const ast: AST = {
		type: 'root',
		name: options.collection,
		query: { limit: options.primaryKeys.length },
		// Act as if every field was a "normal" field
		children:
			options.fields?.map((field) => ({ type: 'field', name: field, fieldKey: field, whenCase: [], alias: false })) ??
			[],
		cases: [],
	};

	await processAst({ ast, ...options }, context);

	// Inject the filter after the permissions have been processed, as to not require access to the primary key

Review comment (suggestion):
```suggestion
	options: ValidateItemAccessOptions | ValidateItemAccessOptionsWithRootFields,
```

Code after:

export interface ValidateItemAccessOptionsWithRootFields extends ValidateItemAccessOptions {
	returnAllowedRootFields: true;
}

export interface ValidateItemAccessResult {
	accessAllowed: boolean;
	allowedRootFields?: string[];
}

export interface ValidateItemAccessResultWithRootFields extends ValidateItemAccessResult {
	allowedRootFields: string[];
}

export async function validateItemAccess(
	options: ValidateItemAccessOptionsWithRootFields,
	context: Context,
): Promise<ValidateItemAccessResultWithRootFields>;

export async function validateItemAccess(
	options: ValidateItemAccessOptions,
	context: Context,
): Promise<ValidateItemAccessResult>;

export async function validateItemAccess(
	options: ValidateItemAccessOptions | ValidateItemAccessOptionsWithRootFields,
	context: Context,
): Promise<ValidateItemAccessResult | ValidateItemAccessResultWithRootFields> {
	const primaryKeyField = context.schema.collections[options.collection]?.primary;

	if (!primaryKeyField) {
		throw new Error(`Cannot find primary key for collection "${options.collection}"`);
	}

	// When we're looking up access to specific items, we have to read them from the database to
	// make sure you are allowed to access them.

	const ast: AST = {
		type: 'root',
		name: options.collection,
		query: { limit: options.primaryKeys.length },
		// Act as if every field was a "normal" field
		children:
			options.fields?.map((field) => ({ type: 'field', name: field, fieldKey: field, whenCase: [], alias: false })) ??
			[],
		cases: [],
	};

	await processAst({ ast, ...options }, context);

	// Inject the filter after the permissions have been processed, as to not require access to the primary key