refactor: code quality improvements (P3)
## Type Safety
- Add zod runtime validation for external API responses
* Namecheap API responses (domain-register.ts)
* n8n webhook responses (n8n-service.ts)
* User request bodies (routes/api.ts)
* Replaced unsafe type assertions with safeParse()
* Proper error handling and logging
## Dead Code Removal
- Remove unused callDepositAgent function (127 lines)
* Legacy Assistants API code no longer needed
* Now using direct code execution
* File reduced from 469 → 345 lines (26.4% reduction)
## Configuration Management
- Extract hardcoded URLs to environment variables
* Added 7 new vars in wrangler.toml:
OPENAI_API_BASE, NAMECHEAP_API_URL, WHOIS_API_URL,
CONTEXT7_API_BASE, BRAVE_API_BASE, WTTR_IN_URL, HOSTING_SITE_URL
* Updated Env interface in types.ts
* All URLs have fallback to current production values
* Enables environment-specific configuration (dev/staging/prod)
## Dependencies
- Add zod 4.3.5 for runtime type validation
## Files Modified
- Configuration: wrangler.toml, types.ts, package.json
- Services: 11 TypeScript files with URL/validation updates
- Total: 15 files, +196/-189 lines
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,25 @@
|
||||
import { z } from 'zod';
|
||||
import { Env } from './types';
|
||||
import { createLogger } from './utils/logger';
|
||||
|
||||
const logger = createLogger('domain-register');
|
||||
|
||||
// Zod schemas for API response validation
|
||||
const NamecheapRegisterResponseSchema = z.object({
|
||||
registered: z.boolean().optional(),
|
||||
domain: z.string().optional(),
|
||||
error: z.string().optional(),
|
||||
detail: z.string().optional(),
|
||||
});
|
||||
|
||||
const DomainInfoResponseSchema = z.object({
|
||||
expires: z.string().optional(),
|
||||
});
|
||||
|
||||
const NameserverResponseSchema = z.object({
|
||||
nameservers: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
interface RegisterResult {
|
||||
success: boolean;
|
||||
domain?: string;
|
||||
@@ -22,7 +39,7 @@ export async function executeDomainRegister(
|
||||
price: number
|
||||
): Promise<RegisterResult> {
|
||||
const apiKey = env.NAMECHEAP_API_KEY;
|
||||
const apiUrl = 'https://namecheap-api.anvil.it.com';
|
||||
const apiUrl = env.NAMECHEAP_API_URL || 'https://namecheap-api.anvil.it.com';
|
||||
|
||||
if (!apiKey) {
|
||||
return { success: false, error: 'API 키가 설정되지 않았습니다.' };
|
||||
@@ -58,12 +75,15 @@ export async function executeDomainRegister(
|
||||
}),
|
||||
});
|
||||
|
||||
const registerResult = await registerResponse.json() as {
|
||||
registered?: boolean;
|
||||
domain?: string;
|
||||
error?: string;
|
||||
detail?: string;
|
||||
};
|
||||
const jsonData = await registerResponse.json();
|
||||
const parseResult = NamecheapRegisterResponseSchema.safeParse(jsonData);
|
||||
|
||||
if (!parseResult.success) {
|
||||
logger.error('Namecheap register response schema validation failed', parseResult.error);
|
||||
return { success: false, error: '도메인 등록 응답 형식이 올바르지 않습니다.' };
|
||||
}
|
||||
|
||||
const registerResult = parseResult.data;
|
||||
|
||||
if (!registerResponse.ok || !registerResult.registered) {
|
||||
const errorMsg = registerResult.error || registerResult.detail || '도메인 등록에 실패했습니다.';
|
||||
@@ -112,11 +132,18 @@ export async function executeDomainRegister(
|
||||
headers: { 'X-API-Key': apiKey }
|
||||
});
|
||||
if (infoResponse.ok) {
|
||||
const infoResult = await infoResponse.json() as { expires?: string };
|
||||
if (infoResult.expires) {
|
||||
// MM/DD/YYYY → YYYY-MM-DD 변환
|
||||
const [month, day, year] = infoResult.expires.split('/');
|
||||
expiresAt = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||||
const infoJsonData = await infoResponse.json();
|
||||
const infoParseResult = DomainInfoResponseSchema.safeParse(infoJsonData);
|
||||
|
||||
if (!infoParseResult.success) {
|
||||
logger.warn('Domain info response schema validation failed', { domain });
|
||||
} else {
|
||||
const infoResult = infoParseResult.data;
|
||||
if (infoResult.expires) {
|
||||
// MM/DD/YYYY → YYYY-MM-DD 변환
|
||||
const [month, day, year] = infoResult.expires.split('/');
|
||||
expiresAt = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +152,15 @@ export async function executeDomainRegister(
|
||||
headers: { 'X-API-Key': apiKey }
|
||||
});
|
||||
if (nsResponse.ok) {
|
||||
const nsResult = await nsResponse.json() as { nameservers?: string[] };
|
||||
nameservers = nsResult.nameservers || [];
|
||||
const nsJsonData = await nsResponse.json();
|
||||
const nsParseResult = NameserverResponseSchema.safeParse(nsJsonData);
|
||||
|
||||
if (!nsParseResult.success) {
|
||||
logger.warn('Nameserver response schema validation failed', { domain });
|
||||
} else {
|
||||
const nsResult = nsParseResult.data;
|
||||
nameservers = nsResult.nameservers || [];
|
||||
}
|
||||
}
|
||||
} catch (infoError) {
|
||||
console.log(`[DomainRegister] 도메인 정보 조회 실패 (무시):`, infoError);
|
||||
|
||||
Reference in New Issue
Block a user