refactor: 프론트엔드 리펙토링
This commit is contained in:
@@ -19,8 +19,10 @@ augmentation으로 `"reference-feature": ReferenceFeatureInput`을 기여하므
|
||||
별도 cast나 runtime shape 확인 없이 정확한 input type을 받는다. 다만 동적 호출로
|
||||
설치되지 않은 ID가 들어오는 경우를 위해 `get`의 runtime guard도 유지한다.
|
||||
|
||||
예측 가능한 실패는 `src/application/result.ts`의 공통
|
||||
`Result<Value, Failure = AppFailure>`로 반환한다. `AppFailure.kind`는
|
||||
예측 가능한 실패는 canonical shared contract인
|
||||
`src/contracts/result.ts`의 `Result<Value, Failure = AppFailure>`로 반환한다.
|
||||
`src/application/result.ts`는 기존 호출자를 위한 deprecated migration shim일
|
||||
뿐 새 코드의 import 경로가 아니다. `AppFailure.kind`는
|
||||
`ERROR_REGISTRY` key에서 파생된 닫힌 vocabulary이며, transport 호환 이름인
|
||||
`ApiFailure`는 같은 type의 alias다.
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ import {
|
||||
createFeatureHttpBinding,
|
||||
type InstalledHttpOperationExecutor,
|
||||
} from "../../../adapters/http/index.ts";
|
||||
import {
|
||||
defineFeatureAdapterContribution,
|
||||
} from "../../feature-adapter-contribution.ts";
|
||||
import { createReferenceFeatureInput } from "../application/reference-feature-api.ts";
|
||||
import {
|
||||
REFERENCE_FEATURE_ID,
|
||||
@@ -17,15 +20,14 @@ export type InstalledContractOperationExecutor =
|
||||
/**
|
||||
* Feature-owned composition seam.
|
||||
*
|
||||
* The feature contributes typed operation descriptors and its application
|
||||
* gateway. HTTP lifecycle/error normalization stays in the reusable capability
|
||||
* binding rather than being repeated by every product feature.
|
||||
* The feature receives only the HTTP capability it declares in `needs`.
|
||||
* HTTP lifecycle/error normalization stays in the reusable capability binding.
|
||||
*/
|
||||
export function createReferenceFeatureInstalledInput(context: Readonly<{
|
||||
contractOperations: InstalledHttpOperationExecutor;
|
||||
http: InstalledHttpOperationExecutor;
|
||||
}>) {
|
||||
const http = createFeatureHttpBinding(
|
||||
context.contractOperations,
|
||||
context.http,
|
||||
REFERENCE_HTTP_OPERATIONS,
|
||||
);
|
||||
|
||||
@@ -35,7 +37,9 @@ export function createReferenceFeatureInstalledInput(context: Readonly<{
|
||||
});
|
||||
}
|
||||
|
||||
export const REFERENCE_FEATURE_ADAPTER_CONTRIBUTION = Object.freeze({
|
||||
featureId: REFERENCE_FEATURE_ID,
|
||||
createInput: createReferenceFeatureInstalledInput,
|
||||
});
|
||||
export const REFERENCE_FEATURE_ADAPTER_CONTRIBUTION =
|
||||
defineFeatureAdapterContribution({
|
||||
featureId: REFERENCE_FEATURE_ID,
|
||||
needs: ["http"] as const,
|
||||
createInput: createReferenceFeatureInstalledInput,
|
||||
});
|
||||
|
||||
@@ -1,40 +1,57 @@
|
||||
import {
|
||||
defineFeatureHttpOperation,
|
||||
defineFeatureHttpOperationForRoutes,
|
||||
type FeatureHttpBinding,
|
||||
} from "../../../adapters/http/index.ts";
|
||||
import type {
|
||||
ReferenceCreateCommand,
|
||||
ReferenceGateway,
|
||||
ReferenceListFilters,
|
||||
} from "../application/reference-feature-api.ts";
|
||||
import type { ReferenceResource } from "../domain/reference-resource.ts";
|
||||
import {
|
||||
CREATE_REFERENCE_RESOURCE_CONTRACT,
|
||||
GET_REFERENCE_RESOURCE_CONTRACT,
|
||||
LIST_REFERENCE_RESOURCES_CONTRACT,
|
||||
} from "../contracts/reference-feature-contract-contribution.ts";
|
||||
import {
|
||||
REFERENCE_FEATURE_CONTRACT,
|
||||
} from "../contracts/reference-feature-contract.ts";
|
||||
import {
|
||||
mapReferenceResourceListPayload,
|
||||
mapReferenceResourcePayload,
|
||||
} from "../contracts/reference-mapper.ts";
|
||||
import type {
|
||||
ReferenceGateway,
|
||||
} from "../application/reference-feature-api.ts";
|
||||
|
||||
export type ReferenceFeatureRouteId =
|
||||
keyof typeof REFERENCE_FEATURE_CONTRACT.routes;
|
||||
|
||||
const defineReferenceHttpOperation =
|
||||
defineFeatureHttpOperationForRoutes<ReferenceFeatureRouteId>();
|
||||
|
||||
export const REFERENCE_HTTP_OPERATIONS = Object.freeze({
|
||||
LIST_REFERENCE_RESOURCES: defineFeatureHttpOperation<
|
||||
ReferenceListFilters,
|
||||
readonly ReferenceResource[]
|
||||
>({
|
||||
operationId: "LIST_REFERENCE_RESOURCES",
|
||||
LIST_REFERENCE_RESOURCES: defineReferenceHttpOperation({
|
||||
contract: LIST_REFERENCE_RESOURCES_CONTRACT,
|
||||
routeId: "REFERENCE_RESOURCE_LIST",
|
||||
mapSuccess: mapReferenceResourceListPayload,
|
||||
}),
|
||||
CREATE_REFERENCE_RESOURCE: defineFeatureHttpOperation<
|
||||
ReferenceCreateCommand,
|
||||
ReferenceResource
|
||||
>({
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
CREATE_REFERENCE_RESOURCE: defineReferenceHttpOperation({
|
||||
contract: CREATE_REFERENCE_RESOURCE_CONTRACT,
|
||||
routeId: "REFERENCE_RESOURCE_LIST",
|
||||
mapSuccess: mapReferenceResourcePayload,
|
||||
mapProblem(problem, metadata) {
|
||||
if (metadata.status === 409) {
|
||||
return Object.freeze({
|
||||
kind: "CONFLICT" as const,
|
||||
code: problem.code ?? "REFERENCE_RESOURCE_CONFLICT",
|
||||
});
|
||||
}
|
||||
if (metadata.status === 422) {
|
||||
return Object.freeze({
|
||||
kind: "VALIDATION_REJECTED" as const,
|
||||
code: problem.code ?? "REFERENCE_RESOURCE_REJECTED",
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}),
|
||||
GET_REFERENCE_RESOURCE: defineFeatureHttpOperation<
|
||||
Readonly<{ resourceId: string }>,
|
||||
ReferenceResource
|
||||
>({
|
||||
operationId: "GET_REFERENCE_RESOURCE",
|
||||
GET_REFERENCE_RESOURCE: defineReferenceHttpOperation({
|
||||
contract: GET_REFERENCE_RESOURCE_CONTRACT,
|
||||
routeId: "REFERENCE_RESOURCE_DETAIL",
|
||||
mapSuccess: mapReferenceResourcePayload,
|
||||
}),
|
||||
|
||||
+42
-56
@@ -2,17 +2,22 @@ import { z } from "zod";
|
||||
|
||||
import type {
|
||||
CommandEffectDescriptor,
|
||||
HttpRequestProjection,
|
||||
InstalledContractContribution,
|
||||
InstalledHttpContract,
|
||||
RuntimeValidator,
|
||||
} from "../../../contracts/external-contract-runtime.ts";
|
||||
import { REFERENCE_FEATURE_ID } from "./reference-feature-contract.ts";
|
||||
import {
|
||||
createReferenceResourceCommandSchema,
|
||||
referenceProblemSchema,
|
||||
referenceResourceDtoSchema,
|
||||
referenceResourceListQuerySchema,
|
||||
referenceResourceParamsSchema,
|
||||
type ReferenceProblem,
|
||||
} from "./reference-schemas.ts";
|
||||
|
||||
export type { ReferenceProblem } from "./reference-schemas.ts";
|
||||
|
||||
/**
|
||||
* §4.8. The single `TEMPLATE_FIXTURE` contribution. It keeps the reference
|
||||
* HTTP vertical executable as deterministic template data and is excluded from
|
||||
@@ -53,33 +58,10 @@ function zodValidator<T>(
|
||||
});
|
||||
}
|
||||
|
||||
const referenceResourceDto = z
|
||||
.object({
|
||||
id: z.string().min(1).max(120),
|
||||
name: z.string().min(1).max(240),
|
||||
createdAt: z.string().min(1).optional(),
|
||||
})
|
||||
.strip();
|
||||
|
||||
const problemSchema = z
|
||||
.object({
|
||||
type: z.string().min(1).max(512),
|
||||
title: z.string().min(1).max(240),
|
||||
status: z.int().min(100).max(599),
|
||||
code: z.string().min(1).max(120).optional(),
|
||||
})
|
||||
.strip();
|
||||
|
||||
export type ReferenceProblem = z.output<typeof problemSchema>;
|
||||
|
||||
const PROBLEM_VALIDATOR = zodValidator("ReferenceProblem", problemSchema);
|
||||
|
||||
const createCommandSchema = z
|
||||
.object({
|
||||
name: z.string().trim().min(1).max(120),
|
||||
note: z.string().trim().max(500).optional(),
|
||||
})
|
||||
.strict();
|
||||
const PROBLEM_VALIDATOR = zodValidator(
|
||||
"ReferenceProblem",
|
||||
referenceProblemSchema,
|
||||
);
|
||||
|
||||
/**
|
||||
* Fixture-side classifier standing in for the package-provided pure bounded
|
||||
@@ -87,17 +69,17 @@ const createCommandSchema = z
|
||||
*/
|
||||
const CREATE_EFFECT: CommandEffectDescriptor<ReferenceProblem> = Object.freeze({
|
||||
successEffect: "APPLIED_CONFIRMED" as const,
|
||||
classifyProblem({ status }: Readonly<{ status: number; problem: ReferenceProblem }>) {
|
||||
if (status === 400 || status === 409 || status === 422) return "NOT_APPLIED";
|
||||
classifyProblem({
|
||||
status,
|
||||
}: Readonly<{ status: number; problem: ReferenceProblem }>) {
|
||||
if (status === 400 || status === 409 || status === 422) {
|
||||
return "NOT_APPLIED";
|
||||
}
|
||||
return "MAYBE_APPLIED";
|
||||
},
|
||||
});
|
||||
|
||||
const LIST_REFERENCE_RESOURCES: InstalledHttpContract<
|
||||
z.output<typeof referenceResourceListQuerySchema>,
|
||||
readonly z.output<typeof referenceResourceDto>[],
|
||||
ReferenceProblem
|
||||
> = Object.freeze({
|
||||
export const LIST_REFERENCE_RESOURCES_CONTRACT = Object.freeze({
|
||||
contract: Object.freeze({
|
||||
operationId: "LIST_REFERENCE_RESOURCES",
|
||||
method: "GET" as const,
|
||||
@@ -108,7 +90,7 @@ const LIST_REFERENCE_RESOURCES: InstalledHttpContract<
|
||||
),
|
||||
outputValidator: zodValidator(
|
||||
"ReferenceResourceListPayload",
|
||||
z.array(referenceResourceDto).max(100),
|
||||
z.array(referenceResourceDtoSchema).max(100),
|
||||
),
|
||||
problemValidator: PROBLEM_VALIDATOR,
|
||||
acceptedStatuses: Object.freeze([200]),
|
||||
@@ -139,13 +121,13 @@ const LIST_REFERENCE_RESOURCES: InstalledHttpContract<
|
||||
authProfileId: "REFERENCE_EXTERNAL_BEARER",
|
||||
diagnosticsOperation: "reference.list",
|
||||
}),
|
||||
});
|
||||
|
||||
const GET_REFERENCE_RESOURCE: InstalledHttpContract<
|
||||
z.output<typeof referenceResourceParamsSchema>,
|
||||
z.output<typeof referenceResourceDto>,
|
||||
}) satisfies InstalledHttpContract<
|
||||
z.output<typeof referenceResourceListQuerySchema>,
|
||||
readonly z.output<typeof referenceResourceDtoSchema>[],
|
||||
ReferenceProblem
|
||||
> = Object.freeze({
|
||||
>;
|
||||
|
||||
export const GET_REFERENCE_RESOURCE_CONTRACT = Object.freeze({
|
||||
contract: Object.freeze({
|
||||
operationId: "GET_REFERENCE_RESOURCE",
|
||||
method: "GET" as const,
|
||||
@@ -156,7 +138,7 @@ const GET_REFERENCE_RESOURCE: InstalledHttpContract<
|
||||
),
|
||||
outputValidator: zodValidator(
|
||||
"ReferenceResourcePayload",
|
||||
referenceResourceDto,
|
||||
referenceResourceDtoSchema,
|
||||
),
|
||||
problemValidator: PROBLEM_VALIDATOR,
|
||||
acceptedStatuses: Object.freeze([200]),
|
||||
@@ -183,24 +165,24 @@ const GET_REFERENCE_RESOURCE: InstalledHttpContract<
|
||||
authProfileId: "REFERENCE_EXTERNAL_BEARER",
|
||||
diagnosticsOperation: "reference.detail",
|
||||
}),
|
||||
});
|
||||
|
||||
const CREATE_REFERENCE_RESOURCE: InstalledHttpContract<
|
||||
z.output<typeof createCommandSchema>,
|
||||
z.output<typeof referenceResourceDto>,
|
||||
}) satisfies InstalledHttpContract<
|
||||
z.output<typeof referenceResourceParamsSchema>,
|
||||
z.output<typeof referenceResourceDtoSchema>,
|
||||
ReferenceProblem
|
||||
> = Object.freeze({
|
||||
>;
|
||||
|
||||
export const CREATE_REFERENCE_RESOURCE_CONTRACT = Object.freeze({
|
||||
contract: Object.freeze({
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
method: "POST" as const,
|
||||
pathTemplate: "/api/reference-resources",
|
||||
inputValidator: zodValidator(
|
||||
"CreateReferenceResourceCommand",
|
||||
createCommandSchema,
|
||||
createReferenceResourceCommandSchema,
|
||||
),
|
||||
outputValidator: zodValidator(
|
||||
"ReferenceResourcePayload",
|
||||
referenceResourceDto,
|
||||
referenceResourceDtoSchema,
|
||||
),
|
||||
problemValidator: PROBLEM_VALIDATOR,
|
||||
acceptedStatuses: Object.freeze([200, 201]),
|
||||
@@ -213,7 +195,7 @@ const CREATE_REFERENCE_RESOURCE: InstalledHttpContract<
|
||||
operationIdentityField: "idempotencyKey",
|
||||
}),
|
||||
commandEffect: CREATE_EFFECT,
|
||||
projectRequest(input: z.output<typeof createCommandSchema>) {
|
||||
projectRequest(input: z.output<typeof createReferenceResourceCommandSchema>) {
|
||||
return Object.freeze({
|
||||
pathValues: Object.freeze({}),
|
||||
queryEntries: Object.freeze([]),
|
||||
@@ -235,7 +217,11 @@ const CREATE_REFERENCE_RESOURCE: InstalledHttpContract<
|
||||
authProfileId: "REFERENCE_EXTERNAL_BEARER",
|
||||
diagnosticsOperation: "reference.create",
|
||||
}),
|
||||
});
|
||||
}) satisfies InstalledHttpContract<
|
||||
z.output<typeof createReferenceResourceCommandSchema>,
|
||||
z.output<typeof referenceResourceDtoSchema>,
|
||||
ReferenceProblem
|
||||
>;
|
||||
|
||||
export const REFERENCE_FEATURE_TEMPLATE_CONTRIBUTION: InstalledContractContribution =
|
||||
Object.freeze({
|
||||
@@ -247,9 +233,9 @@ export const REFERENCE_FEATURE_TEMPLATE_CONTRIBUTION: InstalledContractContribut
|
||||
revision: 1 as const,
|
||||
}),
|
||||
http: Object.freeze([
|
||||
LIST_REFERENCE_RESOURCES,
|
||||
GET_REFERENCE_RESOURCE,
|
||||
CREATE_REFERENCE_RESOURCE,
|
||||
LIST_REFERENCE_RESOURCES_CONTRACT,
|
||||
GET_REFERENCE_RESOURCE_CONTRACT,
|
||||
CREATE_REFERENCE_RESOURCE_CONTRACT,
|
||||
]) as readonly InstalledHttpContract<unknown, unknown, unknown>[],
|
||||
events: Object.freeze([]),
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
type InstalledBoundaryMapper,
|
||||
type MappingResult,
|
||||
} from "../../../contracts/boundary-mapper.ts";
|
||||
import type { ReferenceResourceDto } from "./reference-schemas.ts";
|
||||
|
||||
export type ReferenceResourceView = Readonly<{
|
||||
resourceId: string;
|
||||
@@ -16,22 +17,19 @@ export type ReferenceResourceView = Readonly<{
|
||||
optimistic?: boolean;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Operation-specific mapper. The HTTP contract has already validated the wire
|
||||
* shape, so this mapper owns only wire -> domain construction.
|
||||
*/
|
||||
export function mapReferenceResourcePayload(
|
||||
value: unknown,
|
||||
dto: ReferenceResourceDto,
|
||||
): MappingResult<ReferenceResource> {
|
||||
if (!value || typeof value !== "object") {
|
||||
return mappingFailure("MAPPING_INVARIANT_REJECTED");
|
||||
}
|
||||
const dto = value as Record<string, unknown>;
|
||||
if (typeof dto.id !== "string" || typeof dto.name !== "string") {
|
||||
return mappingFailure("MAPPING_INVARIANT_REJECTED");
|
||||
}
|
||||
try {
|
||||
return mappingSuccess(
|
||||
createReferenceResource({
|
||||
id: dto.id,
|
||||
displayName: dto.name,
|
||||
createdAt: typeof dto.createdAt === "string" ? dto.createdAt : null,
|
||||
createdAt: dto.createdAt ?? null,
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
@@ -40,14 +38,8 @@ export function mapReferenceResourcePayload(
|
||||
}
|
||||
|
||||
export function mapReferenceResourceListPayload(
|
||||
payload: unknown,
|
||||
payload: readonly ReferenceResourceDto[],
|
||||
): MappingResult<readonly ReferenceResource[]> {
|
||||
if (!Array.isArray(payload)) {
|
||||
return mappingFailure("MAPPING_INVARIANT_REJECTED");
|
||||
}
|
||||
if (payload.length > 100) {
|
||||
return mappingFailure("OUTPUT_LIMIT_EXCEEDED");
|
||||
}
|
||||
const output: ReferenceResource[] = [];
|
||||
for (const item of payload) {
|
||||
const mapped = mapReferenceResourcePayload(item);
|
||||
@@ -57,22 +49,58 @@ export function mapReferenceResourceListPayload(
|
||||
return mappingSuccess(Object.freeze(output));
|
||||
}
|
||||
|
||||
function isReferenceResourceDto(value: unknown): value is ReferenceResourceDto {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
||||
const dto = value as Record<string, unknown>;
|
||||
return (
|
||||
typeof dto.id === "string" &&
|
||||
typeof dto.name === "string" &&
|
||||
(dto.createdAt === undefined || typeof dto.createdAt === "string")
|
||||
);
|
||||
}
|
||||
|
||||
function mapUnknownReferenceResourcePayload(
|
||||
value: unknown,
|
||||
): MappingResult<ReferenceResource> {
|
||||
return isReferenceResourceDto(value)
|
||||
? mapReferenceResourcePayload(value)
|
||||
: mappingFailure("MAPPING_INVARIANT_REJECTED");
|
||||
}
|
||||
|
||||
function mapUnknownReferenceResourceListPayload(
|
||||
value: unknown,
|
||||
): MappingResult<readonly ReferenceResource[]> {
|
||||
if (
|
||||
!Array.isArray(value) ||
|
||||
value.length > 100 ||
|
||||
!value.every(isReferenceResourceDto)
|
||||
) {
|
||||
return mappingFailure(
|
||||
Array.isArray(value) && value.length > 100
|
||||
? "OUTPUT_LIMIT_EXCEEDED"
|
||||
: "MAPPING_INVARIANT_REJECTED",
|
||||
);
|
||||
}
|
||||
return mapReferenceResourceListPayload(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry-facing compatibility projection. Feature adapters should prefer the
|
||||
* operation-specific mapper functions above so their result type is exact.
|
||||
* Registry-facing compatibility projection. The registry is intentionally
|
||||
* untyped, so its adapter performs the defensive shape check. Feature HTTP
|
||||
* bindings use the typed operation-specific mappers above.
|
||||
*/
|
||||
export function mapReferenceOperation(
|
||||
operationId: string,
|
||||
payload: unknown,
|
||||
): MappingResult<ReferenceResource | readonly ReferenceResource[]> {
|
||||
if (operationId === "LIST_REFERENCE_RESOURCES") {
|
||||
return mapReferenceResourceListPayload(payload);
|
||||
return mapUnknownReferenceResourceListPayload(payload);
|
||||
}
|
||||
if (
|
||||
operationId === "CREATE_REFERENCE_RESOURCE" ||
|
||||
operationId === "GET_REFERENCE_RESOURCE"
|
||||
) {
|
||||
return mapReferenceResourcePayload(payload);
|
||||
return mapUnknownReferenceResourcePayload(payload);
|
||||
}
|
||||
return mappingFailure("MAPPING_INVARIANT_REJECTED");
|
||||
}
|
||||
@@ -85,7 +113,7 @@ export const REFERENCE_BOUNDARY_MAPPERS = Object.freeze({
|
||||
outputContractId: "ReferenceResourceList",
|
||||
owner: "feature-frontend-reference-feature-vertical-slice",
|
||||
maxOutputItems: 100,
|
||||
map: mapReferenceResourceListPayload,
|
||||
map: mapUnknownReferenceResourceListPayload,
|
||||
}),
|
||||
ReferenceResourceMapper: Object.freeze({
|
||||
mapperId: "ReferenceResourceMapper",
|
||||
@@ -94,7 +122,7 @@ export const REFERENCE_BOUNDARY_MAPPERS = Object.freeze({
|
||||
outputContractId: "ReferenceResource",
|
||||
owner: "feature-frontend-reference-feature-vertical-slice",
|
||||
maxOutputItems: 1,
|
||||
map: mapReferenceResourcePayload,
|
||||
map: mapUnknownReferenceResourcePayload,
|
||||
}),
|
||||
} satisfies Readonly<Record<string, InstalledBoundaryMapper>>);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export const referenceResourceListQuerySchema = z
|
||||
: Array.isArray(value)
|
||||
? value
|
||||
: [value],
|
||||
z.array(z.string().trim().min(1)),
|
||||
z.array(z.string().trim().min(1)).readonly(),
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
@@ -25,7 +25,7 @@ export const referenceResourceParamsSchema = z
|
||||
})
|
||||
.strict();
|
||||
|
||||
const referenceResourceDtoSchema = z
|
||||
export const referenceResourceDtoSchema = z
|
||||
.object({
|
||||
id: z.string().min(1).max(120),
|
||||
name: z.string().min(1).max(240),
|
||||
@@ -33,6 +33,28 @@ const referenceResourceDtoSchema = z
|
||||
})
|
||||
.strip();
|
||||
|
||||
export type ReferenceResourceDto = z.output<
|
||||
typeof referenceResourceDtoSchema
|
||||
>;
|
||||
|
||||
export const referenceProblemSchema = z
|
||||
.object({
|
||||
type: z.string().min(1).max(512),
|
||||
title: z.string().min(1).max(240),
|
||||
status: z.int().min(100).max(599),
|
||||
code: z.string().min(1).max(120).optional(),
|
||||
})
|
||||
.strip();
|
||||
|
||||
export type ReferenceProblem = z.output<typeof referenceProblemSchema>;
|
||||
|
||||
export const createReferenceResourceCommandSchema = z
|
||||
.object({
|
||||
name: z.string().trim().min(1).max(120),
|
||||
note: z.string().trim().max(500).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const payloadSchemas = {
|
||||
ReferenceResourceListPayload: z.array(referenceResourceDtoSchema).max(100),
|
||||
ReferenceResourcePayload: referenceResourceDtoSchema,
|
||||
@@ -42,12 +64,7 @@ const requestSchemas = {
|
||||
ReferenceResourceParams: referenceResourceParamsSchema,
|
||||
ReferenceResourceListQuery: referenceResourceListQuerySchema,
|
||||
NoRequest: z.object({}).strict(),
|
||||
CreateReferenceResourceCommand: z
|
||||
.object({
|
||||
name: z.string().trim().min(1).max(120),
|
||||
note: z.string().trim().max(500).optional(),
|
||||
})
|
||||
.strict(),
|
||||
CreateReferenceResourceCommand: createReferenceResourceCommandSchema,
|
||||
} satisfies Record<string, z.ZodType>;
|
||||
|
||||
function project(result: z.ZodSafeParseResult<unknown>) {
|
||||
|
||||
Reference in New Issue
Block a user