Files
HealthLog/src/lib/sharing/acting-domains.ts
T
Marc-André Bombeck 78ac2c5aeb refactor(sharing): read and judge grants from a leaf module
lib/sharing/grants.ts held both the grant transitions and the predicates
every reader asks (state, level, scope, the live grant for a pair). The
transitions reach into the managed-profile lifecycle and the OAuth connect
target, and both of those read a live grant, so grants, lifecycle and
connect-target formed an import cycle.

The predicates, findActiveGrant and touchGrantUsage move verbatim to
lib/sharing/grant-access.ts, which imports only the database client and
the scope vocabulary. Importers and the mocks that replaced those
functions point at the new module. Runtime import cycles fall from 7 to 6.
2026-10-23 11:02:10 +02:00

35 lines
1.5 KiB
TypeScript

/**
* Which sections of the record the caller is actually inside.
*
* Lives here rather than beside one feature because a route that reads or
* writes across its own declared section is a shape the product keeps growing,
* and its callers are already spread over four features. No list of them here:
* a comment that enumerates its own callers is a comment that goes stale on
* the next one. Two verbatim copies of this existed in the visits and the
* vaccination service, with a note on the second saying a second spelling
* would be a second thing to keep in step.
*
* Returns a predicate rather than a set so the owner path costs nothing: with
* no grant there is nothing to look up and every domain is open. A grant that
* vanished between the auth check and here answers "no" to everything, which
* is the fail-closed direction. `record` answers true only for a grant over
* the whole record, as `grantCoversDomain` decides.
*/
import type { Prisma } from "@/generated/prisma/client";
import { grantCoversDomain } from "@/lib/sharing/grant-access";
import type { ShareScope } from "@/lib/sharing/scope";
export async function actingDomainVisibility(
tx: Prisma.TransactionClient,
grantId: string | null,
): Promise<(domain: ShareScope) => boolean> {
if (grantId === null) return () => true;
const grant = await tx.accountGrant.findUnique({
where: { id: grantId },
select: { scopeJson: true },
});
if (!grant) return () => false;
return (domain) => grantCoversDomain(grant, domain);
}