feat(domains): create domain-driven architecture for Phase 2
Chat Domain: - Add types.ts with Message, Conversation, Agent types - Add store.ts with Valtio-based state management - Add hooks.ts with useChatState, useMessages, etc. - Add index.ts for public API export Hands Domain: - Add types.ts with Hand, Trigger, Approval types - Add machine.ts with XState state machine - Add store.ts with Valtio-based state management - Add hooks.ts with useHands, useApprovalQueue, etc. Shared Module: - Add types.ts with Result, AsyncResult, PaginatedResponse - Add error-handling.ts with AppError, NetworkError, etc. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
105
desktop/src/shared/error-handling.ts
Normal file
105
desktop/src/shared/error-handling.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Shared Error Handling
|
||||
*
|
||||
* Unified error handling utilities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Application error class with error code.
|
||||
*/
|
||||
export class AppError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly code: string,
|
||||
public readonly cause?: Error
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'AppError';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a AppError from an unknown error.
|
||||
*/
|
||||
static fromUnknown(error: unknown, code: string): AppError {
|
||||
if (error instanceof AppError) {
|
||||
return error;
|
||||
}
|
||||
return new AppError(getErrorMessage(error), code, isError(error) ? error : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Network error class.
|
||||
*/
|
||||
export class NetworkError extends AppError {
|
||||
constructor(message: string, public readonly statusCode?: number, cause?: Error) {
|
||||
super(message, 'NETWORK_ERROR', cause);
|
||||
this.name = 'NetworkError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation error class.
|
||||
*/
|
||||
export class ValidationError extends AppError {
|
||||
constructor(message: string, public readonly field?: string, cause?: Error) {
|
||||
super(message, 'VALIDATION_ERROR', cause);
|
||||
this.name = 'ValidationError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication error class.
|
||||
*/
|
||||
export class AuthError extends AppError {
|
||||
constructor(message: string = 'Authentication required', cause?: Error) {
|
||||
super(message, 'AUTH_ERROR', cause);
|
||||
this.name = 'AuthError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for Error.
|
||||
*/
|
||||
export function isError(error: unknown): error is Error {
|
||||
return error instanceof Error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error message from unknown error.
|
||||
*/
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
if (isError(error)) {
|
||||
return error.message;
|
||||
}
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap error with code.
|
||||
*/
|
||||
export function wrapError(error: unknown, code: string): AppError {
|
||||
return AppError.fromUnknown(error, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if error is a specific error class.
|
||||
*/
|
||||
export function isAppError(error: unknown): error is AppError {
|
||||
return error instanceof AppError;
|
||||
}
|
||||
|
||||
export function isNetworkError(error: unknown): error is NetworkError {
|
||||
return error instanceof NetworkError;
|
||||
}
|
||||
|
||||
export function isValidationError(error: unknown): error is ValidationError {
|
||||
return error instanceof ValidationError;
|
||||
}
|
||||
|
||||
export function isAuthError(error: unknown): error is AuthError {
|
||||
return error instanceof AuthError;
|
||||
}
|
||||
31
desktop/src/shared/index.ts
Normal file
31
desktop/src/shared/index.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Shared Module
|
||||
*
|
||||
* Common utilities, types, and error handling.
|
||||
*/
|
||||
|
||||
// Types
|
||||
export type {
|
||||
Result,
|
||||
AsyncResult,
|
||||
PaginatedResponse,
|
||||
AsyncStatus,
|
||||
AsyncState,
|
||||
Entity,
|
||||
NamedEntity,
|
||||
} from './types';
|
||||
|
||||
// Errors
|
||||
export {
|
||||
AppError,
|
||||
NetworkError,
|
||||
ValidationError,
|
||||
AuthError,
|
||||
isError,
|
||||
getErrorMessage,
|
||||
wrapError,
|
||||
isAppError,
|
||||
isNetworkError,
|
||||
isValidationError,
|
||||
isAuthError,
|
||||
} from './error-handling';
|
||||
58
desktop/src/shared/types.ts
Normal file
58
desktop/src/shared/types.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Shared Types
|
||||
*
|
||||
* Common types used across domains.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Result type for functional error handling.
|
||||
*/
|
||||
export type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E };
|
||||
|
||||
/**
|
||||
* Async result for promises.
|
||||
*/
|
||||
export type AsyncResult<T, E = Error> = Promise<Result<T, E>>;
|
||||
|
||||
/**
|
||||
* Paginated response for list endpoints.
|
||||
*/
|
||||
export interface PaginatedResponse<T> {
|
||||
items: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common status for async operations.
|
||||
*/
|
||||
export type AsyncStatus = 'idle' | 'loading' | 'success' | 'error';
|
||||
|
||||
/**
|
||||
* Generic async state wrapper.
|
||||
*/
|
||||
export interface AsyncState<T, E = Error> {
|
||||
status: AsyncStatus;
|
||||
data: T | null;
|
||||
error: E | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity with common fields.
|
||||
*/
|
||||
export interface Entity {
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Named entity with name field.
|
||||
*/
|
||||
export interface NamedEntity extends Entity {
|
||||
name: string;
|
||||
}
|
||||
Reference in New Issue
Block a user