barsa b206de8dba refactor: enterprise-grade cleanup of BFF and domain packages
Comprehensive refactoring across 70 files (net -298 lines) improving
type safety, error handling, and code organization:

- Replace .passthrough()/.catchall(z.unknown()) with .strip() in all Zod schemas
- Tighten Record<string, unknown> to bounded union types where possible
- Replace throw new Error with domain-specific exceptions (OrderException,
  FulfillmentException, WhmcsOperationException, SalesforceOperationException, etc.)
- Split AuthTokenService (625 lines) into TokenGeneratorService and
  TokenRefreshService with thin orchestrator
- Deduplicate FreebitClientService with shared makeRequest() method
- Add typed interfaces to WHMCS facade, order service, and fulfillment mapper
- Externalize hardcoded config values to ConfigService with env fallbacks
- Consolidate duplicate billing cycle enums into shared billingCycleSchema
- Standardize logger usage (nestjs-pino @Inject(Logger) everywhere)
- Move shared WHMCS number coercion helpers to whmcs-utils/schema.ts
2026-02-24 19:05:30 +09:00

62 lines
2.3 KiB
TypeScript

/**
* Checkout Domain - Schemas
*
* Zod validation schemas for checkout flow.
* Supports authenticated checkout.
*/
import { z } from "zod";
import { CHECKOUT_ORDER_TYPE } from "./contract.js";
// ============================================================================
// Order Type Schema
// ============================================================================
const CHECKOUT_ORDER_TYPE_VALUES = Object.values(CHECKOUT_ORDER_TYPE) as [string, ...string[]];
/**
* Checkout order types - uses PascalCase to match Salesforce/BFF contracts
* @see packages/domain/orders/contract.ts ORDER_TYPE for canonical values
*/
export const checkoutOrderTypeSchema = z.enum(CHECKOUT_ORDER_TYPE_VALUES);
// ============================================================================
// Price Breakdown Schema
// ============================================================================
export const priceBreakdownItemSchema = z.object({
label: z.string(),
sku: z.string().optional(),
monthlyPrice: z.number().optional(),
oneTimePrice: z.number().optional(),
quantity: z.number().optional().default(1),
});
// ============================================================================
// Cart Item Schema
// ============================================================================
export const cartItemSchema = z.object({
orderType: checkoutOrderTypeSchema,
planSku: z.string().min(1, "Plan SKU is required"),
planName: z.string().min(1, "Plan name is required"),
addonSkus: z.array(z.string()).default([]),
// Checkout configuration values are user-supplied key-value pairs (strings, numbers, booleans)
configuration: z
.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]))
.default({}),
pricing: z.object({
monthlyTotal: z.number().nonnegative(),
oneTimeTotal: z.number().nonnegative(),
breakdown: z.array(priceBreakdownItemSchema).default([]),
}),
});
// ============================================================================
// Inferred Types
// ============================================================================
export type OrderType = z.infer<typeof checkoutOrderTypeSchema>;
export type PriceBreakdownItem = z.infer<typeof priceBreakdownItemSchema>;
export type CartItem = z.infer<typeof cartItemSchema>;