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:
2026-02-11 21:09:10 -05:00
parent b0d86831b7
commit 286e88fece
18 changed files with 5619 additions and 56 deletions
+74
View File
@@ -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
*/