import type { CallerContext } from "./types"; interface InvokerLike { id: string; attributes: { permissions?: string[]; companyId?: string | null } | null; } interface ResolverContext { invoker: InvokerLike | null; } /** * Translates a resolver context into the {@link CallerContext} that erp-kit * commands and queries take. It only translates — whether the call is allowed is * decided by the permission gate in {@link defineCommand} / {@link defineQuery}, * and by the resolver's own `permission` in `tailor.config.ts`. * * `invoker` is the identity the resolver executes as — the configured machine user * when the resolver declares one, the caller otherwise. The SDK injects it on every * invocation and leaves it `null` only for an anonymous call, which is why there is * no `caller` fallback here. * * An anonymous call yields `actorId: null` rather than a placeholder id. Commands * and permission-gated queries reject it; a query that declares `"allowAnonymous"` * handles it. * * ```ts * const ctx = createContext(context); * const result = await imCommands.createItem(trx, input, ctx); * ``` */ export function createContext(context: ResolverContext): CallerContext { const { invoker } = context; if (!invoker) { return { actorId: null, permissions: [], companyId: null }; } return { actorId: invoker.id, permissions: [...new Set(invoker.attributes?.permissions ?? [])], companyId: invoker.attributes?.companyId, }; }