Files
cfw-autumn/scripts/cleanup-ports.js
John Yeo 1847470403 feat: implement resource-based API versioning system with strong typing
## Summary
Implemented a comprehensive API versioning system with resource-level version changes,
strong typing using Zod schemas, and a composable getApi* pattern.

## Key Changes

### Versioning Infrastructure
- **VersionChange base class**: Now strongly typed with Zod schemas (TNewSchema, TOldSchema, TDataSchema)
- **Bidirectional transforms**: `transformRequest` (old→new) and `transformResponse` (new→old)
- **Input + Data pattern**: `input` for version-specific data, `data` for additional context
- **applyVersionChanges**: Fixed TypeScript errors and added biome-ignore comments for necessary `any` types

### Resource Organization
- **Folder structure**: Each resource gets its own `changes/` folder
  - `shared/api/customers/changes/` - Customer-level changes
  - `shared/api/customers/cusProducts/changes/` - Product-level changes
  - `shared/api/customers/cusFeatures/changes/` - Feature-level changes

### Version Changes (Strongly Typed)
- **V0_2_ProductItems**: Products gained items field (V0_2+ → V0_1)
- **V1_2_FeaturesArrayToObject**: Features object ↔ array (V1_2 → V1_1)
- **V1_1_MergedResponse**: Merged customer response ↔ split (V1_1+ → V1_0)
- **V1_1_LegacyExpandInvoices**: Side-effect only (invoices auto-expand in V1_0)

### getApi* Pattern (server/src/internal/customers/cusUtils/apiCusUtils/)
- **getApiCusProduct**: Builds product in latest format, applies V0_2_ProductItems transform
- **getApiCusFeature**: Transforms balances (used→usage), applies V1_2_FeaturesArrayToObject
- **getApiCustomer**: Orchestrates products/features, merges, applies V1_1_MergedResponse

### V2 Handler Demo
- **handleGetCustomerV2**: Demonstrates zero version branching in handler
- Calls `getApiCustomer` which handles all versioning internally
- Side effects handled explicitly (expand invoices for V1_0)

## Type Safety
- All version changes use Zod schemas for input/output types
- Runtime validation with `parse()` ensures data integrity
- Compile-time type checking catches transformation errors
- Context data support via optional `data` parameter

## Benefits
 No scattered if-else version checks
 Composable resource-based architecture
 Strong typing with Zod schemas
 Self-documenting version changes
 Easy to add new versions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 19:25:21 +01:00

53 lines
1.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
import { getProcessOnPort, killProcess } from "./detect-ports.js";
const PORTS_TO_CHECK = [3000, 3001, 8080, 8081, 8082, 8083];
async function cleanupPorts() {
console.log("🧹 Cleaning up dev server ports...\n");
let killedCount = 0;
for (const port of PORTS_TO_CHECK) {
const processInfo = await getProcessOnPort(port);
if (processInfo) {
const { pid, processName } = processInfo;
// Check if it's a dev server process
const isDevProcess =
processName.includes("bun") ||
processName.includes("node") ||
processName.includes("vite");
if (isDevProcess) {
console.log(`⚠️ Port ${port}: ${processName} (PID: ${pid})`);
const killed = await killProcess(pid);
if (killed) {
console.log(` ✅ Killed process ${pid}\n`);
killedCount++;
} else {
console.log(` ❌ Failed to kill process ${pid}\n`);
}
} else {
console.log(
` Port ${port}: ${processName} (PID: ${pid}) - skipping (not a dev server)\n`,
);
}
}
}
if (killedCount === 0) {
console.log("✨ No dev server processes found on common ports");
} else {
console.log(`✅ Cleaned up ${killedCount} process(es)`);
}
}
cleanupPorts().catch((error) => {
console.error("Error cleaning up ports:", error);
process.exit(1);
});