feat: add removable reference feature vertical slice

This commit is contained in:
donghyeon-ka
2026-07-26 14:56:34 +09:00
parent 980981bc86
commit c11be43f20
87 changed files with 1881 additions and 1114 deletions
@@ -0,0 +1,54 @@
import {
createReferenceResource,
type ReferenceResource,
} from "../domain/reference-resource.js";
export type ReferenceResourceView = Readonly<{
resourceId: string;
title: string;
createdAtLabel: string | null;
optimistic?: boolean;
}>;
function mapReferenceDto(value: unknown): ReferenceResource {
if (!value || typeof value !== "object") {
throw new TypeError("Validated reference DTO is required");
}
const dto = value as Record<string, unknown>;
if (typeof dto.id !== "string" || typeof dto.name !== "string") {
throw new TypeError("Validated reference DTO invariants were breached");
}
return createReferenceResource({
id: dto.id,
displayName: dto.name,
createdAt: typeof dto.createdAt === "string" ? dto.createdAt : null,
});
}
export function mapReferenceOperation(
operationId: string,
payload: unknown,
): ReferenceResource | readonly ReferenceResource[] {
if (operationId === "LIST_REFERENCE_RESOURCES") {
if (!Array.isArray(payload)) throw new TypeError("Expected a reference list");
return payload.map(mapReferenceDto);
}
if (operationId === "CREATE_REFERENCE_RESOURCE") {
return mapReferenceDto(payload);
}
throw new TypeError(`No reference mapper registered for ${operationId}`);
}
export function toReferenceView(
resource: ReferenceResource,
formatDate: (value: Date) => string = (value) =>
new Intl.DateTimeFormat("ko-KR").format(value),
): ReferenceResourceView {
return Object.freeze({
resourceId: resource.id,
title: resource.displayName,
createdAtLabel: resource.createdAt
? formatDate(new Date(resource.createdAt))
: null,
});
}