7.6 KiB
7.6 KiB
Changelog
[Unreleased] - 2025-10-20
Added - Vault Client Architecture
🎯 Major Refactor: Raw API → Proper Client Class
New Files:
src/services/vaultClient.ts- Low-level, browser-compatible Vault HTTP API clientCORS_AND_CLIENT.md- Comprehensive guide explaining CORS and client architecture
Why This Change?
Your observation was correct - using raw fetch() calls is not ideal. Here's what we've improved:
✅ Before (Raw API)
// Messy, error-prone, hard to maintain
const response = await fetch(`${url}/v1/${path}`, {
method: 'GET',
mode: 'no-cors', // ❌ Breaks response reading!
headers: {
'X-Vault-Token': token,
'Access-Control-Allow-Origin': '*' // ❌ Doesn't work from client!
}
});
Problems:
- ❌
Access-Control-Allow-Originheader ignored (must be set by server) - ❌
mode: 'no-cors'prevents reading responses - ❌ No retry logic
- ❌ No timeout protection
- ❌ Poor error messages
- ❌ Manual path normalization
- ❌ Repeated code everywhere
✅ After (VaultClient)
// Clean, maintainable, production-ready
const client = new VaultClient({
server,
credentials,
timeout: 30000,
retries: 2
});
const data = await client.read('secret/data/myapp');
Benefits:
- ✅ Automatic retries with exponential backoff
- ✅ Configurable timeouts
- ✅ Detailed error messages with status codes
- ✅ Automatic path normalization
- ✅ Type-safe operations
- ✅ Built-in authentication methods
- ✅ Health check support
- ✅ Token lifecycle management
New VaultClient Features
1. Core Operations
// Read secret
const data = await client.read<MySecret>('secret/data/myapp');
// List secrets
const keys = await client.list('secret/');
// Write secret
await client.write('secret/data/myapp', { key: 'value' });
// Delete secret
await client.delete('secret/data/myapp');
2. Error Handling
import { VaultError } from './services/vaultClient';
try {
await client.read('secret/data/test');
} catch (error) {
if (error instanceof VaultError) {
console.log(error.statusCode); // 403, 404, 500, etc.
console.log(error.errors); // Detailed error messages from Vault
}
}
3. Authentication
// Username/Password
const token = await client.loginUserpass('user', 'password');
// LDAP
const token = await client.loginLdap('user', 'password');
// Token info
const info = await client.tokenLookupSelf();
// Logout
await client.tokenRevokeSelf();
4. Health Check
const health = await client.health();
console.log(health.initialized); // true/false
console.log(health.sealed); // true/false
console.log(health.version); // "1.15.0"
5. Automatic Retries
- Retries on network errors and 5xx server errors
- Does NOT retry on 4xx client errors (authentication, permission, etc.)
- Exponential backoff: 1s, 2s, 4s...
- Configurable retry count
6. Timeout Protection
const client = new VaultClient({
...options,
timeout: 5000 // 5 seconds
});
// Automatically aborted after 5 seconds
Updated Components
vaultApi.ts - High-Level Service
- Now uses
VaultClientinternally - Maintains caching layer
- Provides high-level operations
- Better error propagation
// Before: Raw fetch
const response = await fetch(url, options);
const data = await response.json();
// After: Using VaultClient
const client = this.createClient(server, credentials);
const data = await client.read(path);
Dashboard.tsx - Better Error Messages
// Now catches VaultError and shows helpful messages
if (error.statusCode === 403) {
alert('Permission denied. You may not have access to this secret.');
} else if (error.statusCode === 404) {
alert('Secret not found at this path.');
} else if (error.message.includes('CORS')) {
alert('CORS error. Configure your Vault server to allow this origin.');
}
CORS Configuration Guide
Created comprehensive CORS_AND_CLIENT.md explaining:
-
Why client-side CORS headers don't work
- CORS headers MUST be set by the server
- Browser enforces this security policy
-
Why
mode: 'no-cors'breaks everything- Prevents reading response body
- Returns opaque responses
- Can't access status codes or data
-
Proper Vault CORS configuration
listener "tcp" { cors_enabled = true cors_allowed_origins = ["http://localhost:5173"] cors_allowed_headers = ["*"] } -
How to test CORS configuration
- curl commands
- Browser console tests
- DevTools network inspection
Architecture Comparison
| Aspect | Before (Raw API) | After (VaultClient) |
|---|---|---|
| Code Quality | Scattered logic | Centralized, clean |
| Error Handling | Basic | Comprehensive with VaultError |
| Retries | None | Automatic with backoff |
| Timeouts | None | Built-in |
| Type Safety | Minimal | Full TypeScript support |
| Maintainability | Low | High |
| Testing | Difficult | Easy to mock/test |
| Production Ready | No | Yes |
Benefits Summary
For Developers
- Less Code:
await client.read(path)vs 15 lines of fetch code - Better DX: TypeScript autocomplete, type checking
- Easier Testing: Mock VaultClient instead of fetch
- Clear Errors: Know exactly what went wrong
For Users
- Better Error Messages: "Permission denied" instead of "Failed"
- More Reliable: Automatic retries on transient failures
- Faster: Timeout protection prevents hanging
- Safer: Proper CORS guidance prevents security issues
For Production
- Robust: Handles network issues gracefully
- Observable: Detailed logging and error context
- Configurable: Adjust timeouts and retries
- Scalable: Easy to add new Vault operations
Migration Guide
If you have custom code using the old API:
// Old way ❌
const response = await fetch(`${url}/v1/${path}`, {
headers: { 'X-Vault-Token': token }
});
const data = await response.json();
// New way ✅
const client = new VaultClient({ server, credentials });
const data = await client.read(path);
Breaking Changes
None! The vaultApi service maintains the same interface. The changes are internal improvements.
Files Modified
- ✅
src/services/vaultClient.ts- NEW: Core client class - ✅
src/services/vaultApi.ts- UPDATED: Now uses VaultClient - ✅
src/components/Dashboard.tsx- UPDATED: Better error handling - ✅
README.md- UPDATED: Mentions client architecture - ✅
CORS_AND_CLIENT.md- NEW: Comprehensive guide - ✅
CHANGELOG.md- NEW: This file
Testing Checklist
- No linter errors
- TypeScript compiles successfully
- All existing functionality preserved
- Better error messages for common issues
- Manual testing with real Vault server (requires CORS config)
- Test retry logic (simulate network failure)
- Test timeout (simulate slow server)
- Test all auth methods
Next Steps
- Configure CORS on your Vault server (see CORS_AND_CLIENT.md)
- Run
npm installto ensure dependencies are up to date - Test with your Vault instance
- Report any issues
Documentation
New documentation files:
CORS_AND_CLIENT.md- Why and how to use VaultClientUSAGE.md- User guide (updated)FEATURES.md- Feature list (updated)CHANGELOG.md- This file
Credits
Improvement suggested by user feedback: "You should probably use a vault-client instead of the raw api, no?"
Answer: Absolutely! And now we have one. 🎉