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:
iven
2026-03-21 19:47:48 +08:00
parent 20eed290f8
commit 7ffd5e1531
13 changed files with 2319 additions and 0 deletions

View 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;
}

View 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';

View 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;
}