Files
agentic-dev/packages/core-dsr/src/payload-processing-restriction.ts

88 lines
2.7 KiB
TypeScript

import { getPayload as _getPayload } from "payload";
import type { SanitizedConfig } from "payload";
import type { AuditLogProtocol } from "@repo/core-shared/di";
import type { IProcessingRestriction } from "./processing-restriction.interface";
type PayloadDoc = Record<string, unknown>;
type PayloadAPI = {
find(args: {
collection: string;
where: Record<string, unknown>;
overrideAccess: true;
limit: number;
}): Promise<{ docs: PayloadDoc[] }>;
update(args: {
collection: string;
id: string;
data: Record<string, unknown>;
overrideAccess: true;
}): Promise<PayloadDoc>;
};
type GetPayload = (args: { config: SanitizedConfig }) => Promise<PayloadAPI>;
const USERS_COLLECTION = "users";
const RESTRICTION_FIELD = "processingRestrictedAt";
/**
* Payload-backed IProcessingRestriction. Toggles and reads the
* `processingRestrictedAt` date field on the subject's user record.
*
* Emits RESTRICT or UNRESTRICT audit entries on every state change.
* The `subjectId` is the document ID in the `users` collection.
*/
export class PayloadProcessingRestriction implements IProcessingRestriction {
constructor(
private readonly config: SanitizedConfig,
private readonly auditLog: AuditLogProtocol,
private readonly getPayloadFn: GetPayload = _getPayload as unknown as GetPayload,
) {}
async setRestriction(subjectId: string, granted: boolean): Promise<void> {
const payload = await this.getPayloadFn({ config: this.config });
await payload.update({
collection: USERS_COLLECTION,
id: subjectId,
data: { [RESTRICTION_FIELD]: granted ? new Date().toISOString() : null },
overrideAccess: true,
});
await this.auditLog.record({
actorId: subjectId,
actorType: "user",
actorRoles: [],
action: granted ? "RESTRICT" : "UNRESTRICT",
resource: { type: USERS_COLLECTION, id: subjectId },
changedFields: [RESTRICTION_FIELD],
at: new Date(),
scope: {
feature: "core-dsr",
environment: process.env["NODE_ENV"] ?? "development",
tenant: "default",
},
from: { ipTruncated: "system", userAgent: "system" },
containsPii: false,
outcome: "success",
});
}
async isRestricted(subjectId: string): Promise<boolean> {
const payload = await this.getPayloadFn({ config: this.config });
const result = await payload.find({
collection: USERS_COLLECTION,
where: { id: { equals: subjectId } },
overrideAccess: true,
limit: 1,
});
const doc = result.docs[0];
if (!doc) return false;
const restrictedAt = doc[RESTRICTION_FIELD];
return restrictedAt !== null && restrictedAt !== undefined;
}
}