e3551fb78f
Replace z.array(z.unknown()) with RolePresetsSchema for blueprint role presets mutation input, ensuring structural validation before Prisma JSON cast. Also adds SECURITY.md for vulnerability disclosure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
112 lines
3.2 KiB
TypeScript
112 lines
3.2 KiB
TypeScript
import type { Prisma, PrismaClient } from "@capakraken/db";
|
|
import {
|
|
CreateBlueprintSchema,
|
|
UpdateBlueprintSchema,
|
|
type BlueprintFieldDefinition,
|
|
} from "@capakraken/shared";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { z } from "zod";
|
|
|
|
type BlueprintIdentifierDb = Pick<PrismaClient, "blueprint">;
|
|
|
|
type BlueprintGlobalFieldDefinition = BlueprintFieldDefinition & {
|
|
blueprintId: string;
|
|
blueprintName: string;
|
|
};
|
|
|
|
type BlueprintFieldDefinitionSource = {
|
|
id: string;
|
|
name: string;
|
|
fieldDefs: unknown;
|
|
};
|
|
|
|
type CreateBlueprintInput = z.infer<typeof CreateBlueprintSchema>;
|
|
type UpdateBlueprintInput = z.infer<typeof UpdateBlueprintSchema>;
|
|
|
|
export async function findBlueprintByIdentifier<TBlueprint>(
|
|
db: BlueprintIdentifierDb,
|
|
identifier: string,
|
|
extraArgs: Record<string, unknown>,
|
|
): Promise<TBlueprint> {
|
|
const normalizedIdentifier = identifier.trim();
|
|
|
|
let blueprint = (await db.blueprint.findUnique({
|
|
where: { id: normalizedIdentifier },
|
|
...extraArgs,
|
|
})) as TBlueprint | null;
|
|
|
|
if (!blueprint) {
|
|
blueprint = (await db.blueprint.findFirst({
|
|
where: { name: { equals: normalizedIdentifier, mode: "insensitive" } },
|
|
...extraArgs,
|
|
})) as TBlueprint | null;
|
|
}
|
|
|
|
if (!blueprint) {
|
|
blueprint = (await db.blueprint.findFirst({
|
|
where: { name: { contains: normalizedIdentifier, mode: "insensitive" } },
|
|
...extraArgs,
|
|
})) as TBlueprint | null;
|
|
}
|
|
|
|
if (!blueprint) {
|
|
throw new TRPCError({
|
|
code: "NOT_FOUND",
|
|
message: `Blueprint not found: ${normalizedIdentifier}`,
|
|
});
|
|
}
|
|
|
|
return blueprint;
|
|
}
|
|
|
|
export function buildBlueprintCreateData(
|
|
input: CreateBlueprintInput,
|
|
): Prisma.BlueprintUncheckedCreateInput {
|
|
return {
|
|
name: input.name,
|
|
target: input.target,
|
|
description: input.description ?? null,
|
|
fieldDefs: input.fieldDefs as unknown as Prisma.InputJsonValue,
|
|
defaults: input.defaults as unknown as Prisma.InputJsonValue,
|
|
validationRules: input.validationRules as unknown as Prisma.InputJsonValue,
|
|
};
|
|
}
|
|
|
|
export function buildBlueprintUpdateData(
|
|
input: UpdateBlueprintInput,
|
|
): Prisma.BlueprintUncheckedUpdateInput {
|
|
return {
|
|
...(input.name !== undefined ? { name: input.name } : {}),
|
|
...(input.description !== undefined ? { description: input.description } : {}),
|
|
...(input.fieldDefs !== undefined
|
|
? { fieldDefs: input.fieldDefs as unknown as Prisma.InputJsonValue }
|
|
: {}),
|
|
...(input.defaults !== undefined
|
|
? { defaults: input.defaults as unknown as Prisma.InputJsonValue }
|
|
: {}),
|
|
...(input.validationRules !== undefined
|
|
? { validationRules: input.validationRules as unknown as Prisma.InputJsonValue }
|
|
: {}),
|
|
};
|
|
}
|
|
|
|
export function buildBlueprintRolePresetsUpdateData(
|
|
rolePresets: readonly Record<string, unknown>[],
|
|
): Prisma.BlueprintUncheckedUpdateInput {
|
|
return {
|
|
rolePresets: rolePresets as unknown as Prisma.InputJsonValue,
|
|
};
|
|
}
|
|
|
|
export function expandGlobalBlueprintFieldDefs(
|
|
blueprints: BlueprintFieldDefinitionSource[],
|
|
): BlueprintGlobalFieldDefinition[] {
|
|
return blueprints.flatMap((blueprint) =>
|
|
(blueprint.fieldDefs as BlueprintFieldDefinition[]).map((fieldDef) => ({
|
|
...fieldDef,
|
|
blueprintId: blueprint.id,
|
|
blueprintName: blueprint.name,
|
|
})),
|
|
);
|
|
}
|