- Updated error response structures in AuthErrorFilter, HttpExceptionFilter, and ZodValidationExceptionFilter to include detailed information such as timestamp and request path. - Replaced generic error messages with domain-specific exceptions in Freebit and WHMCS services to improve clarity and maintainability. - Improved logging and error handling in various services to provide better context for failures and enhance debugging capabilities. - Refactored JWT strategy to include explicit expiration checks for improved security and user feedback.
275 lines
11 KiB
TypeScript
275 lines
11 KiB
TypeScript
/**
|
|
* SIM Domain - Freebit Provider Request Schemas
|
|
*
|
|
* Zod schemas for all Freebit API request payloads.
|
|
*/
|
|
|
|
import { z } from "zod";
|
|
|
|
// ============================================================================
|
|
// Account Details & Traffic Info
|
|
// ============================================================================
|
|
|
|
export const freebitAccountDetailsRequestSchema = z.object({
|
|
version: z.string().optional(),
|
|
requestDatas: z
|
|
.array(
|
|
z.object({
|
|
kind: z.enum(["MASTER", "MVNO"]),
|
|
account: z.union([z.string(), z.number()]).optional(),
|
|
})
|
|
)
|
|
.min(1, "At least one request data entry is required"),
|
|
});
|
|
|
|
export const freebitTrafficInfoRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Top-Up
|
|
// ============================================================================
|
|
|
|
export const freebitTopUpOptionsSchema = z.object({
|
|
campaignCode: z.string().optional(),
|
|
expiryDate: z.string().optional(),
|
|
scheduledAt: z.string().optional(),
|
|
});
|
|
|
|
export const freebitTopUpRequestPayloadSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
quotaMb: z.number().positive("Quota must be positive"),
|
|
options: freebitTopUpOptionsSchema.optional(),
|
|
});
|
|
|
|
export const freebitTopUpApiRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
quota: z.number().positive("Quota must be positive"),
|
|
quotaCode: z.string().optional(),
|
|
expire: z.string().optional(),
|
|
runTime: z.string().optional(),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Plan Change & Cancellation
|
|
// ============================================================================
|
|
|
|
export const freebitPlanChangeRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
newPlanCode: z.string().min(1, "New plan code is required"),
|
|
assignGlobalIp: z.boolean().optional(),
|
|
scheduledAt: z.string().optional(),
|
|
});
|
|
|
|
export const freebitPlanChangeApiRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
plancode: z.string().min(1, "Plan code is required"),
|
|
globalip: z.enum(["0", "1"]).optional(),
|
|
runTime: z.string().optional(),
|
|
});
|
|
|
|
export const freebitAddSpecRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
specCode: z.string().min(1, "Spec code is required"),
|
|
enabled: z.boolean().optional(),
|
|
networkType: z.enum(["4G", "5G"]).optional(),
|
|
});
|
|
|
|
export const freebitRemoveSpecRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
specCode: z.string().min(1, "Spec code is required"),
|
|
});
|
|
|
|
export const freebitCancelPlanRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
runDate: z.string().optional(),
|
|
});
|
|
|
|
export const freebitCancelPlanApiRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
runTime: z.string().optional(),
|
|
});
|
|
|
|
export const freebitQuotaHistoryRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
fromDate: z.string().regex(/^\d{8}$/, "From date must be in YYYYMMDD format"),
|
|
toDate: z.string().regex(/^\d{8}$/, "To date must be in YYYYMMDD format"),
|
|
});
|
|
|
|
export const freebitQuotaHistoryResponseSchema = z.object({
|
|
resultCode: z.string(),
|
|
status: z
|
|
.object({
|
|
message: z.string(),
|
|
statusCode: z.union([z.string(), z.number()]),
|
|
})
|
|
.optional(),
|
|
total: z.union([z.string(), z.number()]),
|
|
count: z.union([z.string(), z.number()]),
|
|
quotaHistory: z.array(
|
|
z.object({
|
|
addQuotaKb: z.union([z.string(), z.number()]),
|
|
addDate: z.string(),
|
|
expireDate: z.string(),
|
|
campaignCode: z.string().optional(),
|
|
})
|
|
),
|
|
});
|
|
|
|
export const freebitEsimMnpSchema = z.object({
|
|
reserveNumber: z.string().min(1, "Reserve number is required"),
|
|
reserveExpireDate: z.string().regex(/^\d{8}$/, "Reserve expire date must be in YYYYMMDD format"),
|
|
});
|
|
|
|
export const freebitEsimReissueRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
newEid: z.string().min(1, "New EID is required"),
|
|
oldEid: z.string().optional(),
|
|
planCode: z.string().optional(),
|
|
oldProductNumber: z.string().optional(),
|
|
});
|
|
|
|
export const freebitEsimAddAccountRequestSchema = z.object({
|
|
authKey: z.string().min(1).optional(),
|
|
aladinOperated: z.enum(["10", "20"]).default("10"),
|
|
account: z.string().min(1, "Account is required"),
|
|
eid: z.string().min(1, "EID is required"),
|
|
addKind: z.enum(["N", "R"]).default("N"),
|
|
shipDate: z.string().regex(/^\d{8}$/, "Ship date must be in YYYYMMDD format").optional(),
|
|
planCode: z.string().optional(),
|
|
contractLine: z.enum(["4G", "5G"]).optional(),
|
|
mnp: freebitEsimMnpSchema.optional(),
|
|
});
|
|
|
|
// =========================================================================
|
|
// SIM Features
|
|
// =========================================================================
|
|
|
|
export const freebitSimFeaturesRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
voiceMailEnabled: z.boolean().optional(),
|
|
callWaitingEnabled: z.boolean().optional(),
|
|
callForwardingEnabled: z.boolean().optional(),
|
|
callerIdEnabled: z.boolean().optional(),
|
|
});
|
|
|
|
export const freebitGlobalIpRequestSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
assign: z.boolean(), // true to assign, false to remove
|
|
});
|
|
|
|
// =========================================================================
|
|
// eSIM Activation
|
|
// =========================================================================
|
|
|
|
export const freebitAuthRequestSchema = z.object({
|
|
oemId: z.string().min(1),
|
|
oemKey: z.string().min(1),
|
|
});
|
|
|
|
export const freebitCancelAccountRequestSchema = z.object({
|
|
account: z.string().min(1),
|
|
runDate: z.string().optional(),
|
|
});
|
|
|
|
export const freebitEsimIdentitySchema = z.object({
|
|
firstnameKanji: z.string().optional(),
|
|
lastnameKanji: z.string().optional(),
|
|
firstnameZenKana: z.string().optional(),
|
|
lastnameZenKana: z.string().optional(),
|
|
gender: z.enum(["M", "F"]).optional(),
|
|
birthday: z.string().regex(/^\d{8}$/, "Birthday must be in YYYYMMDD format").optional(),
|
|
});
|
|
|
|
/**
|
|
* Freebit eSIM Account Activation Request Schema
|
|
* PA05-41 (addAcct) API endpoint
|
|
*/
|
|
export const freebitEsimActivationRequestSchema = z.object({
|
|
authKey: z.string().min(1, "Auth key is required"),
|
|
aladinOperated: z.enum(["10", "20"]).default("10"), // 10: issue profile, 20: no-issue
|
|
createType: z.enum(["new", "reissue", "exchange"]).default("new"),
|
|
account: z.string().min(1, "Account (MSISDN) is required"),
|
|
eid: z.string().min(1, "EID is required for eSIM"),
|
|
simkind: z.enum(["esim", "psim"]).default("esim"),
|
|
planCode: z.string().optional(),
|
|
contractLine: z.enum(["4G", "5G"]).optional(),
|
|
shipDate: z.string().regex(/^\d{8}$/, "Ship date must be in YYYYMMDD format").optional(),
|
|
mnp: freebitEsimMnpSchema.optional(),
|
|
// Identity fields (flattened for API)
|
|
firstnameKanji: z.string().optional(),
|
|
lastnameKanji: z.string().optional(),
|
|
firstnameZenKana: z.string().optional(),
|
|
lastnameZenKana: z.string().optional(),
|
|
gender: z.enum(["M", "F"]).optional(),
|
|
birthday: z.string().regex(/^\d{8}$/, "Birthday must be in YYYYMMDD format").optional(),
|
|
// Additional fields for reissue/exchange
|
|
masterAccount: z.string().optional(),
|
|
masterPassword: z.string().optional(),
|
|
repAccount: z.string().optional(),
|
|
size: z.string().optional(),
|
|
addKind: z.string().optional(), // 'R' for reissue
|
|
oldEid: z.string().optional(),
|
|
oldProductNumber: z.string().optional(),
|
|
deliveryCode: z.string().optional(),
|
|
globalIp: z.enum(["10", "20"]).optional(), // 10: none, 20: with global IP
|
|
});
|
|
|
|
/**
|
|
* Freebit eSIM Activation Response Schema
|
|
* Note: The 'data' field type varies by API version and is not used in production.
|
|
* Using z.unknown() for type safety while allowing any shape if present.
|
|
*/
|
|
export const freebitEsimActivationResponseSchema = z.object({
|
|
resultCode: z.string(),
|
|
resultMessage: z.string().optional(),
|
|
data: z.unknown().optional(),
|
|
status: z.object({
|
|
statusCode: z.union([z.string(), z.number()]),
|
|
message: z.string(),
|
|
}).optional(),
|
|
message: z.string().optional(),
|
|
});
|
|
|
|
/**
|
|
* Higher-level eSIM activation parameters schema
|
|
* Used for business logic layer before mapping to API request
|
|
*/
|
|
export const freebitEsimActivationParamsSchema = z.object({
|
|
account: z.string().min(1, "Account is required"),
|
|
eid: z.string().min(1, "EID is required"),
|
|
planCode: z.string().optional(),
|
|
contractLine: z.enum(["4G", "5G"]).optional(),
|
|
aladinOperated: z.enum(["10", "20"]).default("10"),
|
|
shipDate: z.string().regex(/^\d{8}$/, "Ship date must be in YYYYMMDD format").optional(),
|
|
mnp: freebitEsimMnpSchema.optional(),
|
|
identity: freebitEsimIdentitySchema.optional(),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Type Exports
|
|
// ============================================================================
|
|
|
|
export type FreebitAccountDetailsRequest = z.infer<typeof freebitAccountDetailsRequestSchema>;
|
|
export type FreebitTrafficInfoRequest = z.infer<typeof freebitTrafficInfoRequestSchema>;
|
|
export type FreebitTopUpRequest = z.infer<typeof freebitTopUpRequestPayloadSchema>;
|
|
export type FreebitTopUpApiRequest = z.infer<typeof freebitTopUpApiRequestSchema>;
|
|
export type FreebitPlanChangeRequest = z.infer<typeof freebitPlanChangeRequestSchema>;
|
|
export type FreebitPlanChangeApiRequest = z.infer<typeof freebitPlanChangeApiRequestSchema>;
|
|
export type FreebitAddSpecRequest = z.infer<typeof freebitAddSpecRequestSchema>;
|
|
export type FreebitRemoveSpecRequest = z.infer<typeof freebitRemoveSpecRequestSchema>;
|
|
export type FreebitCancelPlanRequest = z.infer<typeof freebitCancelPlanRequestSchema>;
|
|
export type FreebitCancelPlanApiRequest = z.infer<typeof freebitCancelPlanApiRequestSchema>;
|
|
export type FreebitSimFeaturesRequest = z.infer<typeof freebitSimFeaturesRequestSchema>;
|
|
export type FreebitGlobalIpRequest = z.infer<typeof freebitGlobalIpRequestSchema>;
|
|
export type FreebitEsimActivationRequest = z.infer<typeof freebitEsimActivationRequestSchema>;
|
|
export type FreebitEsimActivationResponse = z.infer<typeof freebitEsimActivationResponseSchema>;
|
|
export type FreebitEsimActivationParams = z.infer<typeof freebitEsimActivationParamsSchema>;
|
|
export type FreebitEsimReissueRequest = z.infer<typeof freebitEsimReissueRequestSchema>;
|
|
export type FreebitQuotaHistoryRequest = z.infer<typeof freebitQuotaHistoryRequestSchema>;
|
|
export type FreebitQuotaHistoryResponse = z.infer<typeof freebitQuotaHistoryResponseSchema>;
|
|
export type FreebitEsimAddAccountRequest = z.infer<typeof freebitEsimAddAccountRequestSchema>;
|
|
export type FreebitAuthRequest = z.infer<typeof freebitAuthRequestSchema>;
|
|
export type FreebitCancelAccountRequest = z.infer<typeof freebitCancelAccountRequestSchema>;
|
|
|