@sahabaplus/moyasar
Version:
A comprehensive TypeScript SDK for integrating with the Moyasar payment gateway
194 lines • 6.76 kB
JavaScript
import { z } from "zod";
import { PaymentSource, CardScheme, CardType, PaymentStatus } from "../enums";
import { amountSchema, currencySchema, paginationMetaSchema, } from "../../../shared/validation/index";
import { PaymentValidation } from "../constants";
const BasePaymentSourceSchema = z.object({
type: z.enum(PaymentSource),
company: z.enum(CardScheme).nullable(),
name: z.string().nullable(),
number: z.string(),
gateway_id: z.string(),
message: z.string().nullable(),
reference_number: z.string().nullable(),
token: z.string().nullable().optional(),
response_code: z.string().optional(),
authorization_code: z
.string()
.regex(PaymentValidation.AUTH_CODE_REGEX)
.optional(),
issuer_name: z.string().optional(),
issuer_country: z.string().optional(),
issuer_card_type: z.enum(CardType).optional(),
issuer_card_category: z.string().optional(),
});
// Zod schemas for validation and parsing
const CreditCardSourceResponseSchema = z.object({
...BasePaymentSourceSchema.shape,
type: z.literal(PaymentSource.CREDITCARD),
transaction_url: z.url().nullable(),
});
const WalletPaymentSourceResponseSchema = z.object({
...BasePaymentSourceSchema.shape,
type: z.enum([
PaymentSource.APPLEPAY,
PaymentSource.GOOGLEPAY,
PaymentSource.SAMSUNGPAY,
]),
dpan: z.string().optional(),
});
const StcPaySourceResponseSchema = z.object({
type: z.literal(PaymentSource.STCPAY),
mobile: z.string().regex(PaymentValidation.SAUDI_MOBILE_REGEX),
reference_number: z.string().optional(),
cashier_id: z.string().optional(),
branch: z.string().optional(),
transaction_url: z.url().nullable(),
message: z.string(),
});
const PaymentSourceResponseSchema = z.discriminatedUnion("type", [
CreditCardSourceResponseSchema,
WalletPaymentSourceResponseSchema,
StcPaySourceResponseSchema,
]);
// z.discriminatedUnion("type", [
// CreditCardSourceResponseSchema,
// WalletPaymentSourceResponseSchema,
// StcPaySourceResponseSchema,
// ]);
export const PaymentSchema = z.object({
id: z.string(),
status: z.enum(PaymentStatus),
amount: amountSchema,
fee: z.number().int().min(0),
currency: currencySchema,
refunded: z.number().int().min(0),
refunded_at: z.coerce.date().nullable(),
captured: z.number().int().min(0),
captured_at: z.coerce.date().nullable(),
voided_at: z.coerce.date().nullable(),
description: z.string(),
amount_format: z
.string()
.transform(val => val),
fee_format: z.string().transform(val => val),
refunded_format: z
.string()
.transform(val => val),
captured_format: z
.string()
.transform(val => val),
invoice_id: z.string().nullable(),
ip: z.ipv4().nullable(),
callback_url: z.url().nullable(),
created_at: z.coerce.date(),
updated_at: z.coerce.date(),
metadata: z.record(z.string(), z.string()).nullable(),
source: PaymentSourceResponseSchema,
});
const CreditCardSourceSchema = z.object({
type: z.literal(PaymentSource.CREDITCARD),
name: z
.string()
.min(1, "Name is required")
.max(PaymentValidation.DESCRIPTION_MAX_LENGTH)
.refine(val => val.trim().split(" ").length >= 2, {
message: "Card holder name must be at least two words",
})
.transform(val => val.trim()),
number: z.string().regex(/^\d{16,19}$/, "Card number must be 16-19 digits"),
month: z
.number()
.int("Month must be an integer")
.min(1, "Month must be between 1 and 12")
.max(12, "Month must be between 1 and 12"),
year: z
.number()
.int("Year must be an integer")
.min(new Date().getFullYear(), "Year cannot be in the past"),
cvc: z.string().regex(/^\d{3,4}$/, "CVC must be 3-4 digits"),
statement_descriptor: z
.string()
.max(PaymentValidation.STATEMENT_DESCRIPTOR_MAX_LENGTH)
.optional(),
"3ds": z.boolean().optional(),
manual: z.boolean().optional(),
save_card: z.boolean().optional(),
});
const TokenSourceSchema = z.object({
type: z.literal(PaymentSource.TOKEN),
token: z.string().regex(/^token_/, "Token must start with 'token_'"),
cvc: z
.string()
.regex(/^\d{3,4}$/, "CVC must be 3-4 digits")
.optional(),
statement_descriptor: z
.string()
.max(PaymentValidation.STATEMENT_DESCRIPTOR_MAX_LENGTH)
.optional(),
"3ds": z.boolean().optional(),
manual: z.boolean().optional(),
});
const WalletPaymentSourceSchema = z.object({
type: z.enum([
PaymentSource.GOOGLEPAY,
PaymentSource.APPLEPAY,
PaymentSource.SAMSUNGPAY,
]),
token: z.string().optional(),
manual: z.boolean().optional(),
save_card: z.boolean().optional(),
statement_descriptor: z
.string()
.max(PaymentValidation.STATEMENT_DESCRIPTOR_MAX_LENGTH)
.optional(),
});
const StcPaySourceSchema = z.object({
type: z.literal(PaymentSource.STCPAY),
mobile: z
.string()
.regex(PaymentValidation.SAUDI_MOBILE_REGEX, "Invalid Saudi mobile number format"),
cashier_id: z.string().optional(),
branch: z.string().optional(),
});
const CreatePaymentSourceSchema = z.discriminatedUnion("type", [
CreditCardSourceSchema,
TokenSourceSchema,
WalletPaymentSourceSchema,
StcPaySourceSchema,
]);
export const CreatePaymentSchema = z.object({
given_id: z.uuid("ID must be a valid UUID").optional(),
amount: amountSchema,
currency: currencySchema,
description: z
.string()
.min(1, "Description is required")
.max(PaymentValidation.DESCRIPTION_MAX_LENGTH, `Description must be less than ${PaymentValidation.DESCRIPTION_MAX_LENGTH} characters`)
.transform(val => val.trim()),
callback_url: z.url("Callback URL must be a valid URL"),
source: CreatePaymentSourceSchema,
metadata: z.record(z.string(), z.string()).optional(),
apply_coupon: z.boolean().optional(),
});
export const UpdatePaymentSchema = z.object({
description: z
.string()
.min(1, "Description is required")
.max(PaymentValidation.DESCRIPTION_MAX_LENGTH)
.transform(val => val.trim())
.optional(),
metadata: z.record(z.string(), z.string()).optional(),
});
export const RefundPaymentSchema = z.object({
amount: amountSchema.optional(),
});
export const CapturePaymentSchema = z
.object({
amount: amountSchema.optional(),
})
.optional();
export const listPaymentResponseSchema = z.object({
payments: z.array(PaymentSchema),
meta: paginationMetaSchema,
});
//# sourceMappingURL=schemas.js.map