website refactor
This commit is contained in:
@@ -2,25 +2,39 @@ import { Result } from "../Result";
|
||||
|
||||
/**
|
||||
* PageQuery contract interface
|
||||
*
|
||||
*
|
||||
* Defines the canonical contract for all server-side page queries.
|
||||
*
|
||||
* Based on WEBSITE_PAGE_QUERIES.md:
|
||||
*
|
||||
* Architecture:
|
||||
* - Server-side composition classes
|
||||
* - Call services that call apps/api
|
||||
* - Assemble a Page DTO
|
||||
* - Explicit result describing route outcome
|
||||
* - Construct Services manually (no DI container)
|
||||
* - Services create their own dependencies (API Client, Logger, ErrorReporter)
|
||||
* - Services return Result<ApiDto, DomainError>
|
||||
* - PageQuery maps DomainError → PresentationError
|
||||
* - PageQuery returns Result<ViewData, PresentationError>
|
||||
* - Do not implement business rules
|
||||
*
|
||||
* @template TApiDto - The API DTO type this query produces
|
||||
*
|
||||
* @template TViewData - The ViewData type this query produces for templates
|
||||
* @template TParams - The parameters required to execute this query
|
||||
* @template TError - The error type (default: string for backward compatibility)
|
||||
*/
|
||||
export interface PageQuery<TApiDto, TParams = void> {
|
||||
export interface PageQuery<TViewData, TParams = void, TError = string> {
|
||||
/**
|
||||
* Execute the page query
|
||||
*
|
||||
*
|
||||
* Manual construction pattern:
|
||||
* ```typescript
|
||||
* const service = new MyService();
|
||||
* const result = await service.getData();
|
||||
* if (result.isErr()) {
|
||||
* return Result.err(mapToPresentationError(result.error));
|
||||
* }
|
||||
* const viewData = MyViewDataBuilder.build(result.value);
|
||||
* return Result.ok(viewData);
|
||||
* ```
|
||||
*
|
||||
* @param params - Parameters required for query execution
|
||||
* @returns Promise resolving to a Result
|
||||
* @returns Promise<Result<ViewData, TError>>
|
||||
*/
|
||||
execute(params: TParams): Promise<Result<TApiDto, string>>;
|
||||
execute(params: TParams): Promise<Result<TViewData, TError>>;
|
||||
}
|
||||
|
||||
42
apps/website/lib/contracts/page-queries/PresentationError.ts
Normal file
42
apps/website/lib/contracts/page-queries/PresentationError.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Presentation Error Type
|
||||
*
|
||||
* Errors that can be handled by the presentation layer (RSC pages, templates).
|
||||
* These are mapped from DomainErrors by PageQueries.
|
||||
*/
|
||||
|
||||
export type PresentationError =
|
||||
| 'notFound' // Resource not found - show 404 page
|
||||
| 'redirect' // Redirect to another page (e.g., login)
|
||||
| 'unauthorized' // Not authorized - show access denied
|
||||
| 'serverError' // Generic server error
|
||||
| 'networkError' // Network/communication error
|
||||
| 'validationError' // Invalid input data
|
||||
| 'unknown'; // Unknown error
|
||||
|
||||
// Helper to map DomainError to PresentationError
|
||||
export function mapToPresentationError(domainError: any): PresentationError {
|
||||
const errorType = domainError?.type || domainError?.name || 'unknown';
|
||||
|
||||
switch (errorType) {
|
||||
case 'notFound':
|
||||
case 'NotFoundError':
|
||||
return 'notFound';
|
||||
case 'unauthorized':
|
||||
case 'UnauthorizedError':
|
||||
case 'ForbiddenError':
|
||||
return 'unauthorized';
|
||||
case 'serverError':
|
||||
case 'ServerError':
|
||||
case 'HttpServerError':
|
||||
return 'serverError';
|
||||
case 'networkError':
|
||||
case 'NetworkError':
|
||||
return 'networkError';
|
||||
case 'validationError':
|
||||
case 'ValidationError':
|
||||
return 'validationError';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user