Files
tech-log-frontend/src/contracts/schema-registry.ts
T

112 lines
3.2 KiB
TypeScript

export type SchemaDefinition = Readonly<{
schemaId: string;
boundary:
| "route-params"
| "route-search"
| "route-search-api-request"
| "api-request"
| "api-response";
owner: string;
runtime: "zod";
schemaVersion?: number;
direction?: "REQUEST" | "RESPONSE";
unknownFieldPolicy?: "REJECT_UNKNOWN" | "STRIP_UNKNOWN";
}>;
export type RuntimeSchemaResult =
| Readonly<{ success: true; data: unknown }>
| Readonly<{
success: false;
issues: readonly Readonly<{ path: string; code: string }>[];
}>;
export type RuntimeSchemaCodec = Readonly<{
schemaId: string;
parse(value: unknown): RuntimeSchemaResult;
}>;
export function composeRuntimeSchemaCodecs(
contributions: readonly Readonly<Record<string, RuntimeSchemaCodec>>[],
): Readonly<Record<string, RuntimeSchemaCodec>> {
const result: Record<string, RuntimeSchemaCodec> = Object.create(null);
for (const contribution of contributions) {
for (const [registryId, codec] of Object.entries(contribution)) {
if (
registryId !== codec.schemaId ||
Object.hasOwn(result, registryId)
) {
throw new TypeError(
`Invalid or duplicate runtime schema codec: ${registryId}`,
);
}
result[registryId] = codec;
}
}
return Object.freeze(result);
}
export function validateWithRuntimeSchemaRegistry(
schemaId: string,
value: unknown,
registry: Readonly<Record<string, RuntimeSchemaCodec>>,
): RuntimeSchemaResult {
const codec = registry[schemaId];
if (!codec) {
return Object.freeze({
success: false,
issues: Object.freeze([
Object.freeze({ path: "", code: "SCHEMA_NOT_REGISTERED" }),
]),
});
}
try {
return codec.parse(value);
} catch {
return Object.freeze({
success: false,
issues: Object.freeze([
Object.freeze({ path: "", code: "SCHEMA_EXECUTION_FAILED" }),
]),
});
}
}
export function composeSchemaRegistry(
contributions: readonly Readonly<Record<string, SchemaDefinition>>[],
): Readonly<Record<string, SchemaDefinition>> {
const result: Record<string, SchemaDefinition> = Object.create(null);
for (const contribution of contributions) {
for (const [registryId, definition] of Object.entries(contribution)) {
if (
registryId !== definition.schemaId ||
!definition.owner ||
(definition.schemaVersion !== undefined &&
(!Number.isSafeInteger(definition.schemaVersion) ||
definition.schemaVersion < 1)) ||
Object.hasOwn(result, registryId)
) {
throw new TypeError(`Invalid or duplicate schema definition: ${registryId}`);
}
result[registryId] = definition;
}
}
return Object.freeze(result);
}
export const PLATFORM_SCHEMA_REGISTRY: Readonly<
Record<string, SchemaDefinition>
> = Object.freeze({
none: Object.freeze({
schemaId: "none",
boundary: "route-params",
owner: "feature-frontend-routing-release-recovery-runtime",
runtime: "zod",
}),
NotFoundSplat: Object.freeze({
schemaId: "NotFoundSplat",
boundary: "route-params",
owner: "feature-frontend-routing-release-recovery-runtime",
runtime: "zod",
}),
});