feat: implement Result types for type-safe error handling (Phase 1.1)
Replace throw/catch patterns with explicit Result types throughout the codebase. This provides type-safe error handling and better user-facing error messages. ## Changes ### Core Type System (src/types.ts) - Add Result<T, E> discriminated union type - Add AsyncResult<T, E> for promises - Add helper functions: Ok(), Err(), tryCatch(), tryCatchAsync() ### Crypto Module (src/lib/crypto.ts) - Update parsePublicKeyFromCert() to return Result<PublicKey, string> - Update encryptValue() to return Result<string, string> - Update encryptKeyValues() to return Result<Record<string, string>, string> - Early return on first encryption failure with detailed error ### Controller API (src/lib/controller.ts) - Update fetchPublicCertificate() to return AsyncResult<string, string> - Update verifySealedSecret() to return AsyncResult<boolean, string> - Update rotateSealedSecret() to return AsyncResult<string, string> - Use tryCatchAsync() for HTTP operations ### UI Components - EncryptDialog: Explicit error checking at each step with specific messages - SealingKeysView: Type-safe certificate download with error handling - DecryptDialog: Import cleanup (auto-fixed by linter) - SealedSecretDetail: Unused import removed (auto-fixed by linter) ### Documentation - ENHANCEMENT_PLAN.md: Comprehensive 4-phase enhancement roadmap - PHASE_1.1_COMPLETE.md: Detailed implementation summary - BUILD_VERIFICATION_SUMMARY.md: Build metrics and verification results - DEVELOPMENT.md: Development workflow guide - TESTING_GUIDE.md: Manual testing procedures - READY_FOR_TESTING.md: Quick-start testing guide ### Development Tools - Add 5 specialized Claude Code subagents to .claude/agents/ - typescript-pro: TypeScript expertise - kubernetes-specialist: K8s best practices - react-specialist: React optimization - security-auditor: Security review - code-reviewer: Code quality ## Benefits - Type Safety: Errors are now part of type signatures - Better UX: Specific error messages at each operation step - Maintainability: Error paths are explicit and visible - No Hidden Exceptions: All error cases handled explicitly ## Verification - TypeScript: 0 errors - Linting: All checks pass - Build: 340.13 kB (93.40 kB gzipped, +0.2%) - Package: Successfully created ## Breaking Changes None for users. Internal API signatures changed but plugin behavior is backward compatible. ## Testing See TESTING_GUIDE.md for detailed test scenarios: - Happy path: Create sealed secret with valid controller - Error path: Try with controller unreachable - Console check: Verify no uncaught exceptions Run: npm start (in headlamp-sealed-secrets directory) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -4,6 +4,80 @@
|
||||
|
||||
import { KubeObjectInterface } from '@kinvolk/headlamp-plugin/lib/lib/k8s/cluster';
|
||||
|
||||
/**
|
||||
* Result type for operations that can fail
|
||||
* Replaces throw/catch with explicit error handling
|
||||
*
|
||||
* @example
|
||||
* function divide(a: number, b: number): Result<number, string> {
|
||||
* if (b === 0) return Err('Division by zero');
|
||||
* return Ok(a / b);
|
||||
* }
|
||||
*/
|
||||
export type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E };
|
||||
|
||||
/**
|
||||
* Async result type for promises that can fail
|
||||
*/
|
||||
export type AsyncResult<T, E = Error> = Promise<Result<T, E>>;
|
||||
|
||||
/**
|
||||
* Helper to create a success result
|
||||
*
|
||||
* @example
|
||||
* return Ok(42);
|
||||
*/
|
||||
export function Ok<T>(value: T): Result<T, never> {
|
||||
return { ok: true, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to create an error result
|
||||
*
|
||||
* @example
|
||||
* return Err('Something went wrong');
|
||||
* return Err(new Error('Something went wrong'));
|
||||
*/
|
||||
export function Err<E>(error: E): Result<never, E> {
|
||||
return { ok: false, error };
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a throwing function to a Result-returning function
|
||||
*
|
||||
* @example
|
||||
* const safeParseJSON = tryCatch(JSON.parse);
|
||||
* const result = safeParseJSON('{"key": "value"}');
|
||||
* if (result.ok) {
|
||||
* console.log(result.value);
|
||||
* }
|
||||
*/
|
||||
export function tryCatch<T>(fn: () => T): Result<T, Error> {
|
||||
try {
|
||||
return Ok(fn());
|
||||
} catch (error) {
|
||||
return Err(error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an async throwing function to an AsyncResult
|
||||
*
|
||||
* @example
|
||||
* const safeFetch = tryCatchAsync(() => fetch('/api/data'));
|
||||
* const result = await safeFetch();
|
||||
*/
|
||||
export async function tryCatchAsync<T>(fn: () => Promise<T>): AsyncResult<T, Error> {
|
||||
try {
|
||||
const value = await fn();
|
||||
return Ok(value);
|
||||
} catch (error) {
|
||||
return Err(error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sealed Secret scope types
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user